aboutsummaryrefslogtreecommitdiffstats
path: root/Lessons
diff options
context:
space:
mode:
Diffstat (limited to 'Lessons')
-rw-r--r--Lessons/Lesson_00/README.md98
-rw-r--r--Lessons/Lesson_01/README.md138
-rw-r--r--Lessons/Lesson_01/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_01/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_02/README.md154
-rw-r--r--Lessons/Lesson_02/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_02/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_02/UefiLessonsPkg/UefiLessonsPkg.dsc23
-rw-r--r--Lessons/Lesson_03/README.md229
-rw-r--r--Lessons/Lesson_03/UefiLessonsPkg/HelloWorld/HelloWorld.c10
-rw-r--r--Lessons/Lesson_03/UefiLessonsPkg/HelloWorld/HelloWorld.inf17
-rw-r--r--Lessons/Lesson_03/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_03/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_03/UefiLessonsPkg/UefiLessonsPkg.dsc26
-rw-r--r--Lessons/Lesson_04/README.md229
-rw-r--r--Lessons/Lesson_04/UefiLessonsPkg/HelloWorld/HelloWorld.c15
-rw-r--r--Lessons/Lesson_04/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_04/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_04/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_04/UefiLessonsPkg/UefiLessonsPkg.dsc30
-rw-r--r--Lessons/Lesson_05/Conf/target.txt7
-rw-r--r--Lessons/Lesson_05/README.md53
-rw-r--r--Lessons/Lesson_05/UefiLessonsPkg/HelloWorld/HelloWorld.c15
-rw-r--r--Lessons/Lesson_05/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_05/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_05/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_05/UefiLessonsPkg/UefiLessonsPkg.dsc30
-rw-r--r--Lessons/Lesson_06/Conf/target.txt7
-rw-r--r--Lessons/Lesson_06/Handle_Protocol_databases_scheme.jpgbin0 -> 59389 bytes
-rw-r--r--Lessons/Lesson_06/README.md243
-rw-r--r--Lessons/Lesson_06/UefiLessonsPkg/HelloWorld/HelloWorld.c15
-rw-r--r--Lessons/Lesson_06/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_06/UefiLessonsPkg/ImageHandle/ImageHandle.c30
-rw-r--r--Lessons/Lesson_06/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_06/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_06/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_06/UefiLessonsPkg/UefiLessonsPkg.dsc31
-rw-r--r--Lessons/Lesson_07/Conf/target.txt7
-rw-r--r--Lessons/Lesson_07/README.md229
-rw-r--r--Lessons/Lesson_07/UefiLessonsPkg/HelloWorld/HelloWorld.c15
-rw-r--r--Lessons/Lesson_07/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_07/UefiLessonsPkg/ImageHandle/ImageHandle.c88
-rw-r--r--Lessons/Lesson_07/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_07/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_07/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_07/UefiLessonsPkg/UefiLessonsPkg.dsc31
-rw-r--r--Lessons/Lesson_08/DevicePath.pngbin0 -> 68176 bytes
-rw-r--r--Lessons/Lesson_08/README.md269
-rw-r--r--Lessons/Lesson_08/UefiLessonsPkg/HelloWorld/HelloWorld.c15
-rw-r--r--Lessons/Lesson_08/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_08/UefiLessonsPkg/ImageHandle/ImageHandle.c88
-rw-r--r--Lessons/Lesson_08/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_08/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lessons/Lesson_08/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lessons/Lesson_08/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_08/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_08/UefiLessonsPkg/UefiLessonsPkg.dsc32
-rw-r--r--Lessons/Lesson_09/Conf/target.txt7
-rw-r--r--Lessons/Lesson_09/README.md148
-rw-r--r--Lessons/Lesson_09/UefiLessonsPkg/HelloWorld/HelloWorld.c15
-rw-r--r--Lessons/Lesson_09/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_09/UefiLessonsPkg/ImageHandle/ImageHandle.c102
-rw-r--r--Lessons/Lesson_09/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_09/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lessons/Lesson_09/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lessons/Lesson_09/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_09/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_09/UefiLessonsPkg/UefiLessonsPkg.dsc32
-rw-r--r--Lessons/Lesson_10/Conf/target.txt7
-rw-r--r--Lessons/Lesson_10/README.md156
-rw-r--r--Lessons/Lesson_10/UefiLessonsPkg/HelloWorld/HelloWorld.c15
-rw-r--r--Lessons/Lesson_10/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_10/UefiLessonsPkg/ImageHandle/ImageHandle.c105
-rw-r--r--Lessons/Lesson_10/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_10/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lessons/Lesson_10/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lessons/Lesson_10/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_10/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_10/UefiLessonsPkg/UefiLessonsPkg.dsc32
-rw-r--r--Lessons/Lesson_11/README.md678
-rw-r--r--Lessons/Lesson_11/UefiLessonsPkg/HelloWorld/HelloWorld.c15
-rw-r--r--Lessons/Lesson_11/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_11/UefiLessonsPkg/ImageHandle/ImageHandle.c105
-rw-r--r--Lessons/Lesson_11/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_11/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lessons/Lesson_11/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lessons/Lesson_11/UefiLessonsPkg/MemoryInfo/MemoryInfo.c134
-rw-r--r--Lessons/Lesson_11/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf18
-rw-r--r--Lessons/Lesson_11/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_11/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_11/UefiLessonsPkg/UefiLessonsPkg.dsc33
-rw-r--r--Lessons/Lesson_12/Conf/target.txt7
-rw-r--r--Lessons/Lesson_12/README.md247
-rw-r--r--Lessons/Lesson_12/UefiLessonsPkg/HelloWorld/HelloWorld.c15
-rw-r--r--Lessons/Lesson_12/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_12/UefiLessonsPkg/ImageHandle/ImageHandle.c105
-rw-r--r--Lessons/Lesson_12/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_12/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lessons/Lesson_12/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lessons/Lesson_12/UefiLessonsPkg/MemoryInfo/MemoryInfo.c215
-rw-r--r--Lessons/Lesson_12/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf21
-rw-r--r--Lessons/Lesson_12/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_12/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_12/UefiLessonsPkg/UefiLessonsPkg.dsc33
-rw-r--r--Lessons/Lesson_12/bzImagebin0 -> 5038592 bytes
-rw-r--r--Lessons/Lesson_13/README.md137
-rw-r--r--Lessons/Lesson_13/UefiLessonsPkg/HelloWorld/HelloWorld.c15
-rw-r--r--Lessons/Lesson_13/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_13/UefiLessonsPkg/ImageHandle/ImageHandle.c105
-rw-r--r--Lessons/Lesson_13/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_13/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lessons/Lesson_13/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lessons/Lesson_13/UefiLessonsPkg/MemoryInfo/MemoryInfo.c215
-rw-r--r--Lessons/Lesson_13/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf21
-rw-r--r--Lessons/Lesson_13/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c14
-rw-r--r--Lessons/Lesson_13/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf19
-rw-r--r--Lessons/Lesson_13/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_13/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_13/UefiLessonsPkg/UefiLessonsPkg.dsc35
-rw-r--r--Lessons/Lesson_14/Conf/target.txt7
-rw-r--r--Lessons/Lesson_14/README.md427
-rw-r--r--Lessons/Lesson_14/UefiLessonsPkg/HelloWorld/HelloWorld.c15
-rw-r--r--Lessons/Lesson_14/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_14/UefiLessonsPkg/ImageHandle/ImageHandle.c105
-rw-r--r--Lessons/Lesson_14/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_14/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lessons/Lesson_14/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lessons/Lesson_14/UefiLessonsPkg/ListVariables/ListVariables.c46
-rw-r--r--Lessons/Lesson_14/UefiLessonsPkg/ListVariables/ListVariables.inf19
-rw-r--r--Lessons/Lesson_14/UefiLessonsPkg/MemoryInfo/MemoryInfo.c215
-rw-r--r--Lessons/Lesson_14/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf21
-rw-r--r--Lessons/Lesson_14/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c14
-rw-r--r--Lessons/Lesson_14/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf19
-rw-r--r--Lessons/Lesson_14/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_14/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_14/UefiLessonsPkg/UefiLessonsPkg.dsc35
-rw-r--r--Lessons/Lesson_15/Conf/target.txt7
-rw-r--r--Lessons/Lesson_15/README.md359
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/HelloWorld/HelloWorld.c15
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/ImageHandle/ImageHandle.c105
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/ListVariables/ListVariables.c46
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/ListVariables/ListVariables.inf19
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/MemoryInfo/MemoryInfo.c215
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf21
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c93
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf19
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c14
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf19
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_15/UefiLessonsPkg/UefiLessonsPkg.dsc36
-rw-r--r--Lessons/Lesson_16/Conf/target.txt7
-rw-r--r--Lessons/Lesson_16/Ovmf.diff59
-rw-r--r--Lessons/Lesson_16/README.md286
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/HelloWorld/HelloWorld.c15
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/ImageHandle/ImageHandle.c105
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/ListVariables/ListVariables.c46
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/ListVariables/ListVariables.inf19
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/MemoryInfo/MemoryInfo.c215
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf21
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c93
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf19
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c14
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf19
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/UefiLessonsPkg.dec22
-rw-r--r--Lessons/Lesson_16/UefiLessonsPkg/UefiLessonsPkg.dsc36
-rw-r--r--Lessons/Lesson_17/BootManager.pngbin0 -> 9561 bytes
-rw-r--r--Lessons/Lesson_17/Conf/target.txt7
-rw-r--r--Lessons/Lesson_17/README.md91
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/HelloWorld/HelloWorld.c19
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/ImageHandle/ImageHandle.c105
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/ListVariables/ListVariables.c46
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/ListVariables/ListVariables.inf19
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/MemoryInfo/MemoryInfo.c215
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf21
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c93
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf19
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c14
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf19
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/UefiLessonsPkg.dec22
-rw-r--r--Lessons/Lesson_17/UefiLessonsPkg/UefiLessonsPkg.dsc36
-rw-r--r--Lessons/Lesson_18/Conf/target.txt7
-rw-r--r--Lessons/Lesson_18/README.md116
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/GOPInfo/GOPInfo.c14
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/GOPInfo/GOPInfo.inf19
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/HelloWorld/HelloWorld.c19
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/ImageHandle/ImageHandle.c105
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/InteractiveApp/InteractiveApp.c34
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf18
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/ListVariables/ListVariables.c46
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/ListVariables/ListVariables.inf19
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/MemoryInfo/MemoryInfo.c215
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf21
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c93
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf19
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c14
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf19
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/UefiLessonsPkg.dec22
-rw-r--r--Lessons/Lesson_18/UefiLessonsPkg/UefiLessonsPkg.dsc37
-rw-r--r--Lessons/Lesson_19/BootManager.pngbin0 -> 8811 bytes
-rw-r--r--Lessons/Lesson_19/Conf/target.txt7
-rw-r--r--Lessons/Lesson_19/README.md186
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/GOPInfo/GOPInfo.c14
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/GOPInfo/GOPInfo.inf19
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/HelloWorld/HelloWorld.c19
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/ImageHandle/ImageHandle.c105
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/InteractiveApp/InteractiveApp.c34
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf18
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/ListVariables/ListVariables.c46
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/ListVariables/ListVariables.inf19
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/MemoryInfo/MemoryInfo.c215
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf21
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c93
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf19
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c14
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf19
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/UefiLessonsPkg.dec22
-rw-r--r--Lessons/Lesson_19/UefiLessonsPkg/UefiLessonsPkg.dsc37
-rw-r--r--Lessons/Lesson_20/Conf/target.txt7
-rw-r--r--Lessons/Lesson_20/README.md108
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/HelloWorld/HelloWorld.c19
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/ImageHandle/ImageHandle.c105
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/InteractiveApp/InteractiveApp.c34
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf18
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/ListVariables/ListVariables.c46
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/ListVariables/ListVariables.inf19
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/MemoryInfo/MemoryInfo.c215
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf21
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.c15
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.inf22
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c93
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf19
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c14
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf19
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/UefiLessonsPkg.dec20
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/UefiLessonsPkg.dsc39
-rw-r--r--Lessons/Lesson_21/Conf/target.txt7
-rw-r--r--Lessons/Lesson_21/README.md71
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/HelloWorld/HelloWorld.c19
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/ImageHandle/ImageHandle.c105
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/InteractiveApp/InteractiveApp.c34
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf18
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/ListVariables/ListVariables.c46
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/ListVariables/ListVariables.inf19
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/MemoryInfo/MemoryInfo.c215
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf21
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/PCDLesson/PCDLesson.c17
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/PCDLesson/PCDLesson.inf24
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c93
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf19
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c14
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf19
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/UefiLessonsPkg.dec22
-rw-r--r--Lessons/Lesson_21/UefiLessonsPkg/UefiLessonsPkg.dsc41
-rw-r--r--Lessons/Lesson_22/README.md117
-rw-r--r--Lessons/Lesson_23/README.md225
-rw-r--r--Lessons/Lesson_25/README.md13
-rw-r--r--Lessons/Lesson_26/README.md194
-rw-r--r--Lessons/Lesson_27/BIOS_menu.pngbin0 -> 7868 bytes
-rw-r--r--Lessons/Lesson_27/README.md696
-rw-r--r--Lessons/Lesson_27/SMBIOS_entry_structure.pngbin0 -> 90357 bytes
-rw-r--r--Lessons/Lesson_27/SMBIOS_entry_structure_dump.pngbin0 -> 9665 bytes
-rw-r--r--Lessons/Lesson_27/UefiLessonsPkg/SmbiosInfo/SmbiosInfo.c88
-rw-r--r--Lessons/Lesson_27/UefiLessonsPkg/SmbiosInfo/SmbiosInfo.inf24
-rw-r--r--Lessons/Lesson_28/README.md551
-rw-r--r--Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.c106
-rw-r--r--Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.inf24
-rw-r--r--Lessons/Lesson_29/Conf/target.txt7
-rw-r--r--Lessons/Lesson_29/README.md427
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/AcpiInfo/AcpiInfo.c106
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/AcpiInfo/AcpiInfo.inf24
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/HelloWorld/HelloWorld.c19
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/ImageHandle/ImageHandle.c105
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/InteractiveApp/InteractiveApp.c34
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf18
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/ListVariables/ListVariables.c46
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/ListVariables/ListVariables.inf19
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/MemoryInfo/MemoryInfo.c215
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf21
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/PCDLesson/PCDLesson.c43
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/PCDLesson/PCDLesson.inf39
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/SaveBGRT/SaveBGRT.c104
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/SaveBGRT/SaveBGRT.inf23
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c93
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf19
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/ShowTables/ShowTables.c16
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/ShowTables/ShowTables.inf18
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c14
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf19
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/UefiLessonsPkg.dec35
-rw-r--r--Lessons/Lesson_29/UefiLessonsPkg/UefiLessonsPkg.dsc50
-rw-r--r--Lessons/Lesson_30/PCI_Configuration_Address.pngbin0 -> 79884 bytes
-rw-r--r--Lessons/Lesson_30/README.md458
-rw-r--r--Lessons/Lesson_30/UefiLessonsPkg/ListPCI/ListPCI.c116
-rw-r--r--Lessons/Lesson_30/UefiLessonsPkg/ListPCI/ListPCI.inf20
-rw-r--r--Lessons/Lesson_31/README.md507
-rw-r--r--Lessons/Lesson_31/UefiLessonsPkg/ListPCI/ListPCI.c268
-rw-r--r--Lessons/Lesson_31/UefiLessonsPkg/ListPCI/ListPCI.inf22
-rw-r--r--Lessons/Lesson_32/README.md545
-rw-r--r--Lessons/Lesson_32/UefiLessonsPkg/PCIRomInfo/PCIRomInfo.c380
-rw-r--r--Lessons/Lesson_32/UefiLessonsPkg/PCIRomInfo/PCIRomInfo.inf22
-rw-r--r--Lessons/Lesson_33/README.md335
-rw-r--r--Lessons/Lesson_34/README.md352
-rw-r--r--Lessons/Lesson_34/UefiLessonsPkg/SimpleDriver/SimpleDriver.c26
-rw-r--r--Lessons/Lesson_34/UefiLessonsPkg/SimpleDriver/SimpleDriver.inf19
-rw-r--r--Lessons/Lesson_35/README.md383
352 files changed, 21169 insertions, 0 deletions
diff --git a/Lessons/Lesson_00/README.md b/Lessons/Lesson_00/README.md
new file mode 100644
index 0000000..a45b5ae
--- /dev/null
+++ b/Lessons/Lesson_00/README.md
@@ -0,0 +1,98 @@
+First install necessary packages to your distro.
+For the TianoCore compilation you'll need:
+- nasm - The Netwide Assembler (NASM) is an assembler and disassembler for the Intel x86 architecture. It can be used to write 16-bit, 32-bit (IA-32) and 64-bit (x86-64) programs. NASM is considered to be one of the most popular assemblers for Linux,
+- iasl - Intel ACPI compiler/decompiler. Advanced Configuration and Power Interface (ACPI) provides an open standard that operating systems can use to discover and configure computer hardware components, to perform power management and to perform status monitoring. UEFI firmware provides ACPI configuration tables to OS. ACPI specification can be found at https://uefi.org/specifications,
+- uuid-dev - Universally Unique ID library. A universally unique identifier (UUID) is a 128-bit label used for identification of various components in UEFI. The term globally unique identifier (GUID) is also used,
+- python3 - Python 3 interpreter is needed as build infrastructure includes python scripts.
+
+This is how you install these packages in Ubuntu:
+```
+$ sudo apt-get install -y nasm iasl uuid-dev python3
+```
+
+Then it is necessary to clone edk2 repo and update all its submodules:
+```
+$ git clone https://github.com/tianocore/edk2
+$ cd edk2
+$ git submodule update --init
+```
+
+Just in case the size of the edk2 folder after that would be ~867M (as for 12-06-2021).
+
+Next we need to compile EDK2 build tools:
+```
+make -C BaseTools
+```
+
+To initiate a build we need to source `edksetup.sh` script to get necessary variables into our environment:
+```
+$ . edksetup.sh
+Loading previous configuration from /<...>/edk2/Conf/BuildEnv.sh
+Using EDK2 in-source Basetools
+WORKSPACE: /<...>/edk2
+EDK_TOOLS_PATH: /<...>/edk2/BaseTools
+CONF_PATH: /<...>/edk2/Conf
+```
+
+After that we could use `build` command to build EDK2 packages.
+Try to execute help command to see all available options:
+```
+build --help
+```
+
+Next we want to build the Open Virtual Machine Firmware (OVMF). OVMF is a port of tianocore firmware to the qemu virtual machine. This allows easy debugging and experimentation with UEFI firmware; either for testing OS booting or using the (included) EFI shell. We would be writing various EFI programs, and OVMF is an easy way to test them. We could install it with the package manager with something like `sudo apt-get install ovmf`, but it is not fun.
+
+To build OVMF execute:
+```
+build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5
+```
+
+If build is successful, result would be in the folder `Build/{Platform Name}/{TARGET}_{TOOL_CHAIN_TAG}/FV`. So in our case it would be:
+```
+$ ls -lh Build/OvmfX64/RELEASE_GCC5/FV/OVMF*
+-rw-r--r-- 1 kostr kostr 4.0M Jun 12 21:03 Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd
+-rw-r--r-- 1 kostr kostr 3.5M Jun 12 21:03 Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd
+-rw-r--r-- 1 kostr kostr 528K Jun 12 21:03 Build/OvmfX64/RELEASE_GCC5/FV/OVMF_VARS.fd
+```
+
+The OVMF firmware (a UEFI implementation for QEMU) is split into two files:
+- OVMF_CODE.fd contains the actual UEFI firmware,
+- OVMF_VARS.fd is a "template" used to emulate persistent NVRAM storage.
+
+All VM instances can share the same system-wide, read-only OVMF_CODE.fd file from the ovmf package, but each instance needs a private, writable copy of OVMF_VARS.fd.
+
+Let's install QEMU to test our build artifacts:
+```
+sudo apt-get install qemu-system-x86_64
+```
+
+Lets execute QEMU to run our binaries:
+```
+$ qemu-system-x86_64 -drive if=pflash,format=raw,readonly,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd \
+ -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF_VARS.fd \
+ -nographic \
+ -net none
+```
+
+Hopefully you'll see UEFI Interactive Shell:
+```
+ïI Interactive Shell v2.2
+EDK II
+UEFI v2.70 (EDK II, 0x00010000)
+Mapping table
+ BLK0: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+Press ESC in 1 seconds to skip startup.nsh or any other key to continue.
+Shell>
+```
+
+To exit QEMU run `CTRL+A - X`
+
+The QEMU run script can be simplified to:
+```
+$ qemu-system-x86_64 -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
+ -nographic \
+ -net none
+```
+
+More info about OVMF can be found at https://github.com/tianocore/edk2/blob/master/OvmfPkg/README
diff --git a/Lessons/Lesson_01/README.md b/Lessons/Lesson_01/README.md
new file mode 100644
index 0000000..2f7d3ce
--- /dev/null
+++ b/Lessons/Lesson_01/README.md
@@ -0,0 +1,138 @@
+In last lesson we've built an app that was already included in the TianoCore sources.
+
+Let's work our way through to our own app.
+We will be working on UEFI app that can be run in UEFI shell.
+
+Create directory for our app:
+```
+mkdir SimplestApp
+```
+
+Then create *.c source file for our app with the folowing content:
+```
+$ cat SimplestApp/SimplestApp.c
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EFI_SUCCESS;
+}
+```
+
+Then we need to create edk2 app configuration file. This configuration in edk2 is represented in the *.inf format.
+INF file can have several sections:
+- Defines
+- Sources
+- Packages
+- LibraryClasses
+- Guids
+- Ppis
+- Protocols
+- FeaturePcd
+- Pcd
+- ...
+
+But right now for our minimal example we're interested in the 3 of those:
+- Defines - this section contatins some basic module description. In this section:
+
+BASE_NAME - our app name
+
+FILE_GUID - as was said earlier UEFI uses GUID numbers for identification of the components. You could use free online GUID generator to get random GUID https://www.guidgenerator.com/ or simply use `uuidgen` command line utility:
+```
+$ uuidgen
+e7218aab-998e-4d88-af9b-9573a5bf90ea
+```
+MODULE_TYPE - we want to build an application that can be run from the UEFI shell, so we use `UEFI_APPLICATION` here. UEFI application is like a simple program that you can run from shell. It is getting loaded to some memory address, executes and returns something, after that app memory would be freed again. For example other possible value here is UEFI_DRIVER - the difference is when you load a driver it keeps staying in memory even after its execution.
+Other values are listed here: https://edk2-docs.gitbook.io/edk-ii-inf-specification/appendix_f_module_types
+
+ENTRY_POINT - name of the main function in our *.c source file. As it was `UefiMain` this is the value that we write here.
+
+- Sources - source files for our edk2 module
+- LibraryClasses - we need to include `UefiApplicationEntryPoint` library class for our minimal example
+- Packages - `MdePkg/MdePkg.dec` is edk2 package with basic UEFI services. It includes `UefiApplicationEntryPoint` that we need to compile our package.
+
+vi SimplestApp/SimplestApp.inf
+```
+[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
+```
+Full specification for the "Module Information (INF) File" can be found under https://edk2-docs.gitbook.io/edk-ii-inf-specification/
+
+After the creation of the INF file we need to include our app to some package so we could build it.
+
+We don't have our own package, so let's include it to `OvmfPkg/OvmfPkgX64.dsc` that we've compiled earlier.
+Add a path to our app *.inf file in the components section.
+```
+ ################################################################################
+ [Components]
++ SimplestApp/SimplestApp.inf
+ OvmfPkg/ResetVector/ResetVector.inf
+
+```
+
+Then build OVMF:
+```
+build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5
+```
+
+Our compiled app would be in a directory `Build/OvmfX64/RELEASE_GCC5/X64`:
+```
+$ ls -lh Build/OvmfX64/RELEASE_GCC5/X64/SimplestApp.efi
+-rw-r--r-- 1 kostr kostr 832 Jun 13 10:14 Build/OvmfX64/RELEASE_GCC5/X64/SimplestApp.efi
+```
+
+Create a folder that we would populate to UEFI shell and copy our app into it:
+```
+mkdir ~/UEFI_disk
+cp Build/OvmfX64/RELEASE_GCC5/X64/SimplestApp.efi ~/UEFI_disk
+```
+
+Now lets run OVMF with this folder included:
+```
+$ qemu-system-x86_64 -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
+ -drive format=raw,file=fat:rw:~/UEFI_disk \
+ -nographic \
+ -net none
+```
+
+Hopefully you'll see something like this:
+```
+UEFI Interactive Shell v2.2
+EDK II
+UEFI v2.70 (EDK II, 0x00010000)
+Mapping table
+ FS0: Alias(s):HD0a1:;BLK1:
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
+ BLK0: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ BLK2: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+Press ESC in 3 seconds to skip startup.nsh or any other key to continue.
+```
+
+As you can see we have new rows in our mapping table. Our app would be under `FS0`. Lets `mount` this filesystem and execute our app.
+```
+Shell> fs0:
+FS0:\> SimplestApp.efi
+FS0:\>
+```
+
+
diff --git a/Lessons/Lesson_01/SimplestApp/SimplestApp.c b/Lessons/Lesson_01/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_01/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/Lessons/Lesson_01/SimplestApp/SimplestApp.inf b/Lessons/Lesson_01/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_01/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/Lessons/Lesson_02/README.md b/Lessons/Lesson_02/README.md
new file mode 100644
index 0000000..c91e47e
--- /dev/null
+++ b/Lessons/Lesson_02/README.md
@@ -0,0 +1,154 @@
+In the last lesson to build our app we've included its *.inf file as a component to the other package and have built this package. It is clearly not a good solution and in this lesson we will create our own package.
+
+First lets remove our app from the `OvmfPkg/OvmfPkgX64.dsc` file:
+```
+ ################################################################################
+ [Components]
+- SimplestApp/SimplestApp.inf
+ OvmfPkg/ResetVector/ResetVector.inf
+
+```
+
+Then create `UefiLessonsPkg` folder in the edk2 directory and move our app into this folder:
+```
+mkdir UefiLessonsPkg
+mv SimplestApp UefiLessonsPkg/SimplestApp
+```
+
+Then we need to create platform description file (DSC) for our newly created package:
+```
+$ vi UefiLessonsPkg/UefiLessonsPkg.dsc
+[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
+
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
+```
+All the fileds under `Defines` section are mondatory.
+Full specification for the Platform Description (DSC) File can be found under https://edk2-docs.gitbook.io/edk-ii-dsc-specification/
+
+Let's try to build our SimplestApp module that is now in our own package:
+```
+$ . edksetup.sh
+$ build --platform=UefiLessonsPkg/UefiLessonsPkg.dsc \
+ --module=UefiLessonsPkg/SimplestApp/SimplestApp.inf \
+ --arch=X64 \
+ --buildtarget=RELEASE \
+ --tagname=GCC5
+```
+
+Unfortunately the build would fail:
+```
+build.py...
+/home/kostr/edk2/UefiLessonsPkg/UefiLessonsPkg.dsc(...): error 4000: Instance of library class [UefiApplicationEntryPoint] is not found
+ in [/home/kostr/edk2/UefiLessonsPkg/SimplestApp/SimplestApp.inf] [X64]
+ consumed by module [/home/kostr/edk2/UefiLessonsPkg/SimplestApp/SimplestApp.inf]
+```
+
+To fix this we need to add `UefiApplicationEntryPoint` to the `LibraryClasses` section in our `UefiLessonsPkg.dsc` file.
+To find necessay include lets search our edk2 codebase:
+```
+$ grep UefiApplicationEntryPoint -r ./ --include=*.inf | grep LIBRARY_CLASS
+./MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf: LIBRARY_CLASS = UefiApplicationEntryPoint|UEFI_APPLICATION
+```
+
+Therefore we need to add these strings to our *.dsc file:
+```
+[LibraryClasses]
+ UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
+```
+Format of the record is
+```
+LibraryClassName|Path/To/LibInstanceName.inf
+```
+LibraryClass can have several potential realizations (instances), therefore we need to write both `LibraryClassName` and `LibraryInstanceName`.
+
+In the end this adds this string to the Makefile:
+```
+LIBS = $(LIBS) $(LIB_DIR)/$(LibInstanceName)
+```
+You can read more about `LibraryClasses` section under https://edk2-docs.gitbook.io/edk-ii-dsc-specification/2_dsc_overview/26_-libraryclasses-_section_processing
+
+Let's try to rebuild:
+```
+$ build --platform=UefiLessonsPkg/UefiLessonsPkg.dsc \
+ --module=UefiLessonsPkg/SimplestApp/SimplestApp.inf \
+ --arch=X64 \
+ --buildtarget=RELEASE \
+ --tagname=GCC5
+```
+
+But the build would fail again:
+```
+build.py...
+/home/kostr/tiano/edk2/UefiLessonsPkg/UefiLessonsPkg.dsc(...): error 4000: Instance of library class [UefiBootServicesTableLib] is not found
+ in [/home/kostr/tiano/edk2/MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf] [X64]
+ consumed by module [/home/kostr/tiano/edk2/UefiLessonsPkg/SimplestApp/SimplestApp.inf]
+```
+
+As we see the error message is the same. It seems like `UefiApplicationEntryPoint` module that we've included needs some additional includes. So we search necessary libraries again... and again... and again.
+In the end our *.dsc file would be looking like this:
+```
+[Defines]
+ PLATFORM_NAME = UefiLessonsPkg
+ PLATFORM_GUID = 3db7270f-ffac-4139-90a4-0ae68f3f8167
+ PLATFORM_VERSION = 0.01
+ DSC_SPECIFICATION = 0x00010006
+ OUTPUT_DIRECTORY = Build/UefiLessonsPkg
+ SUPPORTED_ARCHITECTURES = X64
+ BUILD_TARGETS = RELEASE
+ SKUID_IDENTIFIER = DEFAULT
+
+[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
+
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
+```
+
+After the successful build the result binary would be in a `Build/UefiLessonsPkg/RELEASE_GCC5/X64` folder:
+```
+$ ls -lh Build/UefiLessonsPkg/RELEASE_GCC5/X64/SimplestApp.efi
+-rw-r--r-- 1 kostr kostr 960 Jun 13 12:47 Build/UefiLessonsPkg/RELEASE_GCC5/X64/SimplestApp.efi
+```
+
+Let's copy in our `UEFI_disk` folder and run it in OVMF:
+```
+$ cp Build/UefiLessonsPkg/RELEASE_GCC5/X64/SimplestApp.efi ~/UEFI_disk/
+$ qemu-system-x86_64 -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
+ -drive format=raw,file=fat:rw:~/UEFI_disk \
+ -nographic \
+ -net none
+```
+
+Hopefully everything would be the same it was earlier:
+```
+UEFI Interactive Shell v2.2
+EDK II
+UEFI v2.70 (EDK II, 0x00010000)
+Mapping table
+ FS0: Alias(s):HD0a1:;BLK1:
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
+ BLK0: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ BLK2: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+Press ESC in 4 seconds to skip startup.nsh or any other key to continue.
+Shell> fs0:
+FS0:\> SimplestApp.efi
+FS0:\>
+```
diff --git a/Lessons/Lesson_02/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_02/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_02/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/Lessons/Lesson_02/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_02/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_02/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/Lessons/Lesson_02/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_02/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..61378d6
--- /dev/null
+++ b/Lessons/Lesson_02/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,23 @@
+[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
+
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
+
diff --git a/Lessons/Lesson_03/README.md b/Lessons/Lesson_03/README.md
new file mode 100644
index 0000000..af1d1ad
--- /dev/null
+++ b/Lessons/Lesson_03/README.md
@@ -0,0 +1,229 @@
+Finally we are ready to write our "Hello World" app.
+
+First we create a new edk2 module in our package directory similar to the our `SimplestApp` module:
+```
+$ mkdir UefiLessonsPkg/HelloWorld
+$ vi UefiLessonsPkg/HelloWorld/HelloWorld.inf
+[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
+```
+Don't forget to add our newly created app to the `Components` section of the package DSC file
+```
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
++ UefiLessonsPkg/HelloWorld/HelloWorld.inf
+```
+Next we need to write the source code file. Let's remember the code for our SimplestApp:
+```
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EFI_SUCCESS;
+}
+```
+To print something to the console ("Hello World" message in our case) we need to use services from the `EFI_SYSTEM_TABLE` that is passed to the entry point of our app.
+
+The description of the `EFI_SYSTEM_TABLE` can be found in the UEFI specification (https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf).
+
+EFI_SYSTEM_TABLE is a struct that was populated by the UEFI firmware and contains pointers to the runtime and boot services tables.
+```
+typedef struct {
+ EFI_TABLE_HEADER Hdr;
+ CHAR16 *FirmwareVendor;
+ UINT32 FirmwareRevision;
+ EFI_HANDLE ConsoleInHandle;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
+ EFI_HANDLE ConsoleOutHandle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
+ EFI_HANDLE StandardErrorHandle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr;
+ EFI_RUNTIME_SERVICES *RuntimeServices;
+ EFI_BOOT_SERVICES *BootServices;
+ UINTN NumberOfTableEntries;
+ EFI_CONFIGURATION_TABLE *ConfigurationTable;
+} EFI_SYSTEM_TABLE;
+```
+We are interested in the `ConOut` field. `ConOut` is abbreviaton for "Console Output" and according to the UEFI spec it is a pointer to the `EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL` interface that is associated with `ConsoleOutHandle`.
+
+If we keep digging into UEFI spec we can find description of the `EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL`.
+According to the spec `EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL` defines the minimum requirements for a text-based ConsoleOut device.
+
+As everything in UEFI it has GUID:
+```
+#define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \
+ {0x387477c2,0x69c7,0x11d2,\
+ {0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b}}
+```
+
+And the interface description is:
+```
+typedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
+ EFI_TEXT_RESET Reset;
+ EFI_TEXT_STRING OutputString;
+ EFI_TEXT_TEST_STRING TestString;
+ EFI_TEXT_QUERY_MODE QueryMode;
+ EFI_TEXT_SET_MODE SetMode;
+ EFI_TEXT_SET_ATTRIBUTE SetAttribute;
+ EFI_TEXT_CLEAR_SCREEN ClearScreen;
+ EFI_TEXT_SET_CURSOR_POSITION SetCursorPosition;
+ EFI_TEXT_ENABLE_CURSOR EnableCursor;
+ SIMPLE_TEXT_OUTPUT_MODE *Mode;
+} EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
+```
+Right now we are interested in a `OutputString` method:
+```
+OutputString Displays the string on the device at the current cursor location.
+```
+This is what we need. Let's look at the function description:
+```
+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString()
+
+Summary
+Writes a string to the output device.
+
+Prototype
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TEXT_STRING) (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *String
+ );
+
+Parameters
+This A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+String The Null-terminated string to be displayed on the output device(s).
+```
+
+In edk2 `EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL` is defined in the header file:
+https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/SimpleTextOut.h
+
+
+With all this knowledge we can write our source code file `UefiLessonsPkg/HelloWorld/HelloWorld.c`:
+```
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello World!\n");
+ return EFI_SUCCESS;
+}
+```
+
+The `L""` signifies that the string is composed from CHAR16 symbols, as was required in spec.
+
+As for `CHAR16` - UEFI uses special names like these for simple types. It is a proxy for a different type realization in different processor architectures.
+When we compile our code code for X64, our realization would be picked from a file https://github.com/tianocore/edk2/blob/master/MdePkg/Include/X64/ProcessorBind.h:
+```
+typedef unsigned short CHAR16;
+```
+For example RISCV would define it like this (https://github.com/tianocore/edk2/blob/master/MdePkg/Include/RiscV64/ProcessorBind.h):
+```
+typedef unsigned short CHAR16 __attribute__ ((aligned (2)));
+```
+
+All the simple types for X64:
+```
+ ///
+ /// 8-byte unsigned value
+ ///
+ typedef unsigned long long UINT64;
+ ///
+ /// 8-byte signed value
+ ///
+ typedef long long INT64;
+ ///
+ /// 4-byte unsigned value
+ ///
+ typedef unsigned int UINT32;
+ ///
+ /// 4-byte signed value
+ ///
+ typedef int INT32;
+ ///
+ /// 2-byte unsigned value
+ ///
+ typedef unsigned short UINT16;
+ ///
+ /// 2-byte Character. Unless otherwise specified all strings are stored in the
+ /// UTF-16 encoding format as defined by Unicode 2.1 and ISO/IEC 10646 standards.
+ ///
+ typedef unsigned short CHAR16;
+ ///
+ /// 2-byte signed value
+ ///
+ typedef short INT16;
+ ///
+ /// Logical Boolean. 1-byte value containing 0 for FALSE or a 1 for TRUE. Other
+ /// values are undefined.
+ ///
+ typedef unsigned char BOOLEAN;
+ ///
+ /// 1-byte unsigned value
+ ///
+ typedef unsigned char UINT8;
+ ///
+ /// 1-byte Character
+ ///
+ typedef char CHAR8;
+ ///
+ /// 1-byte signed value
+ ///
+ typedef signed char INT8;
+```
+
+
+Let's finally compile our edk2 module:
+```
+$ build --platform=UefiLessonsPkg/UefiLessonsPkg.dsc \
+ --module=UefiLessonsPkg/HelloWorld/HelloWorld.inf \
+ --arch=X64 \
+ --buildtarget=RELEASE --tagname=GCC5
+```
+
+Copy the app to our `UEFI_disk` folder and run OVMF:
+```
+$ cp Build/UefiLessonsPkg/RELEASE_GCC5/X64/HelloWorld.efi ~/UEFI_disk/
+$ qemu-system-x86_64 -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
+ -drive format=raw,file=fat:rw:~/UEFI_disk \
+ -nographic \
+ -net none
+```
+
+```
+UEFI Interactive Shell v2.2
+EDK II
+UEFI v2.70 (EDK II, 0x00010000)
+Mapping table
+ FS0: Alias(s):HD0a1:;BLK1:
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
+ BLK0: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ BLK2: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+Press ESC in 4 seconds to skip startup.nsh or any other key to continue.
+Shell> fs0:
+FS0:\> HelloWorld.efi
+Hello World!
+FS0:\>
+```
diff --git a/Lessons/Lesson_03/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_03/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..399b0ac
--- /dev/null
+++ b/Lessons/Lesson_03/UefiLessonsPkg/HelloWorld/HelloWorld.c
@@ -0,0 +1,10 @@
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello World!\n");
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_03/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_03/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..95924c5
--- /dev/null
+++ b/Lessons/Lesson_03/UefiLessonsPkg/HelloWorld/HelloWorld.inf
@@ -0,0 +1,17 @@
+[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
+
diff --git a/Lessons/Lesson_03/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_03/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_03/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/Lessons/Lesson_03/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_03/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_03/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/Lessons/Lesson_03/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_03/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..91a79e6
--- /dev/null
+++ b/Lessons/Lesson_03/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,26 @@
+[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
+
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
+ UefiLessonsPkg/HelloWorld/HelloWorld.inf
+
+
diff --git a/Lessons/Lesson_04/README.md b/Lessons/Lesson_04/README.md
new file mode 100644
index 0000000..8892c28
--- /dev/null
+++ b/Lessons/Lesson_04/README.md
@@ -0,0 +1,229 @@
+In this lesson we keep working on our 'Hello World' app.
+
+It is kinda tedious to write such a long string for a simple printf:
+```
+ SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello World!\n");
+```
+
+So let's try to simplify it.
+
+First in UEFI/edk2 you would be using a lot this `SystemTable` pointer as well as its filed `SystemTable->BootServices` and another main function parameter `ImageHandle`.
+
+So simplify access to these variables edk2 library create global defines for them gST, gBS, gImageHandle.
+
+You could look at the source of the UefiBootServicesTableLib.c:
+
+https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.c
+
+https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/UefiBootServicesTableLib.h
+
+```
+EFI_HANDLE gImageHandle = NULL;
+EFI_SYSTEM_TABLE *gST = NULL;
+EFI_BOOT_SERVICES *gBS = NULL;
+
+EFI_STATUS
+EFIAPI
+UefiBootServicesTableLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ //
+ // Cache the Image Handle
+ //
+ gImageHandle = ImageHandle;
+ ASSERT (gImageHandle != NULL);
+
+ //
+ // Cache pointer to the EFI System Table
+ //
+ gST = SystemTable;
+ ASSERT (gST != NULL);
+
+ //
+ // Cache pointer to the EFI Boot Services Table
+ //
+ gBS = SystemTable->BootServices;
+ ASSERT (gBS != NULL);
+
+ return EFI_SUCCESS;
+}
+```
+
+Let's try to use them in our function:
+
+```
+gST->ConOut->OutputString(gST->ConOut, L"Hello again!\n");
+```
+
+And try to recompile:
+```
+$ build --platform=UefiLessonsPkg/UefiLessonsPkg.dsc \
+ --module=UefiLessonsPkg/HelloWorld/HelloWorld.inf \
+ --arch=X64 \
+ --buildtarget=RELEASE --tagname=GCC5
+```
+
+Unfortunately this will not compile:
+```
+/home/kostr/edk2/UefiLessonsPkg/HelloWorld/HelloWorld.c: In function ‘UefiMain’:
+/home/kostr/edk2/UefiLessonsPkg/HelloWorld/HelloWorld.c:12:3: error: ‘gST’ undeclared (first use in this function)
+ 12 | gST->ConOut->OutputString(gST->ConOut, L"Hello again!\n");
+ | ^~~
+```
+
+This error message is familiar, we'are missing some `#include` in our file, so let's add it:
+```
+#include <Library/UefiBootServicesTableLib.h>
+```
+
+This library is already included in our *.dsc file, so we are good to go:
+```
+[LibraryClasses]
+ ...
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+ ...
+```
+
+Our source code file at this point is:
+```
+// for gBS
+#include <Library/UefiBootServicesTableLib.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");
+ return EFI_SUCCESS;
+}
+```
+
+Test for the successful compilation:
+```
+$ build --platform=UefiLessonsPkg/UefiLessonsPkg.dsc \
+ --module=UefiLessonsPkg/HelloWorld/HelloWorld.inf \
+ --arch=X64 \
+ --buildtarget=RELEASE --tagname=GCC5
+```
+
+In the case of printf we can simplify things even more. Print is such a common function, that there is a library function for it in edk2. Add this to our file:
+```
+Print(L"Bye!\n");
+```
+
+If we try to recompile we would get error message about missing `#include` once again:
+```
+/home/kostr/tiano/edk2/UefiLessonsPkg/HelloWorld/HelloWorld.c: In function ‘UefiMain’:
+/home/kostr/tiano/edk2/UefiLessonsPkg/HelloWorld/HelloWorld.c:13:3: error: implicit declaration of function ‘Print’ [-Werror=implicit-function-declaration]
+ 13 | Print(L"Bye!\n");
+ | ^~~~~
+```
+
+In this case header and source file for the `Print` function are:
+- https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/UefiLib.h
+- https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiLib/UefiLibPrint.c
+
+So let's include `UefiLib.h` in our file:
+```
+#include <Library/UefiLib.h>
+```
+And try to recompile.
+```
+$ build --platform=UefiLessonsPkg/UefiLessonsPkg.dsc \
+ --module=UefiLessonsPkg/HelloWorld/HelloWorld.inf \
+ --arch=X64 \
+ --buildtarget=RELEASE --tagname=GCC5
+```
+
+Build would fail with a message:
+```
+/home/kostr/edk2/MdePkg/Library/BasePrintLib/PrintLibInternal.c:821: undefined reference to `Print'
+collect2: error: ld returned 1 exit status
+make: *** [GNUmakefile:307: /home/kostr/edk2/Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/HelloWorld/HelloWorld/DEBUG/HelloWorld.dll] Error 1
+```
+
+Compilation step was successful, but the linker have failed. This usually means that *.h file was in place, but the actual library wasn't linked.
+
+```
+$ grep UefiLib -r ./ --include=*.inf | grep LIBRARY_CLASS
+./MdePkg/Library/UefiLib/UefiLib.inf: LIBRARY_CLASS = UefiLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
+```
+
+Add this to our `UefiLessonsPkg/UefiLessonsPkg.dsc` file:
+```
+[LibraryClasses]
+ ...
++ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+```
+And this string to our `UefiLessonsPkg/HelloWorld/HelloWorld.inf` file:
+```
+[LibraryClasses]
+ UefiApplicationEntryPoint
++ UefiLib
+```
+
+If we try to build, we will get `Failed` once again:
+```
+/home/kostr/edk2/UefiLessonsPkg/UefiLessonsPkg.dsc(...): error 4000: Instance of library class [MemoryAllocationLib] is not found
+ in [/home/kostr/edk2/MdePkg/Library/UefiLib/UefiLib.inf] [X64]
+ consumed by module [/home/kostr/edk2/UefiLessonsPkg/HelloWorld/HelloWorld.inf]
+```
+
+Try to find it:
+```
+$ grep MemoryAllocationLib -r ./ --include=*.inf | grep LIBRARY_CLASS | grep MdePkg
+./MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf: LIBRARY_CLASS = MemoryAllocationLib|PEIM PEI_CORE SEC
+./MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf: LIBRARY_CLASS = MemoryAllocationLib|DXE_SMM_DRIVER
+./MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf: LIBRARY_CLASS = MemoryAllocationLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+```
+
+Add this to our *.dsc file:
+```
+[LibraryClasses]
+ ...
++ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+```
+
+After that we would get another build failure with the similar message. So we need to repeat this process of finding right library. In the end we would need to add two more libraries:
+```
+[LibraryClasses]
+ ...
++ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
++ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+```
+
+After that finally build would finish successfully.
+
+Test it:
+```
+cp Build/UefiLessonsPkg/RELEASE_GCC5/X64/HelloWorld.efi ~/UEFI_disk/
+$ qemu-system-x86_64 -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
+ -drive format=raw,file=fat:rw:~/UEFI_disk \
+ -nographic \
+ -net none
+```
+```
+UEFI Interactive Shell v2.2
+EDK II
+UEFI v2.70 (EDK II, 0x00010000)
+Mapping table
+ FS0: Alias(s):HD0a1:;BLK1:
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
+ BLK0: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ BLK2: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+Press ESC in 1 seconds to skip startup.nsh or any other key to continue.
+Shell> fs0:
+FS0:\> HelloWorld.efi
+Hello World!
+Hello again!
+Bye!
+FS0:\>
+```
diff --git a/Lessons/Lesson_04/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_04/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..1f05899
--- /dev/null
+++ b/Lessons/Lesson_04/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/Lessons/Lesson_04/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_04/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_04/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/Lessons/Lesson_04/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_04/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_04/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/Lessons/Lesson_04/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_04/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_04/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/Lessons/Lesson_04/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_04/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..0a2edbe
--- /dev/null
+++ b/Lessons/Lesson_04/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,30 @@
+[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
+
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
+ UefiLessonsPkg/HelloWorld/HelloWorld.inf
+
+
diff --git a/Lessons/Lesson_05/Conf/target.txt b/Lessons/Lesson_05/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lessons/Lesson_05/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/Lessons/Lesson_05/README.md b/Lessons/Lesson_05/README.md
new file mode 100644
index 0000000..23130f4
--- /dev/null
+++ b/Lessons/Lesson_05/README.md
@@ -0,0 +1,53 @@
+To build modules in our package we've used something like this:
+```
+$ build --platform=UefiLessonsPkg/UefiLessonsPkg.dsc \
+ --module=UefiLessonsPkg/HelloWorld/HelloWorld.inf \
+ --arch=X64 \
+ --buildtarget=RELEASE \
+ --tagname=GCC5
+```
+
+This is kinda long string. Let's simplify it.
+
+First we can omit `module` option from the command and always compile our package entirely with all its modules:
+
+```
+$ build --platform=UefiLessonsPkg/UefiLessonsPkg.dsc \
+ --arch=X64 \
+ --buildtarget=RELEASE \
+ --tagname=GCC5
+```
+
+When we initiate our environment with:
+```
+. edk2setup.sh
+```
+`Conf` directory is created in the edk2 folder. This directory is populated with a bunch of files.
+Also the `CONF_PATH` environment variable is created which points to the newly created `Conf` folder.
+
+Right now we are interested in the `Conf/target.txt` file.
+By default it has many comments (lines that start with `#` symbol) and is prepopulated with these values:
+```
+ACTIVE_PLATFORM = EmulatorPkg/EmulatorPkg.dsc
+TARGET = DEBUG
+TARGET_ARCH = IA32
+TOOL_CHAIN_CONF = Conf/tools_def.txt
+TOOL_CHAIN_TAG = VS2015x86
+BUILD_RULE_CONF = Conf/build_rule.txt
+```
+
+We can put all our build command options in this file to simplify our everyday life.
+```
+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
+```
+
+After that we could build our package with all its modules with the one single command:
+```
+build
+```
+
diff --git a/Lessons/Lesson_05/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_05/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..1f05899
--- /dev/null
+++ b/Lessons/Lesson_05/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/Lessons/Lesson_05/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_05/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_05/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/Lessons/Lesson_05/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_05/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_05/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/Lessons/Lesson_05/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_05/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_05/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/Lessons/Lesson_05/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_05/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..0a2edbe
--- /dev/null
+++ b/Lessons/Lesson_05/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,30 @@
+[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
+
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
+ UefiLessonsPkg/HelloWorld/HelloWorld.inf
+
+
diff --git a/Lessons/Lesson_06/Conf/target.txt b/Lessons/Lesson_06/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lessons/Lesson_06/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/Lessons/Lesson_06/Handle_Protocol_databases_scheme.jpg b/Lessons/Lesson_06/Handle_Protocol_databases_scheme.jpg
new file mode 100644
index 0000000..771a981
--- /dev/null
+++ b/Lessons/Lesson_06/Handle_Protocol_databases_scheme.jpg
Binary files differ
diff --git a/Lessons/Lesson_06/README.md b/Lessons/Lesson_06/README.md
new file mode 100644
index 0000000..3bd7b83
--- /dev/null
+++ b/Lessons/Lesson_06/README.md
@@ -0,0 +1,243 @@
+Let's create `ImageHandle` app in our `UefiLessonsPkg`.
+
+First generate a random GUID.
+```
+$ uuidgen
+b68d3472-70c7-4928-841b-6566032e0a23
+```
+
+And then create *.inf and *.c file based on the code in our `HelloWorld` app:
+```
+$ cat UefiLessonsPkg/ImageHandle/ImageHandle.inf
+[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
+```
+```
+$ cat UefiLessonsPkg/ImageHandle/ImageHandle.c
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EFI_SUCCESS;
+}
+```
+Add a newly created app to our `UefiLessonsPkg/UefiLessonsPkg.dsc` file:
+```
+[Components]
+ ...
++ UefiLessonsPkg/ImageHandle/ImageHandle.inf
+```
+
+Now let's get to work.
+
+Our main function in a *.c file has 2 input parameters `EFI_HANDLE ImageHandle` and `EFI_SYSTEM_TABLE *SystemTable`:
+```
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+```
+We've already started to explore the `EFI_SYSTEM_TABLE`. In this lesson let's look what `ImageHandle` is about.
+
+`ImageHandle` parameter is a handle of an image for the program itself.
+
+You can found a definition for a `EFI_HANDLE` type in a https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Uefi/UefiBaseType.h
+```
+///
+/// A collection of related interfaces.
+///
+typedef VOID *EFI_HANDLE;
+```
+So it is simply a pointer to a void. So it could be a pointer to anything.
+
+In a reality it is a pointer to this type of structure https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Core/Dxe/Hand/Handle.h :
+```
+#define EFI_HANDLE_SIGNATURE SIGNATURE_32('h','n','d','l')
+
+///
+/// IHANDLE - contains a list of protocol handles
+///
+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;
+```
+LIST_ENTRY is a double linked list. So with it we can traverse to any handle in the system. Sometimes it is called the Handle database.
+
+In case you wonder how LIST_ENTRY is defined look at the https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Base.h :
+```
+///
+/// LIST_ENTRY structure definition.
+///
+typedef struct _LIST_ENTRY LIST_ENTRY;
+
+///
+/// _LIST_ENTRY structure definition.
+///
+struct _LIST_ENTRY {
+ LIST_ENTRY *ForwardLink;
+ LIST_ENTRY *BackLink;
+};
+```
+Each handle has a list of protocols attached to it. Protocol is like an interface - a set of functions and data fields. To track the list of protocols attached to a handle this field is used:
+```
+ /// List of PROTOCOL_INTERFACE's for this handle
+ LIST_ENTRY Protocols;
+```
+It is another double linked list that points to these structures:
+```
+#define PROTOCOL_INTERFACE_SIGNATURE SIGNATURE_32('p','i','f','c')
+
+///
+/// PROTOCOL_INTERFACE - each protocol installed on a handle is tracked
+/// with a protocol interface structure
+///
+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;
+```
+
+Effectively PROTOCOL_INTERFACE structure is only a proxy that points to an actual PROTOCOL_ENTRY structrure which are exist in a separate protocol database.
+```
+#define PROTOCOL_ENTRY_SIGNATURE SIGNATURE_32('p','r','t','e')
+
+///
+/// PROTOCOL_ENTRY - each different protocol has 1 entry in the protocol
+/// database. Each handler that supports this protocol is listed, along
+/// with a list of registered notifies.
+///
+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;
+```
+It all sounds a little bit complicated so it is better to see it in a picture:
+![Handle_Protocol_databases_scheme](Handle_Protocol_databases_scheme.jpg?raw=true "Handle/Protocol databases scheme")
+Important information from the picture:
+- HANDLE 0 has PROTOCOL_INTERFACE 0 (->PROTOCOL_ENTRY 0) and PROTOCOL_INTERFACE 1 (->PROTOCOL_ENTRY 1)
+- HANDLE 1 has PROTOCOL_INTERFACE 2 (->PROTOCOL_ENTRY 2) and PROTOCOL_INTERFACE 3 (->PROTOCOL_ENTRY 1)
+- HANDLE 2 has PROTOCOL_INTERFACE 4 (->PROTOCOL_ENTRY 1)
+Besides that:
+- All handles are interconnected with the help of `AllHandles` field in each `IHANDLE` structure
+- All protocols are interconnected with the help of `AllEntries` field in each `PROTOCOL_ENTRY` structure
+Red lines:
+- Each handle has a double linked list of all its PROTOCOL_INTERFACES, which internally connected to each other through the `Link` field
+Green lines:
+- Each protocol entry effectively knows all the users (=PROTOCOL_INTERFACES) of it.
+
+Let's check that `EFI_HANDLE ImageHandle` effectively is the `IHANDLE` structure.
+
+To check this we will cast `ImageHandle` to `IHANDLE` and print its signature.
+
+```
+#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;
+
+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);
+
+ return EFI_SUCCESS;
+}
+```
+
+Don't blame me for redefinition of `IHANDLE` structure. These structures (IHANDLE/PROTOCOL_ENTRY/PROTOCOL_INTERFACE) are private and not intended to be used outside of the `MdeModulePkg`. Even https://github.com/tianocore/edk2/blob/master/StandaloneMmPkg/Core/StandaloneMmCore.h redifines IHANDLE/PROTOCOL_ENTRY/PROTOCOL_INTERFACE.
+
+```
+$ . edksetup.sh
+$ build
+$ cp Build/UefiLessonsPkg/RELEASE_GCC5/X64/ImageHandle.efi ~/UEFI_disk/
+$ qemu-system-x86_64 -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
+ -drive format=raw,file=fat:rw:~/UEFI_disk \
+ -nographic \
+ -net none
+```
+
+```
+UEFI Interactive Shell v2.2
+EDK II
+UEFI v2.70 (EDK II, 0x00010000)
+Mapping table
+ FS0: Alias(s):HD0a1:;BLK1:
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
+ BLK0: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ BLK2: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+Press ESC in 4 seconds to skip startup.nsh or any other key to continue.
+Shell> fs0:
+FS0:\> ImageHandle.efi
+Signature: h n d l
+```
+
+
+
diff --git a/Lessons/Lesson_06/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_06/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..1f05899
--- /dev/null
+++ b/Lessons/Lesson_06/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/Lessons/Lesson_06/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_06/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_06/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/Lessons/Lesson_06/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_06/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..e869e28
--- /dev/null
+++ b/Lessons/Lesson_06/UefiLessonsPkg/ImageHandle/ImageHandle.c
@@ -0,0 +1,30 @@
+#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;
+
+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);
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_06/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_06/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_06/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/Lessons/Lesson_06/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_06/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_06/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/Lessons/Lesson_06/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_06/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_06/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/Lessons/Lesson_06/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_06/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..0d4fbb0
--- /dev/null
+++ b/Lessons/Lesson_06/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,31 @@
+[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
+
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
+ UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ UefiLessonsPkg/ImageHandle/ImageHandle.inf
+
+
diff --git a/Lessons/Lesson_07/Conf/target.txt b/Lessons/Lesson_07/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lessons/Lesson_07/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/Lessons/Lesson_07/README.md b/Lessons/Lesson_07/README.md
new file mode 100644
index 0000000..66e8689
--- /dev/null
+++ b/Lessons/Lesson_07/README.md
@@ -0,0 +1,229 @@
+Let's print GUID for all the protocols that are exist in our `IMAGE_HANDLE`.
+
+First understand what `EFI_GUID` internally means in the edk2 codebase:
+
+https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Uefi/UefiBaseType.h
+```
+///
+/// 128-bit buffer containing a unique identifier value.
+///
+typedef GUID EFI_GUID;
+```
+`GUID` structure is defined in https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Base.h :
+```
+///
+/// 128 bit buffer containing a unique identifier value.
+/// Unless otherwise specified, aligned on a 64 bit boundary.
+///
+typedef struct {
+ UINT32 Data1;
+ UINT16 Data2;
+ UINT16 Data3;
+ UINT8 Data4[8];
+} GUID;
+```
+Fortunately we don't have to manually print all these fields by hand. `Print` function has a format option `%g` to print GUIDs, so we could simply print GUIDs with a code like this:
+```
+Print("GUID=%g\n", myGUID);
+```
+More information about `Print` formating options can be found at https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PrintLib.h
+
+
+We want to print `EFI_GUID` field from the `PROTOCOL_ENTRY` structure which are referred from the `PROTOCOL_INTERFACE` structures. So we need to define both of these structures in our file for the same reason we've defined `IHANDLE` earlier.
+
+```
+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;
+```
+
+`PROTOCOL_INTERFACE` structures that are connected to any HANDLE are interlinked with each other with a help of a `LIST_ENTRY Link` field that connects them to a double linked list.
+
+As you may remember `LIST_ENTRY` is defined like this:
+```
+///
+/// LIST_ENTRY structure definition.
+///
+typedef struct _LIST_ENTRY LIST_ENTRY;
+
+///
+/// _LIST_ENTRY structure definition.
+///
+struct _LIST_ENTRY {
+ LIST_ENTRY *ForwardLink;
+ LIST_ENTRY *BackLink;
+};
+```
+Each of these fields inside these structure points to another `LIST_ENTRY` structure that is placed in another `PROTOCOL_INTERFACE`.
+
+So this connection looks like this:
+
+```
+typedef struct { typedef struct {
+ UINTN Signature; UINTN Signature;
+ struct LIST_ENTRY { |---------> struct LIST_ENTRY {
+ LIST_ENTRY *ForwardLink; -----------------| LIST_ENTRY *ForwardLink;
+ LIST_ENTRY *BackLink; LIST_ENTRY *BackLink;
+ } Link; } Link;
+ IHANDLE *Handle; IHANDLE *Handle;
+ LIST_ENTRY ByProtocol; LIST_ENTRY ByProtocol;
+ PROTOCOL_ENTRY *Protocol; PROTOCOL_ENTRY *Protocol;
+ VOID *Interface; VOID *Interface;
+ LIST_ENTRY OpenList; LIST_ENTRY OpenList;
+ UINTN OpenListCount; UINTN OpenListCount;
+} PROTOCOL_INTERFACE; } PROTOCOL_INTERFACE;
+```
+
+But in reality we want a pointer not to `Link` field of another `PROTOCOL_INTERFACE` structure, we want a pointer to another `PROTCOL_INTERFACE` structure inself.
+
+Therefore one more thing that we would need is a couple of macros:
+```
+#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) );})
+```
+These macros can be familiar to you if you've investigated linux kernel programming. This is where I got them from anyway.
+
+`contianer_of` macro helps to get a pointer to a structure if you have a pointer to one of its fields.
+
+If you want to understand how it works internally in C language I suggest you to look at the https://stackoverflow.com/questions/15832301/understanding-container-of-macro-in-the-linux-kernel
+
+With all of this information final code for our `UefiMain` function would look like this:
+```
+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: %c %c %c %c\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);
+
+ return EFI_SUCCESS;
+}
+```
+
+If we compile and run our app in OVMF (I hope at this time I don't need to repeat how to do it):
+```
+FS0:\> ImageHandle.efi
+h n d l
+Back Protocol Interface Link: 68D4320
+Forward Protocol Interface Link: 6891520
+
+Current Link: 6891520
+p i f c
+Back Link: 6891430
+Forward Link: 6891B20
+GUID=752F3136-4E16-4FDC-A22A-E5F46812F4CA
+
+Current Link: 6891B20
+p i f c
+Back Link: 6891520
+Forward Link: 68D4320
+GUID=BC62157E-3E33-4FEC-9920-2D3B36D750DF
+
+Current Link: 68D4320
+p i f c
+Back Link: 6891B20
+Forward Link: 6891430
+GUID=5B1B31A1-9562-11D2-8E3F-00A0C969723B
+
+Current Link: 6891430
+ ? ? ?
+Back Link: 68D4320
+Forward Link: 6891520
+GUID=00000000-0000-0000-0000-000000000000
+```
+
+Let's find first GUID by executing grep on the edk2 source:
+```
+$ grep -i 752F3136 -r ./ --exclude-dir=Build
+./MdePkg/Include/Protocol/ShellParameters.h: 0x752f3136, 0x4e16, 0x4fdc, { 0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca } \
+./MdePkg/MdePkg.dec: gEfiShellParametersProtocolGuid = { 0x752f3136, 0x4e16, 0x4fdc, {0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca }}
+```
+
+https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/ShellParameters.h
+```
+#define EFI_SHELL_PARAMETERS_PROTOCOL_GUID \
+ { \
+ 0x752f3136, 0x4e16, 0x4fdc, { 0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca } \
+ }
+```
+You can also see in in a https://github.com/tianocore/edk2/blob/master/MdePkg/MdePkg.dec file:
+```
+ ## Include/Protocol/ShellParameters.h
+ gEfiShellParametersProtocolGuid = { 0x752f3136, 0x4e16, 0x4fdc, {0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca }}
+```
+
+The next two GUIDs you can find in UEFI the specification.
+
+`EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL` - When installed, the Loaded Image Device Path Protocol specifies the device path that was used when a PE/COFF image was loaded through the EFI Boot Service LoadImage().
+
+```
+#define EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \
+{0xbc62157e,0x3e33,0x4fec,\
+ {0x99,0x20,0x2d,0x3b,0x36,0xd7,0x50,0xdf}}
+```
+
+`EFI_LOADED_IMAGE_PROTOCOL` - Can be used on any image handle to obtain information about the loaded image.
+```
+#define EFI_LOADED_IMAGE_PROTOCOL_GUID\
+ {0x5B1B31A1,0x9562,0x11d2,\
+ {0x8E,0x3F,0x00,0xA0,0xC9,0x69,0x72,0x3B}}
+```
+
+The last `PROTOCOL_INTERFACE` structure doesn't have a valid "p i f c" signature (in my case it is 0x20 0x0E 0xED 0x06), so we don't need to look at its GUID.
+
diff --git a/Lessons/Lesson_07/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_07/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..1f05899
--- /dev/null
+++ b/Lessons/Lesson_07/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/Lessons/Lesson_07/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_07/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_07/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/Lessons/Lesson_07/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_07/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..bcf42e3
--- /dev/null
+++ b/Lessons/Lesson_07/UefiLessonsPkg/ImageHandle/ImageHandle.c
@@ -0,0 +1,88 @@
+#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);
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_07/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_07/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_07/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/Lessons/Lesson_07/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_07/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_07/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/Lessons/Lesson_07/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_07/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_07/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/Lessons/Lesson_07/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_07/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..0d4fbb0
--- /dev/null
+++ b/Lessons/Lesson_07/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,31 @@
+[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
+
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
+ UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ UefiLessonsPkg/ImageHandle/ImageHandle.inf
+
+
diff --git a/Lessons/Lesson_08/DevicePath.png b/Lessons/Lesson_08/DevicePath.png
new file mode 100644
index 0000000..225226f
--- /dev/null
+++ b/Lessons/Lesson_08/DevicePath.png
Binary files differ
diff --git a/Lessons/Lesson_08/README.md b/Lessons/Lesson_08/README.md
new file mode 100644
index 0000000..fd31bcf
--- /dev/null
+++ b/Lessons/Lesson_08/README.md
@@ -0,0 +1,269 @@
+Let's explore protocols associated with our `ImageHandle` that we've discovered in the last lesson.
+
+If we try to grep GUIDs in the edk2 source code:
+```
+$ grep -i bc62157e -r ./ --exclude-dir=Build
+./MdePkg/Include/Protocol/LoadedImage.h: 0xbc62157e, 0x3e33, 0x4fec, {0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf } \
+./MdePkg/MdePkg.dec: gEfiLoadedImageDevicePathProtocolGuid = { 0xbc62157e, 0x3e33, 0x4fec, {0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf }}
+$ grep -i 5B1B31A1 -r ./ --exclude-dir=Build
+./MdePkg/Include/Protocol/LoadedImage.h: 0x5B1B31A1, 0x9562, 0x11d2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B } \
+./MdePkg/MdePkg.dec: gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}
+```
+
+Link to the header file: https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/LoadedImage.h
+
+Description for one of these protocol structures can be found in the same file:
+```
+///
+/// Can be used on any image handle to obtain information about the loaded image.
+///
+typedef struct {
+ UINT32 Revision; ///< Defines the revision of the EFI_LOADED_IMAGE_PROTOCOL structure.
+ ///< All future revisions will be backward compatible to the current revision.
+ EFI_HANDLE ParentHandle; ///< Parent image's image handle. NULL if the image is loaded directly from
+ ///< the firmware's boot manager.
+ EFI_SYSTEM_TABLE *SystemTable; ///< the image's EFI system table pointer.
+
+ //
+ // Source location of image
+ //
+ EFI_HANDLE DeviceHandle; ///< The device handle that the EFI Image was loaded from.
+ EFI_DEVICE_PATH_PROTOCOL *FilePath; ///< A pointer to the file path portion specific to DeviceHandle
+ ///< that the EFI Image was loaded from.
+ VOID *Reserved; ///< Reserved. DO NOT USE.
+
+ //
+ // Images load options
+ //
+ UINT32 LoadOptionsSize;///< The size in bytes of LoadOptions.
+ VOID *LoadOptions; ///< A pointer to the image's binary load options.
+
+ //
+ // Location of where image was loaded
+ //
+ VOID *ImageBase; ///< The base address at which the image was loaded.
+ UINT64 ImageSize; ///< The size in bytes of the loaded image.
+ EFI_MEMORY_TYPE ImageCodeType; ///< The memory type that the code sections were loaded as.
+ EFI_MEMORY_TYPE ImageDataType; ///< The memory type that the data sections were loaded as.
+ EFI_IMAGE_UNLOAD Unload;
+} EFI_LOADED_IMAGE_PROTOCOL;
+```
+
+UEFI specification gives following description for this protocol:
+```
+Each loaded image has an image handle that supports EFI_LOADED_IMAGE_PROTOCOL. When an image is started, it is passed the image handle for itself. The image can use the handle to obtain its relevant image data stored in the EFI_LOADED_IMAGE_PROTOCOL structure, such as its load options
+```
+
+Another GUID stands for the `EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL` - When installed, the Loaded Image Device Path Protocol specifies the device path that was used when a PE/COFF image was loaded through the EFI Boot Service LoadImage().
+The Loaded Image Device Path Protocol uses the same protocol interface structure as the Device Path Protocol. The only difference between the Device Path Protocol and the Loaded Image Device Path Protocol is the protocol GUID value.
+The Loaded Image Device Path Protocol must be installed onto the image handle of a PE/COFF image loaded through the EFI Boot Service LoadImage(). A copy of the device path specified by the DevicePath parameter to the EFI Boot Service LoadImage() is made before it is installed onto the image handle. It is legal to call LoadImage() for a buffer in memory with a NULL DevicePath parameter. In this case, the Loaded Image Device Path Protocol is installed with a NULL interface pointer.
+
+So effectively if you want to look up the definition for this protocol you should search `EFI_DEVICE_PATH_PROTOCOL`.
+
+It is defined in edk2 sources here https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/DevicePath.h :
+```
+/**
+ This protocol can be used on any device handle to obtain generic path/location
+ information concerning the physical device or logical device. If the handle does
+ not logically map to a physical device, the handle may not necessarily support
+ the device path protocol. The device path describes the location of the device
+ the handle is for. The size of the Device Path can be determined from the structures
+ that make up the Device Path.
+**/
+typedef struct {
+ UINT8 Type; ///< 0x01 Hardware Device Path.
+ ///< 0x02 ACPI Device Path.
+ ///< 0x03 Messaging Device Path.
+ ///< 0x04 Media Device Path.
+ ///< 0x05 BIOS Boot Specification Device Path.
+ ///< 0x7F End of Hardware Device Path.
+
+ UINT8 SubType; ///< Varies by Type
+ ///< 0xFF End Entire Device Path, or
+ ///< 0x01 End This Instance of a Device Path and start a new
+ ///< Device Path.
+
+ UINT8 Length[2]; ///< Specific Device Path data. Type and Sub-Type define
+ ///< type of data. Size of data is included in Length.
+
+} EFI_DEVICE_PATH_PROTOCOL;
+```
+This structure is like a header to an actual path data which immediately follows it for amount of `Length` bytes.
+![Device path](DevicePath.png?raw=true "Device Path in memory")
+
+
+Now we have understanding of all the protocol structures, it is time to know the right way of how to get to them.
+The "raw" method that we've used in last lessons was purely educational.
+UEFI has several functions to help to get the protocol structures in a code.
+
+`EFI_BOOT_SERVICES.HandleProtocol()` - Queries a handle to determine if it supports a specified protocol.
+
+UEFI docs:
+```
+Prototype:
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_HANDLE_PROTOCOL) (
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface
+);
+
+Parameters:
+Handle The handle being queried. If Handle isNULL, then EFI_INVALID_PARAMETER is returned.
+Protocol The published unique identifier of the protocol. It is the caller’s responsibility to pass in a valid GUID.
+Interface Supplies the address where a pointer to the corresponding Protocol Interface is returned.
+ NULL will be returned in *Interface if a structure is not associated with Protocol.
+
+Description:
+The HandleProtocol() function queries Handle to determine if it supports Protocol. If it does, then on return Interface points to a pointer to the corresponding Protocol Interface. Interface can then be passed to any protocol service to identify the context of the request.
+
+Status Codes Returned:
+EFI_SUCCESS The interface information for the specified protocol was returned.
+EFI_UNSUPPORTED The device does not support the specified protocol.
+EFI_INVALID_PARAMETER Handle is NULL..
+EFI_INVALID_PARAMETER Protocol is NULL.
+EFI_INVALID_PARAMETER Interface is NULL.
+```
+
+
+With all this info let's write source code for our new `ImageInfo` app:
+```
+#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));
+ 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;
+}
+```
+
+Some new important things:
+- `gBS` is a global variable which is a shortcut for the `SystemTable->BootServices` a table which contains UEFI services produced by UEFI firmware. These services are only valid in pre-OS environment opposed to the `gRT=SystemTable->RuntimeServices`
+- `EFI_STATUS` variable can be printed with the help of "%r" formatting option (see https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PrintLib.h)
+- `ConvertDevicePathToText` can be used to convert device path to a string.
+It is defined here:
+https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiDevicePathLibDevicePathProtocol/UefiDevicePathLib.c
+With a header file https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/DevicePathLib.h :
+```
+/**
+ Converts a device path to its text representation.
+ @param DevicePath A Pointer to the device to be converted.
+ @param DisplayOnly If DisplayOnly is TRUE, then the shorter text representation
+ of the display node is used, where applicable. If DisplayOnly
+ is FALSE, then the longer text representation of the display node
+ is used.
+ @param AllowShortcuts If AllowShortcuts is TRUE, then the shortcut forms of text
+ representation for a device node can be used, where applicable.
+ @return A pointer to the allocated text representation of the device path or
+ NULL if DeviceNode is NULL or there was insufficient memory.
+**/
+CHAR16 *
+EFIAPI
+ConvertDevicePathToText (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN BOOLEAN DisplayOnly,
+ IN BOOLEAN AllowShortcuts
+ );
+```
+
+Ok, let's try to compile our app.
+```
+. edksetup.sh
+build
+```
+
+Unfortunately build would fail:
+```
+/home/kostr/tiano/edk2/UefiLessonsPkg/ImageInfo/ImageInfo.c:16: undefined reference to `gEfiLoadedImageProtocolGuid'
+/usr/bin/ld: /tmp/ImageInfo.dll.JKxzWu.ltrans0.ltrans.o:/home/kostr/tiano/edk2/UefiLessonsPkg/ImageInfo/ImageInfo.c:24: undefined reference to `gEfiLoadedImageDevicePathProtocolGuid'
+```
+
+To solve this error add `Protocols` section to the `UefiLessonsPkg/ImageInfo/ImageInfo.inf` file:
+```
+[Protocols]
+ gEfiLoadedImageProtocolGuid ## CONSUMES
+ gEfiLoadedImageDevicePathProtocolGuid ## CONSUMES
+```
+
+The [Protocols] section of the EDK II INF file is a list of the global Protocol C Names that are used by the module developer. These C names are used by the parsing utility to lookup the actual GUID value of the PROTOCOL that is located in the EDK II package DEC files, and then emit a data structure to the module's AutoGen.c file (https://edk2-docs.gitbook.io/edk-ii-inf-specification/2_inf_overview/29_-protocols-_section).
+
+
+`## CONSUMES` is used to indicate usage of this protocol. It has no value other than informational. You can encounter values like this for example in the edk2 codebase:
+```
+## CONSUMES
+## PRODUCES
+## ALWAYS_CONSUMES
+## ALWAYS_PRODUCES
+## SOMETIMES_PRODUCES
+## SOMETIMES_PRODUCES
+## NOTIFY
+```
+
+After we add these protocols to the *.inf file, the build will succeed.
+
+In case you wonder, our GUID variables will go to a file `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/ImageInfo/ImageInfo/DEBUG/AutoGen.c` which is automatically generated by the build system:
+```
+// Protocols
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadedImageDevicePathProtocolGuid = { 0xbc62157e, 0x3e33, 0x4fec, {0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf }};
+```
+
+If we try to execute our app under OVMF we would get something like this:
+```
+UEFI Interactive Shell v2.2
+EDK II
+UEFI v2.70 (EDK II, 0x00010000)
+Mapping table
+ FS0: Alias(s):HD0a1:;BLK1:
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
+ BLK0: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ BLK2: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+Press ESC in 5 seconds to skip startup.nsh or any other key to continue.
+Shell> fs0:
+FS0:\> ImageInfo.efi
+Image device: PciRoot(0x0)/Pci(0x1,0x1)/Ata(Primary,Master,0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)/\ImageInfo.efi
+Image file: \ImageInfo.efi
+Image Base: 6885000
+Image Size: 5140
+```
diff --git a/Lessons/Lesson_08/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_08/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..1f05899
--- /dev/null
+++ b/Lessons/Lesson_08/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/Lessons/Lesson_08/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_08/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_08/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/Lessons/Lesson_08/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_08/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..bcf42e3
--- /dev/null
+++ b/Lessons/Lesson_08/UefiLessonsPkg/ImageHandle/ImageHandle.c
@@ -0,0 +1,88 @@
+#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);
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_08/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_08/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_08/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/Lessons/Lesson_08/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lessons/Lesson_08/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lessons/Lesson_08/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/Lessons/Lesson_08/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_08/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lessons/Lesson_08/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/Lessons/Lesson_08/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_08/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_08/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/Lessons/Lesson_08/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_08/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_08/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/Lessons/Lesson_08/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_08/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..ff2edf6
--- /dev/null
+++ b/Lessons/Lesson_08/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,32 @@
+[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
+
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
+ UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ UefiLessonsPkg/ImageHandle/ImageHandle.inf
+ UefiLessonsPkg/ImageInfo/ImageInfo.inf
+
+
diff --git a/Lessons/Lesson_09/Conf/target.txt b/Lessons/Lesson_09/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lessons/Lesson_09/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/Lessons/Lesson_09/README.md b/Lessons/Lesson_09/README.md
new file mode 100644
index 0000000..3b838d8
--- /dev/null
+++ b/Lessons/Lesson_09/README.md
@@ -0,0 +1,148 @@
+The methods that we've used to discover protocols for our image handle were purely educational.
+
+Let's try UEFI API functions to get the same result.
+
+To do this we will need to understand `ProtocolsPerHandle` function:
+```
+EFI_BOOT_SERVICES.ProtocolsPerHandle()
+
+Summary:
+Retrieves the list of protocol interface GUIDs that are installed on a handle in a buffer allocated from pool.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PROTOCOLS_PER_HANDLE) (
+ IN EFI_HANDLE Handle,
+ OUT EFI_GUID ***ProtocolBuffer,
+ OUT UINTN *ProtocolBufferCount
+ );
+
+Parameters:
+Handle The handle from which to retrieve the list of protocol interface GUIDs.
+ProtocolBuffer A pointer to the list of protocol interface GUID pointers that are installed on Handle. This buffer is allocated with a call to the Boot Service EFI_BOOT_SERVICES.AllocatePool(). It is the caller's responsibility to call the Boot Service EFI_BOOT_SERVICES.FreePool() when the caller no longer requires the contents of ProtocolBuffer.
+ProtocolBufferCountA pointer to the number of GUID pointers present in ProtocolBuffer.
+
+Description:
+The ProtocolsPerHandle() function retrieves the list of protocol interface GUIDs that are installed on Handle. The list is returned in ProtocolBuffer, and the number of GUID pointers in ProtocolBuffer is returned in ProtocolBufferCount.
+If Handle is NULL or Handle is NULL, then EFI_INVALID_PARAMETER is returned.
+If ProtocolBuffer is NULL, then EFI_INVALID_PAREMETER is returned.
+If ProtocolBufferCount is NULL, then EFI_INVALID_PARAMETER is returned.
+If there are not enough resources available to allocate ProtocolBuffer, then EFI_OUT_OF_RESOURCES is
+returned.
+
+Status Codes Returned:
+EFI_SUCCESS The list of protocol interface GUIDs installed on Handle was returned in
+ ProtocolBuffer. The number of protocol interface GUIDs was
+ returned in ProtocolBufferCount.
+EFI_INVALID_PARAMETER Handle is NULL.
+EFI_INVALID_PARAMETER ProtocolBuffer is NULL.
+EFI_INVALID_PARAMETER ProtocolBufferCount is NULL.
+EFI_OUT_OF_RESOURCES There is not enough pool memory to store the results.
+```
+
+This description mentions that we need manually deallocate received ProtocolBuffer, so lel's also look to the suggessted `FreePool` function:
+
+```
+EFI_BOOT_SERVICES.FreePool()
+
+Summary:
+Returns pool memory to the system.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FREE_POOL) (
+ IN VOID *Buffer
+);
+
+Parameters:
+Buffer Pointer to the buffer to free.
+
+Description:
+The FreePool() function returns the memory specified by Buffer to the system. On return, the
+memory’s type is EfiConventionalMemory. The Buffer that is freed must have been allocated by
+AllocatePool().
+
+Status Codes Returned:
+EFI_SUCCESS The memory was returned to the system.
+EFI_INVALID_PARAMETER Buffer was invalid
+```
+
+Now when we know how to use API, let's add this code at the end of our `ImageHandle` app:
+```
+Print(L"________\n");
+EFI_GUID **ProtocolGuidArray;
+UINTN ArrayCount;
+EFI_STATUS Status = gBS->ProtocolsPerHandle(ImageHandle,
+ &ProtocolGuidArray,
+ &ArrayCount);
+
+if (Status == EFI_SUCCESS) {
+ for (int i=0; i<ArrayCount; i++) {
+ Print(L"%g\n", ProtocolGuidArray[i]);
+ }
+ FreePool(ProtocolGuidArray);
+}
+
+```
+
+Also for the `FreePool` function we need to add one more include file https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/MemoryAllocationLib.h:
+```
+#include <Library/MemoryAllocationLib.h>
+```
+
+Some may have noticed, that we've used `FreePool`, but not a `gBS->FreePool`. It is legit because `FreePool` is defined in the https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiMemoryAllocationLib/MemoryAllocationLib.c file:
+```
+/**
+ Frees a buffer that was previously allocated with one of the pool allocation functions in the
+ Memory Allocation Library.
+
+ Frees the buffer specified by Buffer. Buffer must have been allocated on a previous call to the
+ pool allocation services of the Memory Allocation Library. If it is not possible to free pool
+ resources, then this function will perform no actions.
+
+ If Buffer was not allocated with a pool allocation function in the Memory Allocation Library,
+ then ASSERT().
+
+ @param Buffer The pointer to the buffer to free.
+
+**/
+VOID
+EFIAPI
+FreePool (
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->FreePool (Buffer);
+ ASSERT_EFI_ERROR (Status);
+}
+```
+This is shortcut is neccessary as `FreePool` have different library implementations:
+```
+MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c
+MdePkg/Library/SmmMemoryAllocationLib/MemoryAllocationLib.c
+MdePkg/Library/UefiMemoryAllocationLib/MemoryAllocationLib.c
+```
+This is the example of LibraryClass that can have several possible instances. In our case we use `UefiMemoryAllocationLib` instance.
+
+UefiLessonsPkg/UefiLessonsPkg.dsc:
+```
+[LibraryClasses]
+ ...
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ ...
+```
+
+Now if we build and execute our app under OVMF this code will give us:
+```
+752F3136-4E16-4FDC-A22A-E5F46812F4CA
+BC62157E-3E33-4FEC-9920-2D3B36D750DF
+5B1B31A1-9562-11D2-8E3F-00A0C969723B
+```
+Which are the same GUIDs we've discovered through hardcore raw walkthrough through the handle/protocol databases.
+
+
+
diff --git a/Lessons/Lesson_09/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_09/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..1f05899
--- /dev/null
+++ b/Lessons/Lesson_09/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/Lessons/Lesson_09/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_09/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_09/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/Lessons/Lesson_09/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_09/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..6117243
--- /dev/null
+++ b/Lessons/Lesson_09/UefiLessonsPkg/ImageHandle/ImageHandle.c
@@ -0,0 +1,102 @@
+#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(ImageHandle,
+ &ProtocolGuidArray,
+ &ArrayCount);
+
+ if (Status == EFI_SUCCESS) {
+ for (int i=0; i<ArrayCount; i++) {
+ Print(L"%g\n", ProtocolGuidArray[i]);
+ }
+ FreePool(ProtocolGuidArray);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_09/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_09/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_09/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/Lessons/Lesson_09/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lessons/Lesson_09/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lessons/Lesson_09/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/Lessons/Lesson_09/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_09/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lessons/Lesson_09/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/Lessons/Lesson_09/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_09/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_09/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/Lessons/Lesson_09/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_09/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_09/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/Lessons/Lesson_09/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_09/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..ff2edf6
--- /dev/null
+++ b/Lessons/Lesson_09/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,32 @@
+[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
+
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
+ UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ UefiLessonsPkg/ImageHandle/ImageHandle.inf
+ UefiLessonsPkg/ImageInfo/ImageInfo.inf
+
+
diff --git a/Lessons/Lesson_10/Conf/target.txt b/Lessons/Lesson_10/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lessons/Lesson_10/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/Lessons/Lesson_10/README.md b/Lessons/Lesson_10/README.md
new file mode 100644
index 0000000..cca1dc5
--- /dev/null
+++ b/Lessons/Lesson_10/README.md
@@ -0,0 +1,156 @@
+
+It is common in UEFI code to use construct like this:
+```
+if (!EFI_ERROR(Status) {
+ ...
+} else {
+ ...
+}
+```
+
+For the internal implementation of EFI_STATUS functionality look at the files:
+MdePkg/Include/Uefi/UefiBaseType.h
+MdePkg/Include/Base.h
+
+```
+#define EFI_ERROR(A) RETURN_ERROR(A)
+
+...
+
+/**
+ Returns TRUE if a specified RETURN_STATUS code is an error code.
+
+ This function returns TRUE if StatusCode has the high bit set. Otherwise, FALSE is returned.
+
+ @param StatusCode The status code value to evaluate.
+
+ @retval TRUE The high bit of StatusCode is set.
+ @retval FALSE The high bit of StatusCode is clear.
+
+**/
+#define RETURN_ERROR(StatusCode) (((INTN)(RETURN_STATUS)(StatusCode)) < 0)
+
+...
+
+//
+// Status codes common to all execution phases
+//
+typedef UINTN RETURN_STATUS;
+```
+
+So the `EFI_ERROR` macro simply test if a passed value is negative which is the same fact for a signed integer that is has high bit set.
+
+Enumration of possible EFI_STATUS values is in the file MdePkg/Include/Uefi/UefiBaseType.h
+```
+///
+/// Enumeration of EFI_STATUS.
+///@{
+#define EFI_SUCCESS RETURN_SUCCESS
+#define EFI_LOAD_ERROR RETURN_LOAD_ERROR
+#define EFI_INVALID_PARAMETER RETURN_INVALID_PARAMETER
+#define EFI_UNSUPPORTED RETURN_UNSUPPORTED
+#define EFI_BAD_BUFFER_SIZE RETURN_BAD_BUFFER_SIZE
+#define EFI_BUFFER_TOO_SMALL RETURN_BUFFER_TOO_SMALL
+#define EFI_NOT_READY RETURN_NOT_READY
+#define EFI_DEVICE_ERROR RETURN_DEVICE_ERROR
+#define EFI_WRITE_PROTECTED RETURN_WRITE_PROTECTED
+#define EFI_OUT_OF_RESOURCES RETURN_OUT_OF_RESOURCES
+#define EFI_VOLUME_CORRUPTED RETURN_VOLUME_CORRUPTED
+#define EFI_VOLUME_FULL RETURN_VOLUME_FULL
+#define EFI_NO_MEDIA RETURN_NO_MEDIA
+#define EFI_MEDIA_CHANGED RETURN_MEDIA_CHANGED
+#define EFI_NOT_FOUND RETURN_NOT_FOUND
+#define EFI_ACCESS_DENIED RETURN_ACCESS_DENIED
+#define EFI_NO_RESPONSE RETURN_NO_RESPONSE
+#define EFI_NO_MAPPING RETURN_NO_MAPPING
+#define EFI_TIMEOUT RETURN_TIMEOUT
+#define EFI_NOT_STARTED RETURN_NOT_STARTED
+#define EFI_ALREADY_STARTED RETURN_ALREADY_STARTED
+#define EFI_ABORTED RETURN_ABORTED
+#define EFI_ICMP_ERROR RETURN_ICMP_ERROR
+#define EFI_TFTP_ERROR RETURN_TFTP_ERROR
+#define EFI_PROTOCOL_ERROR RETURN_PROTOCOL_ERROR
+#define EFI_INCOMPATIBLE_VERSION RETURN_INCOMPATIBLE_VERSION
+#define EFI_SECURITY_VIOLATION RETURN_SECURITY_VIOLATION
+#define EFI_CRC_ERROR RETURN_CRC_ERROR
+#define EFI_END_OF_MEDIA RETURN_END_OF_MEDIA
+#define EFI_END_OF_FILE RETURN_END_OF_FILE
+#define EFI_INVALID_LANGUAGE RETURN_INVALID_LANGUAGE
+#define EFI_COMPROMISED_DATA RETURN_COMPROMISED_DATA
+#define EFI_HTTP_ERROR RETURN_HTTP_ERROR
+
+#define EFI_WARN_UNKNOWN_GLYPH RETURN_WARN_UNKNOWN_GLYPH
+#define EFI_WARN_DELETE_FAILURE RETURN_WARN_DELETE_FAILURE
+#define EFI_WARN_WRITE_FAILURE RETURN_WARN_WRITE_FAILURE
+#define EFI_WARN_BUFFER_TOO_SMALL RETURN_WARN_BUFFER_TOO_SMALL
+#define EFI_WARN_STALE_DATA RETURN_WARN_STALE_DATA
+#define EFI_WARN_FILE_SYSTEM RETURN_WARN_FILE_SYSTEM
+```
+
+If you want to see how they encoded look at the MdePkg\Include\Base.h :
+```
+///
+/// The operation completed successfully.
+///
+#define RETURN_SUCCESS 0
+
+///
+/// The image failed to load.
+///
+#define RETURN_LOAD_ERROR ENCODE_ERROR (1)
+
+///
+/// The parameter was incorrect.
+///
+#define RETURN_INVALID_PARAMETER ENCODE_ERROR (2)
+
+<...>
+
+/**
+ Produces a RETURN_STATUS code with the highest bit set.
+
+ @param StatusCode The status code value to convert into a warning code.
+ StatusCode must be in the range 0x00000000..0x7FFFFFFF.
+
+ @return The value specified by StatusCode with the highest bit set.
+
+**/
+#define ENCODE_ERROR(StatusCode) ((RETURN_STATUS)(MAX_BIT | (StatusCode)))
+
+/**
+ Produces a RETURN_STATUS code with the highest bit clear.
+
+ @param StatusCode The status code value to convert into a warning code.
+ StatusCode must be in the range 0x00000000..0x7FFFFFFF.
+
+ @return The value specified by StatusCode with the highest bit clear.
+
+**/
+#define ENCODE_WARNING(StatusCode) ((RETURN_STATUS)(StatusCode))
+```
+
+Let's use `EFI_ERROR` macro in our code and test error printing with the help of `%r` Print formatting option.
+
+We could test error display with a passing `NULL` pointer instead of ImageHandle:
+```
+Print(L"________\n");
+EFI_GUID **ProtocolGuidArray;
+UINTN ArrayCount;
+EFI_STATUS Status = gBS->ProtocolsPerHandle(NULL,
+ &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);
+}
+```
+
+This would give us this message in OVMF:
+```
+ProtocolsPerHandle error: Invalid Parameter
+```
diff --git a/Lessons/Lesson_10/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_10/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..1f05899
--- /dev/null
+++ b/Lessons/Lesson_10/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/Lessons/Lesson_10/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_10/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_10/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/Lessons/Lesson_10/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_10/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..32e9c43
--- /dev/null
+++ b/Lessons/Lesson_10/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/Lessons/Lesson_10/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_10/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_10/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/Lessons/Lesson_10/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lessons/Lesson_10/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lessons/Lesson_10/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/Lessons/Lesson_10/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_10/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lessons/Lesson_10/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/Lessons/Lesson_10/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_10/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_10/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/Lessons/Lesson_10/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_10/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_10/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/Lessons/Lesson_10/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_10/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..ff2edf6
--- /dev/null
+++ b/Lessons/Lesson_10/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,32 @@
+[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
+
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
+ UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ UefiLessonsPkg/ImageHandle/ImageHandle.inf
+ UefiLessonsPkg/ImageInfo/ImageInfo.inf
+
+
diff --git a/Lessons/Lesson_11/README.md b/Lessons/Lesson_11/README.md
new file mode 100644
index 0000000..7ae189f
--- /dev/null
+++ b/Lessons/Lesson_11/README.md
@@ -0,0 +1,678 @@
+One of the main BIOS/UEFI task is to present OS memory map. Operating system needs to know how much RAM is available in the systems and what regions of it OS can use and what regions it can't use.
+
+
+For this purpose UEFI specification defines `EFI_BOOT_SERVICES.GetMemoryMap()` function:
+```
+EFI_BOOT_SERVICES.GetMemoryMap()
+
+Summary:
+Returns the current memory map.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_GET_MEMORY_MAP) (
+ IN OUT UINTN *MemoryMapSize,
+ IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ OUT UINTN *MapKey,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *DescriptorVersion
+ );
+
+Parameters:
+MemoryMapSize A pointer to the size, in bytes, of the MemoryMap buffer. On input,
+ this is the size of the buffer allocated by the caller. On output, it is
+ the size of the buffer returned by the firmware if the buffer was
+ large enough, or the size of the buffer needed to contain the map if
+ the buffer was too small.
+MemoryMap A pointer to the buffer in which firmware places the current memory
+ map. The map is an array of EFI_MEMORY_DESCRIPTORs.
+MapKey A pointer to the location in which firmware returns the key for the
+ current memory map.
+DescriptorSize A pointer to the location in which firmware returns the size, in bytes,
+ of an individual EFI_MEMORY_DESCRIPTOR.
+DescriptorVersion A pointer to the location in which firmware returns the version
+ number associated with the EFI_MEMORY_DESCRIPTOR.
+
+
+Status Codes Returned:
+EFI_SUCCESS The memory map was returned in the MemoryMap buffer.
+EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current buffer size needed to
+ hold the memory map is returned in MemoryMapSize.
+EFI_INVALID_PARAMETER MemoryMapSize is NULL.
+EFI_INVALID_PARAMETER The MemoryMap buffer is not too small and MemoryMap is NULL.
+```
+
+```
+//*******************************************************
+//EFI_MEMORY_DESCRIPTOR
+//*******************************************************
+typedef struct {
+ UINT32 Type;
+ EFI_PHYSICAL_ADDRESS PhysicalStart;
+ EFI_VIRTUAL_ADDRESS VirtualStart;
+ UINT64 NumberOfPages;
+ UINT64 Attribute;
+} EFI_MEMORY_DESCRIPTOR;
+
+Type Type of the memory region.
+ Type EFI_MEMORY_TYPE is defined in the AllocatePages()
+ function description.
+PhysicalStart Physical address of the first byte in the memory region.
+ PhysicalStart must be aligned on a 4 KiB boundary, and must
+ not be above 0xfffffffffffff000. Type EFI_PHYSICAL_ADDRESS is
+ defined in the AllocatePages() function description.
+VirtualStart Virtual address of the first byte in the memory region.
+ VirtualStart must be aligned on a 4 KiB boundary, and must not
+ be above 0xfffffffffffff000.
+NumberOfPages Number of 4 KiB pages in the memory region.
+ NumberOfPages must not be 0, and must not be any value that
+ would represent a memory page with a start address, either physical
+ or virtual, above 0xfffffffffffff000
+Attribute Attributes of the memory region that describe the bit mask of
+ capabilities for that memory region, and not necessarily the current
+ settings for that memory region.
+```
+
+EFI_BOOT_SERVICES.AllocatePages() allocates 4KB pages according to spec
+
+
+
+Code for our app:
+```
+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;
+ 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;
+ int i = 0;
+ while ((UINT8 *)desc < (UINT8 *)MemoryMap + MemoryMapSize) {
+ UINTN PAGE_SIZE = 4096;
+ UINTN mapping_size =(UINTN) desc->NumberOfPages * PAGE_SIZE;
+
+
+ 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", desc->PhysicalStart, desc->PhysicalStart + mapping_size - 1);
+
+ desc = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)desc + DescriptorSize);
+ }
+
+ 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;
+}
+```
+
+The first call to `GetMemoryMap` function should fail with `EFI_BUFFER_TOO_SMALL` as `MemoryMapSize=0` is obviously not enough to store all the memory descriptors. But this first call will fill the same `MemoryMapSize` with an actual size that we need to allocate.
+
+We allocate the necessary size with the `gBS->AllocatePool` call
+```
+EFI_BOOT_SERVICES.AllocatePool()
+
+Summary:
+Allocates pool memory
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ALLOCATE_POOL) (
+ IN EFI_MEMORY_TYPE PoolType,
+ IN UINTN Size,
+ OUT VOID **Buffer
+ );
+
+Parameters:
+PoolType The type of pool to allocate. Type EFI_MEMORY_TYPE is defined in
+ the EFI_BOOT_SERVICES.AllocatePages() function description.
+Size The number of bytes to allocate from the pool.
+Buffer A pointer to a pointer to the allocated buffer if the call succeeds;
+ undefined otherwise.
+
+Description:
+The AllocatePool() function allocates a memory region of Size bytes from memory of type PoolType
+and returns the address of the allocated memory in the location referenced by Buffer.
+
+Status Codes Returned:
+EFI_SUCCESS The requested number of bytes was allocated.
+EFI_OUT_OF_RESOURCES The pool requested could not be allocated.
+EFI_INVALID_PARAMETER PoolType is in the range EfiMaxMemoryType..0x6FFFFFFF.
+EFI_INVALID_PARAMETER PoolType is EfiPersistentMemory.
+EFI_INVALID_PARAMETER Buffer is NULL
+```
+
+As a `EFI_MEMORY_TYPE` we pass `EfiBootServicesData` which signifies the data that is connected to the BootServices and would be freed after OS starts execution.
+Other possible values for `EFI_MEMORY_TYPE` can be found in a spec or here https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Uefi/UefiMultiPhase.h
+
+
+If the memory was successfully allocated we need to dealocate it with the `gBS->FreePool` call in the end:
+```
+EFI_BOOT_SERVICES.FreePool()
+
+Summary:
+Returns pool memory to the system.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_FREE_POOL) (
+IN VOID *Buffer
+);
+
+Parameters:
+Buffer Pointer to the buffer to free.
+
+Description:
+The FreePool() function returns the memory specified by Buffer to the system. The Buffer that is freed must have been allocated by AllocatePool().
+
+Status Codes Returned:
+EFI_SUCCESS The memory was returned to the system.
+EFI_INVALID_PARAMETER Buffer was invalid.
+```
+
+If the second call to the `GetMemoryMap` function was successful we would get array of `EFI_MEMORY_DESCRIPTOR` objects starting at `MemoryMap` address.
+
+We walk through that array and print information in each descriptor.
+
+To convert memory type value to a string we create `memory_type_to_str` helper function:
+```
+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_type_to_str(UINT32 type)
+{
+ if (type > sizeof(memory_types)/sizeof(CHAR16 *))
+ return L"Unknown";
+
+ return memory_types[type];
+}
+```
+
+To convert memory attrributes to a string we create `memory_attrs_to_str` helper function.
+I'm not proud of this macro solution, as macros generally considered error prone design, but this gives us an easy way to concatenate all possible attriburtes which are defined as `EFI_MEMORY_XXX` in a edk2 codebase.
+```
+#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;
+}
+```
+
+In the last snippet we've used some edk2 string manipulation functions:
+- StrCpyS:
+https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseLib/SafeString.c
+(According to https://edk2-docs.gitbook.io/edk-ii-secure-coding-guide/secure_coding_guidelines_general StrCpy is a deprecated API and should be replaced with StrCpyS)
+- StrLen: https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseLib/String.c
+This functions are similar to their analogs from the standard C library.
+
+For these string functions we need to add one more include:
+```
+#include <Library/BaseMemoryLib.h>
+```
+
+
+If we build and execute our app under OVMF it will give us something like this:
+```
+FS0:\> MemoryInfo.efi
+[#00] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000000000000-0000000000000FFF
+[#01] Type: EfiConventionalMemory Attr: UC WC WT WB
+ Phys: 0000000000001000-000000000009FFFF
+[#02] Type: EfiConventionalMemory Attr: UC WC WT WB
+ Phys: 0000000000100000-00000000007FFFFF
+[#03] Type: EfiACPIMemoryNVS Attr: UC WC WT WB
+ Phys: 0000000000800000-0000000000807FFF
+[#04] Type: EfiConventionalMemory Attr: UC WC WT WB
+ Phys: 0000000000808000-000000000080FFFF
+[#05] Type: EfiACPIMemoryNVS Attr: UC WC WT WB
+ Phys: 0000000000810000-00000000008FFFFF
+[#06] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000000900000-00000000014FFFFF
+[#07] Type: EfiConventionalMemory Attr: UC WC WT WB
+ Phys: 0000000001500000-0000000003F35FFF
+[#08] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000003F36000-0000000003F55FFF
+[#09] Type: EfiConventionalMemory Attr: UC WC WT WB
+ Phys: 0000000003F56000-000000000673AFFF
+[#10] Type: EfiLoaderCode Attr: UC WC WT WB
+ Phys: 000000000673B000-000000000680BFFF
+[#11] Type: EfiConventionalMemory Attr: UC WC WT WB
+ Phys: 000000000680C000-0000000006855FFF
+[#12] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006856000-0000000006873FFF
+[#13] Type: EfiConventionalMemory Attr: UC WC WT WB
+ Phys: 0000000006874000-000000000688AFFF
+[#14] Type: EfiLoaderCode Attr: UC WC WT WB
+ Phys: 000000000688B000-000000000688DFFF
+[#15] Type: EfiConventionalMemory Attr: UC WC WT WB
+ Phys: 000000000688E000-000000000688EFFF
+[#16] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 000000000688F000-0000000006EAAFFF
+[#17] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006EAB000-0000000006ECCFFF
+[#18] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006ECD000-0000000006ED2FFF
+[#19] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006ED3000-0000000006ED9FFF
+[#20] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006EDA000-0000000006EDBFFF
+[#21] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006EDC000-0000000006EF3FFF
+[#22] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006EF4000-0000000006EF5FFF
+[#23] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006EF6000-0000000006EFDFFF
+[#24] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006EFE000-0000000006EFEFFF
+[#25] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006EFF000-0000000006F0CFFF
+[#26] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006F0D000-0000000006F0DFFF
+[#27] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006F0E000-0000000006F10FFF
+[#28] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006F11000-0000000006F17FFF
+[#29] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006F18000-0000000006F26FFF
+[#30] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006F27000-0000000006F28FFF
+[#31] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006F29000-0000000006F3CFFF
+[#32] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006F3D000-0000000006F43FFF
+[#33] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006F44000-0000000006F66FFF
+[#34] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006F67000-0000000006F69FFF
+[#35] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006F6A000-0000000006F6EFFF
+[#36] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006F6F000-0000000006F70FFF
+[#37] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006F71000-0000000006F80FFF
+[#38] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006F81000-0000000006F82FFF
+[#39] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006F83000-0000000006F85FFF
+[#40] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006F86000-0000000006F87FFF
+[#41] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006F88000-0000000006F93FFF
+[#42] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006F94000-0000000006F95FFF
+[#43] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006F96000-0000000006FA0FFF
+[#44] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006FA1000-0000000006FA2FFF
+[#45] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006FA3000-0000000006FA7FFF
+[#46] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006FA8000-0000000006FA9FFF
+[#47] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006FAA000-0000000006FB0FFF
+[#48] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006FB1000-0000000006FB6FFF
+[#49] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006FB7000-0000000006FBAFFF
+[#50] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006FBB000-0000000006FBBFFF
+[#51] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006FBC000-0000000006FE8FFF
+[#52] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000006FE9000-0000000006FEAFFF
+[#53] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000006FEB000-0000000006FFFFFF
+[#54] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000007000000-0000000007200FFF
+[#55] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007201000-0000000007201FFF
+[#56] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000007202000-0000000007205FFF
+[#57] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007206000-0000000007206FFF
+[#58] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000007207000-0000000007207FFF
+[#59] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007208000-000000000720EFFF
+[#60] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 000000000720F000-0000000007215FFF
+[#61] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007216000-0000000007219FFF
+[#62] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 000000000721A000-000000000721EFFF
+[#63] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 000000000721F000-000000000722CFFF
+[#64] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 000000000722D000-0000000007230FFF
+[#65] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007231000-0000000007242FFF
+[#66] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000007243000-0000000007246FFF
+[#67] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007247000-0000000007257FFF
+[#68] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000007258000-0000000007258FFF
+[#69] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007259000-000000000725CFFF
+[#70] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 000000000725D000-0000000007260FFF
+[#71] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007261000-0000000007263FFF
+[#72] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000007264000-0000000007266FFF
+[#73] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007267000-000000000727EFFF
+[#74] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 000000000727F000-000000000727FFFF
+[#75] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007280000-0000000007283FFF
+[#76] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000007284000-0000000007287FFF
+[#77] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007288000-0000000007288FFF
+[#78] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000007289000-0000000007289FFF
+[#79] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 000000000728A000-000000000728FFFF
+[#80] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000007290000-0000000007291FFF
+[#81] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007292000-0000000007292FFF
+[#82] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000007293000-0000000007293FFF
+[#83] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007294000-0000000007296FFF
+[#84] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000007297000-0000000007298FFF
+[#85] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007299000-000000000729BFFF
+[#86] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 000000000729C000-000000000729DFFF
+[#87] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 000000000729E000-000000000729EFFF
+[#88] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 000000000729F000-00000000072A8FFF
+[#89] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 00000000072A9000-00000000072B4FFF
+[#90] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 00000000072B5000-00000000072B6FFF
+[#91] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 00000000072B7000-00000000072B7FFF
+[#92] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 00000000072B8000-00000000072BAFFF
+[#93] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 00000000072BB000-00000000072C0FFF
+[#94] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 00000000072C1000-00000000076C0FFF
+[#95] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 00000000076C1000-00000000076C6FFF
+[#96] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 00000000076C7000-00000000076C8FFF
+[#97] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 00000000076C9000-00000000076D3FFF
+[#98] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 00000000076D4000-00000000076D6FFF
+[#99] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 00000000076D7000-00000000076D9FFF
+[#100] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 00000000076DA000-00000000078EEFFF
+[#101] Type: EfiRuntimeServicesData Attr: UC WC WT WB RUNTIME
+ Phys: 00000000078EF000-00000000079EEFFF
+[#102] Type: EfiRuntimeServicesCode Attr: UC WC WT WB RUNTIME
+ Phys: 00000000079EF000-0000000007AEEFFF
+[#103] Type: EfiReservedMemoryType Attr: UC WC WT WB
+ Phys: 0000000007AEF000-0000000007B6EFFF
+[#104] Type: EfiACPIReclaimMemory Attr: UC WC WT WB
+ Phys: 0000000007B6F000-0000000007B7EFFF
+[#105] Type: EfiACPIMemoryNVS Attr: UC WC WT WB
+ Phys: 0000000007B7F000-0000000007BFEFFF
+[#106] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000007BFF000-0000000007DFFFFF
+[#107] Type: EfiConventionalMemory Attr: UC WC WT WB
+ Phys: 0000000007E00000-0000000007E9CFFF
+[#108] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000007E9D000-0000000007EBCFFF
+[#109] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007EBD000-0000000007ED6FFF
+[#110] Type: EfiBootServicesData Attr: UC WC WT WB
+ Phys: 0000000007ED7000-0000000007EDFFFF
+[#111] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000007EE0000-0000000007EF3FFF
+[#112] Type: EfiRuntimeServicesData Attr: UC WC WT WB RUNTIME
+ Phys: 0000000007EF4000-0000000007F77FFF
+[#113] Type: EfiACPIMemoryNVS Attr: UC WC WT WB
+ Phys: 0000000007F78000-0000000007FFFFFF
+[#114] Type: EfiMemoryMappedIO Attr: UC RUNTIME
+ Phys: 00000000FFC00000-00000000FFFFFFFF
+```
+
+
+You could verify our result if you execute `memmap` shell command:
+```
+Shell> memmap
+Type Start End # Pages Attributes
+BS_Code 0000000000000000-0000000000000FFF 0000000000000001 000000000000000F
+Available 0000000000001000-000000000009FFFF 000000000000009F 000000000000000F
+Available 0000000000100000-00000000007FFFFF 0000000000000700 000000000000000F
+ACPI_NVS 0000000000800000-0000000000807FFF 0000000000000008 000000000000000F
+Available 0000000000808000-000000000080FFFF 0000000000000008 000000000000000F
+ACPI_NVS 0000000000810000-00000000008FFFFF 00000000000000F0 000000000000000F
+BS_Data 0000000000900000-00000000014FFFFF 0000000000000C00 000000000000000F
+Available 0000000001500000-0000000003F35FFF 0000000000002A36 000000000000000F
+BS_Data 0000000003F36000-0000000003F55FFF 0000000000000020 000000000000000F
+Available 0000000003F56000-0000000006509FFF 00000000000025B4 000000000000000F
+LoaderCode 000000000650A000-00000000065DAFFF 00000000000000D1 000000000000000F
+Available 00000000065DB000-0000000006624FFF 000000000000004A 000000000000000F
+BS_Data 0000000006625000-0000000006642FFF 000000000000001E 000000000000000F
+Available 0000000006643000-000000000665AFFF 0000000000000018 000000000000000F
+BS_Data 000000000665B000-000000000666DFFF 0000000000000013 000000000000000F
+Available 000000000666E000-000000000666FFFF 0000000000000002 000000000000000F
+BS_Data 0000000006670000-0000000006D68FFF 00000000000006F9 000000000000000F
+BS_Code 0000000006D69000-0000000006E1FFFF 00000000000000B7 000000000000000F
+BS_Data 0000000006E20000-0000000006EAAFFF 000000000000008B 000000000000000F
+BS_Code 0000000006EAB000-0000000006ECCFFF 0000000000000022 000000000000000F
+BS_Data 0000000006ECD000-0000000006ED2FFF 0000000000000006 000000000000000F
+BS_Code 0000000006ED3000-0000000006ED9FFF 0000000000000007 000000000000000F
+BS_Data 0000000006EDA000-0000000006EDBFFF 0000000000000002 000000000000000F
+BS_Code 0000000006EDC000-0000000006EF3FFF 0000000000000018 000000000000000F
+BS_Data 0000000006EF4000-0000000006EF5FFF 0000000000000002 000000000000000F
+BS_Code 0000000006EF6000-0000000006EFDFFF 0000000000000008 000000000000000F
+BS_Data 0000000006EFE000-0000000006EFEFFF 0000000000000001 000000000000000F
+BS_Code 0000000006EFF000-0000000006F0CFFF 000000000000000E 000000000000000F
+BS_Data 0000000006F0D000-0000000006F0DFFF 0000000000000001 000000000000000F
+BS_Code 0000000006F0E000-0000000006F10FFF 0000000000000003 000000000000000F
+BS_Data 0000000006F11000-0000000006F17FFF 0000000000000007 000000000000000F
+BS_Code 0000000006F18000-0000000006F26FFF 000000000000000F 000000000000000F
+BS_Data 0000000006F27000-0000000006F28FFF 0000000000000002 000000000000000F
+BS_Code 0000000006F29000-0000000006F3CFFF 0000000000000014 000000000000000F
+BS_Data 0000000006F3D000-0000000006F43FFF 0000000000000007 000000000000000F
+BS_Code 0000000006F44000-0000000006F66FFF 0000000000000023 000000000000000F
+BS_Data 0000000006F67000-0000000006F69FFF 0000000000000003 000000000000000F
+BS_Code 0000000006F6A000-0000000006F6EFFF 0000000000000005 000000000000000F
+BS_Data 0000000006F6F000-0000000006F70FFF 0000000000000002 000000000000000F
+BS_Code 0000000006F71000-0000000006F80FFF 0000000000000010 000000000000000F
+BS_Data 0000000006F81000-0000000006F82FFF 0000000000000002 000000000000000F
+BS_Code 0000000006F83000-0000000006F85FFF 0000000000000003 000000000000000F
+BS_Data 0000000006F86000-0000000006F87FFF 0000000000000002 000000000000000F
+BS_Code 0000000006F88000-0000000006F93FFF 000000000000000C 000000000000000F
+BS_Data 0000000006F94000-0000000006F95FFF 0000000000000002 000000000000000F
+BS_Code 0000000006F96000-0000000006FA0FFF 000000000000000B 000000000000000F
+BS_Data 0000000006FA1000-0000000006FA2FFF 0000000000000002 000000000000000F
+BS_Code 0000000006FA3000-0000000006FA7FFF 0000000000000005 000000000000000F
+BS_Data 0000000006FA8000-0000000006FA9FFF 0000000000000002 000000000000000F
+BS_Code 0000000006FAA000-0000000006FB0FFF 0000000000000007 000000000000000F
+BS_Data 0000000006FB1000-0000000006FB6FFF 0000000000000006 000000000000000F
+BS_Code 0000000006FB7000-0000000006FBAFFF 0000000000000004 000000000000000F
+BS_Data 0000000006FBB000-0000000006FBBFFF 0000000000000001 000000000000000F
+BS_Code 0000000006FBC000-0000000006FE8FFF 000000000000002D 000000000000000F
+BS_Data 0000000006FE9000-0000000006FEAFFF 0000000000000002 000000000000000F
+BS_Code 0000000006FEB000-0000000006FFFFFF 0000000000000015 000000000000000F
+BS_Data 0000000007000000-0000000007200FFF 0000000000000201 000000000000000F
+BS_Code 0000000007201000-0000000007201FFF 0000000000000001 000000000000000F
+BS_Data 0000000007202000-0000000007205FFF 0000000000000004 000000000000000F
+BS_Code 0000000007206000-0000000007206FFF 0000000000000001 000000000000000F
+BS_Data 0000000007207000-0000000007207FFF 0000000000000001 000000000000000F
+BS_Code 0000000007208000-000000000720EFFF 0000000000000007 000000000000000F
+BS_Data 000000000720F000-0000000007215FFF 0000000000000007 000000000000000F
+BS_Code 0000000007216000-0000000007219FFF 0000000000000004 000000000000000F
+BS_Data 000000000721A000-000000000721EFFF 0000000000000005 000000000000000F
+BS_Code 000000000721F000-000000000722CFFF 000000000000000E 000000000000000F
+BS_Data 000000000722D000-0000000007230FFF 0000000000000004 000000000000000F
+BS_Code 0000000007231000-0000000007242FFF 0000000000000012 000000000000000F
+BS_Data 0000000007243000-0000000007246FFF 0000000000000004 000000000000000F
+BS_Code 0000000007247000-0000000007257FFF 0000000000000011 000000000000000F
+BS_Data 0000000007258000-0000000007258FFF 0000000000000001 000000000000000F
+BS_Code 0000000007259000-000000000725CFFF 0000000000000004 000000000000000F
+BS_Data 000000000725D000-0000000007260FFF 0000000000000004 000000000000000F
+BS_Code 0000000007261000-0000000007263FFF 0000000000000003 000000000000000F
+BS_Data 0000000007264000-0000000007266FFF 0000000000000003 000000000000000F
+BS_Code 0000000007267000-000000000727EFFF 0000000000000018 000000000000000F
+BS_Data 000000000727F000-000000000727FFFF 0000000000000001 000000000000000F
+BS_Code 0000000007280000-0000000007283FFF 0000000000000004 000000000000000F
+BS_Data 0000000007284000-0000000007287FFF 0000000000000004 000000000000000F
+BS_Code 0000000007288000-0000000007288FFF 0000000000000001 000000000000000F
+BS_Data 0000000007289000-0000000007289FFF 0000000000000001 000000000000000F
+BS_Code 000000000728A000-000000000728FFFF 0000000000000006 000000000000000F
+BS_Data 0000000007290000-0000000007291FFF 0000000000000002 000000000000000F
+BS_Code 0000000007292000-0000000007292FFF 0000000000000001 000000000000000F
+BS_Data 0000000007293000-0000000007293FFF 0000000000000001 000000000000000F
+BS_Code 0000000007294000-0000000007296FFF 0000000000000003 000000000000000F
+BS_Data 0000000007297000-0000000007298FFF 0000000000000002 000000000000000F
+BS_Code 0000000007299000-000000000729BFFF 0000000000000003 000000000000000F
+BS_Data 000000000729C000-000000000729DFFF 0000000000000002 000000000000000F
+BS_Code 000000000729E000-000000000729EFFF 0000000000000001 000000000000000F
+BS_Data 000000000729F000-00000000072A8FFF 000000000000000A 000000000000000F
+BS_Code 00000000072A9000-00000000072B4FFF 000000000000000C 000000000000000F
+BS_Data 00000000072B5000-00000000072B6FFF 0000000000000002 000000000000000F
+BS_Code 00000000072B7000-00000000072B7FFF 0000000000000001 000000000000000F
+BS_Data 00000000072B8000-00000000072BAFFF 0000000000000003 000000000000000F
+BS_Code 00000000072BB000-00000000072C0FFF 0000000000000006 000000000000000F
+BS_Data 00000000072C1000-00000000076C0FFF 0000000000000400 000000000000000F
+BS_Code 00000000076C1000-00000000076C6FFF 0000000000000006 000000000000000F
+BS_Data 00000000076C7000-00000000076C8FFF 0000000000000002 000000000000000F
+BS_Code 00000000076C9000-00000000076D3FFF 000000000000000B 000000000000000F
+BS_Data 00000000076D4000-00000000076D6FFF 0000000000000003 000000000000000F
+BS_Code 00000000076D7000-00000000076D9FFF 0000000000000003 000000000000000F
+BS_Data 00000000076DA000-00000000078EEFFF 0000000000000215 000000000000000F
+RT_Data 00000000078EF000-00000000079EEFFF 0000000000000100 800000000000000F
+RT_Code 00000000079EF000-0000000007AEEFFF 0000000000000100 800000000000000F
+Reserved 0000000007AEF000-0000000007B6EFFF 0000000000000080 000000000000000F
+ACPI_Recl 0000000007B6F000-0000000007B7EFFF 0000000000000010 000000000000000F
+ACPI_NVS 0000000007B7F000-0000000007BFEFFF 0000000000000080 000000000000000F
+BS_Data 0000000007BFF000-0000000007DFFFFF 0000000000000201 000000000000000F
+Available 0000000007E00000-0000000007E9CFFF 000000000000009D 000000000000000F
+BS_Data 0000000007E9D000-0000000007EBCFFF 0000000000000020 000000000000000F
+BS_Code 0000000007EBD000-0000000007ED6FFF 000000000000001A 000000000000000F
+BS_Data 0000000007ED7000-0000000007EDFFFF 0000000000000009 000000000000000F
+BS_Code 0000000007EE0000-0000000007EF3FFF 0000000000000014 000000000000000F
+RT_Data 0000000007EF4000-0000000007F77FFF 0000000000000084 800000000000000F
+ACPI_NVS 0000000007F78000-0000000007FFFFFF 0000000000000088 000000000000000F
+MMIO 00000000FFC00000-00000000FFFFFFFF 0000000000000400 8000000000000001
+
+ Reserved : 128 Pages (524,288 Bytes)
+ LoaderCode: 209 Pages (856,064 Bytes)
+ LoaderData: 0 Pages (0 Bytes)
+ BS_Code : 670 Pages (2,744,320 Bytes)
+ BS_Data : 7,819 Pages (32,026,624 Bytes)
+ RT_Code : 256 Pages (1,048,576 Bytes)
+ RT_Data : 388 Pages (1,589,248 Bytes)
+ ACPI_Recl : 16 Pages (65,536 Bytes)
+ ACPI_NVS : 512 Pages (2,097,152 Bytes)
+ MMIO : 1,024 Pages (4,194,304 Bytes)
+ MMIO_Port : 0 Pages (0 Bytes)
+ PalCode : 0 Pages (0 Bytes)
+ Available : 22,674 Pages (92,872,704 Bytes)
+ Persistent: 0 Pages (0 Bytes)
+ --------------
+Total Memory: 127 MB (133,300,224 Bytes)
+```
+
+As you can see, the regions are the same that we've got with our program.
diff --git a/Lessons/Lesson_11/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_11/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..1f05899
--- /dev/null
+++ b/Lessons/Lesson_11/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/Lessons/Lesson_11/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_11/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_11/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/Lessons/Lesson_11/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_11/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..32e9c43
--- /dev/null
+++ b/Lessons/Lesson_11/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/Lessons/Lesson_11/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_11/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_11/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/Lessons/Lesson_11/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lessons/Lesson_11/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lessons/Lesson_11/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/Lessons/Lesson_11/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_11/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lessons/Lesson_11/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/Lessons/Lesson_11/UefiLessonsPkg/MemoryInfo/MemoryInfo.c b/Lessons/Lesson_11/UefiLessonsPkg/MemoryInfo/MemoryInfo.c
new file mode 100644
index 0000000..a8fcb83
--- /dev/null
+++ b/Lessons/Lesson_11/UefiLessonsPkg/MemoryInfo/MemoryInfo.c
@@ -0,0 +1,134 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+// for SetMem
+#include <Library/BaseMemoryLib.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_type_to_str(UINT32 type)
+{
+ if (type > sizeof(memory_types)/sizeof(CHAR16 *))
+ return L"Unknown";
+
+ return memory_types[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;
+ 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;
+ int i = 0;
+ while ((UINT8 *)desc < (UINT8 *)MemoryMap + MemoryMapSize) {
+ UINTN PAGE_SIZE = 4096;
+ UINTN mapping_size =(UINTN) desc->NumberOfPages * PAGE_SIZE;
+
+
+ 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", desc->PhysicalStart, desc->PhysicalStart + mapping_size - 1);
+
+ desc = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)desc + DescriptorSize);
+ }
+
+ 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/Lessons/Lesson_11/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf b/Lessons/Lesson_11/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
new file mode 100644
index 0000000..d18c087
--- /dev/null
+++ b/Lessons/Lesson_11/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
@@ -0,0 +1,18 @@
+[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
+
diff --git a/Lessons/Lesson_11/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_11/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_11/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/Lessons/Lesson_11/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_11/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_11/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/Lessons/Lesson_11/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_11/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..09f38ea
--- /dev/null
+++ b/Lessons/Lesson_11/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,33 @@
+[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
+
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
+ UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ UefiLessonsPkg/ImageHandle/ImageHandle.inf
+ UefiLessonsPkg/ImageInfo/ImageInfo.inf
+ UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
+
+
diff --git a/Lessons/Lesson_12/Conf/target.txt b/Lessons/Lesson_12/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lessons/Lesson_12/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/Lessons/Lesson_12/README.md b/Lessons/Lesson_12/README.md
new file mode 100644
index 0000000..727d300
--- /dev/null
+++ b/Lessons/Lesson_12/README.md
@@ -0,0 +1,247 @@
+Let's investigate final protocol that was attached to our `ImageHandle` - `EFI_SHELL_PARAMETERS_PROTOCOL`
+
+https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/ShellParameters.h
+```
+typedef struct _EFI_SHELL_PARAMETERS_PROTOCOL {
+ ///
+ /// Points to an Argc-element array of points to NULL-terminated strings containing
+ /// the command-line parameters. The first entry in the array is always the full file
+ /// path of the executable. Any quotation marks that were used to preserve
+ /// whitespace have been removed.
+ ///
+ CHAR16 **Argv;
+
+ ///
+ /// The number of elements in the Argv array.
+ ///
+ UINTN Argc;
+
+ ///
+ /// The file handle for the standard input for this executable. This may be different
+ /// from the ConInHandle in EFI_SYSTEM_TABLE.
+ ///
+ SHELL_FILE_HANDLE StdIn;
+
+ ///
+ /// The file handle for the standard output for this executable. This may be different
+ /// from the ConOutHandle in EFI_SYSTEM_TABLE.
+ ///
+ SHELL_FILE_HANDLE StdOut;
+
+ ///
+ /// The file handle for the standard error output for this executable. This may be
+ /// different from the StdErrHandle in EFI_SYSTEM_TABLE.
+ ///
+ SHELL_FILE_HANDLE StdErr;
+} EFI_SHELL_PARAMETERS_PROTOCOL;
+```
+
+As we see, we can access command line arguments that was passed to our program through this protocol.
+Let's use it in our `MemoryInfo` program.
+
+In the last lesson we've printed our EFI memory map. It had >100 entries.
+When you boot Linux kernel, you can see some info about the current memory map, but this table is much shorter. It happens because of two facts:
+- Kernel differentiate EFI memory types much less granular. Instead of `EfiReservedMemoryType`/`EfiLoaderCode`/`EfiLoaderData`/...` it simply has only 4 types: `usable`/`ACPI NVS`/`ACPI data`/`reserved`
+- Kernel glues adjacent regions together
+
+
+I've generated kernel image for EFI x86-64 with buildroot:
+```
+cd ~
+git clone https://github.com/buildroot/buildroot.git
+cd buildroot
+make pc_x86_64_efi_defconfig
+make
+```
+
+If we try to boot this kernel with:
+```
+qemu-system-x86_64 -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd
+ -drive format=raw,file=fat:rw:~/UEFI_disk
+ -nographic
+ -kernel ~/buildroot/output/images/bzImage
+ -append "console=ttyS0"
+```
+
+In kernel boot log we can see:
+```
+BIOS-provided physical RAM map:
+BIOS-e820: [mem 0x0000000000000000-0x000000000009ffff] usable
+BIOS-e820: [mem 0x0000000000100000-0x00000000007fffff] usable
+BIOS-e820: [mem 0x0000000000800000-0x0000000000807fff] ACPI NVS
+BIOS-e820: [mem 0x0000000000808000-0x000000000080ffff] usable
+BIOS-e820: [mem 0x0000000000810000-0x00000000008fffff] ACPI NVS
+BIOS-e820: [mem 0x0000000000900000-0x00000000078eefff] usable
+BIOS-e820: [mem 0x00000000078ef000-0x0000000007b6efff] reserved
+BIOS-e820: [mem 0x0000000007b6f000-0x0000000007b7efff] ACPI data
+BIOS-e820: [mem 0x0000000007b7f000-0x0000000007bfefff] ACPI NVS
+BIOS-e820: [mem 0x0000000007bff000-0x0000000007ef3fff] usable
+BIOS-e820: [mem 0x0000000007ef4000-0x0000000007f77fff] reserved
+BIOS-e820: [mem 0x0000000007f78000-0x0000000007ffffff] ACPI NVS
+BIOS-e820: [mem 0x00000000ffc00000-0x00000000ffffffff] reserved
+```
+
+Let's modify our `MemoryInfo` program:
+- if `full` option is passed, we print memory map as we do now
+- if no option is passed, we print memory map in a "Linux kernel way"
+
+First, add `full` boolean flag. If argument "full" is passed to our program, we'll set this flag, else it would be equal to `false`.
+```
+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;
+ }
+ }
+}
+```
+
+To use `EFI_SHELL_PARAMETERS_PROTOCOL` we need to add include file:
+```
+#include <Protocol/ShellParameters.h>
+```
+And add GUID to the application *.inf file:
+```
+[Protocols]
+ gEfiShellParametersProtocolGuid
+```
+
+Now to the next problem. Create a function for OS memory type mapping:
+```
+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_OS_view(UINT32 type)
+{
+ if (type > sizeof(memory_types_OS_view)/sizeof(CHAR16 *))
+ return L"Unknown";
+
+ return memory_types_OS_view[type];
+}
+```
+
+And finally we need to modify our program to glue adjacent regions with the same type together if the `full` flag is not set:
+```
+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;
+}
+```
+
+Build program and copy it to UEFI folder.
+If we run in with the `full` option, everything would be like the last time:
+```
+FS0:\> MemoryInfo.efi full
+[#00] Type: EfiBootServicesCode Attr: UC WC WT WB
+ Phys: 0000000000000000-0000000000000FFF
+[#01] Type: EfiConventionalMemory Attr: UC WC WT WB
+ Phys: 0000000000001000-000000000009FFFF
+[#02] Type: EfiConventionalMemory Attr: UC WC WT WB
+ Phys: 0000000000100000-00000000007FFFFF
+[#03] Type: EfiACPIMemoryNVS Attr: UC WC WT WB
+ Phys: 0000000000800000-0000000000807FFF
+[#04] Type: EfiConventionalMemory Attr: UC WC WT WB
+ Phys: 0000000000808000-000000000080FFFF
+[#05] Type: EfiACPIMemoryNVS Attr: UC WC WT WB
+ Phys: 0000000000810000-00000000008FFFFF
+...
+```
+
+But if we run it without the `full` option, we will get a map similar to the that kernel displays in its boot log:
+```
+FS0:\> MemoryInfo.efi
+ [mem: 0000000000000000-000000000009FFFF] usable
+ [mem: 0000000000100000-00000000007FFFFF] usable
+ [mem: 0000000000800000-0000000000807FFF] ACPI NVS
+ [mem: 0000000000808000-000000000080FFFF] usable
+ [mem: 0000000000810000-00000000008FFFFF] ACPI NVS
+ [mem: 0000000000900000-00000000078EEFFF] usable
+ [mem: 00000000078EF000-0000000007B6EFFF] reserved
+ [mem: 0000000007B6F000-0000000007B7EFFF] ACPI data
+ [mem: 0000000007B7F000-0000000007BFEFFF] ACPI NVS
+ [mem: 0000000007BFF000-0000000007EF3FFF] usable
+ [mem: 0000000007EF4000-0000000007F77FFF] reserved
+ [mem: 0000000007F78000-0000000007FFFFFF] ACPI NVS
+ [mem: 00000000FFC00000-00000000FFFFFFFF] reserved
+```
+Compare it with the actual kernel output:
+```
+BIOS-provided physical RAM map:
+BIOS-e820: [mem 0x0000000000000000-0x000000000009ffff] usable
+BIOS-e820: [mem 0x0000000000100000-0x00000000007fffff] usable
+BIOS-e820: [mem 0x0000000000800000-0x0000000000807fff] ACPI NVS
+BIOS-e820: [mem 0x0000000000808000-0x000000000080ffff] usable
+BIOS-e820: [mem 0x0000000000810000-0x00000000008fffff] ACPI NVS
+BIOS-e820: [mem 0x0000000000900000-0x00000000078eefff] usable
+BIOS-e820: [mem 0x00000000078ef000-0x0000000007b6efff] reserved
+BIOS-e820: [mem 0x0000000007b6f000-0x0000000007b7efff] ACPI data
+BIOS-e820: [mem 0x0000000007b7f000-0x0000000007bfefff] ACPI NVS
+BIOS-e820: [mem 0x0000000007bff000-0x0000000007ef3fff] usable
+BIOS-e820: [mem 0x0000000007ef4000-0x0000000007f77fff] reserved
+BIOS-e820: [mem 0x0000000007f78000-0x0000000007ffffff] ACPI NVS
+BIOS-e820: [mem 0x00000000ffc00000-0x00000000ffffffff] reserved
+```
diff --git a/Lessons/Lesson_12/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_12/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..1f05899
--- /dev/null
+++ b/Lessons/Lesson_12/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/Lessons/Lesson_12/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_12/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_12/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/Lessons/Lesson_12/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_12/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..32e9c43
--- /dev/null
+++ b/Lessons/Lesson_12/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/Lessons/Lesson_12/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_12/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_12/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/Lessons/Lesson_12/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lessons/Lesson_12/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lessons/Lesson_12/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/Lessons/Lesson_12/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_12/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lessons/Lesson_12/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/Lessons/Lesson_12/UefiLessonsPkg/MemoryInfo/MemoryInfo.c b/Lessons/Lesson_12/UefiLessonsPkg/MemoryInfo/MemoryInfo.c
new file mode 100644
index 0000000..8c3bcf2
--- /dev/null
+++ b/Lessons/Lesson_12/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/Lessons/Lesson_12/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf b/Lessons/Lesson_12/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
new file mode 100644
index 0000000..777010d
--- /dev/null
+++ b/Lessons/Lesson_12/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/Lessons/Lesson_12/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_12/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_12/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/Lessons/Lesson_12/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_12/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_12/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/Lessons/Lesson_12/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_12/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..09f38ea
--- /dev/null
+++ b/Lessons/Lesson_12/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,33 @@
+[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
+
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
+ UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ UefiLessonsPkg/ImageHandle/ImageHandle.inf
+ UefiLessonsPkg/ImageInfo/ImageInfo.inf
+ UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
+
+
diff --git a/Lessons/Lesson_12/bzImage b/Lessons/Lesson_12/bzImage
new file mode 100644
index 0000000..80c73e2
--- /dev/null
+++ b/Lessons/Lesson_12/bzImage
Binary files differ
diff --git a/Lessons/Lesson_13/README.md b/Lessons/Lesson_13/README.md
new file mode 100644
index 0000000..0d42005
--- /dev/null
+++ b/Lessons/Lesson_13/README.md
@@ -0,0 +1,137 @@
+In previous lesson we've used `EFI_SHELL_PARAMETERS_PROTOCOL` to get command line parameters to our app.
+It is a valid method but there is a simpler way to do it for the shell apps.
+
+To ease things we can use the entry point in this format:
+https://github.com/tianocore/edk2/blob/master/ShellPkg/Include/Library/ShellCEntryLib.h
+```
+INTN
+EFIAPI
+ShellAppMain (
+ IN UINTN Argc,
+ IN CHAR16 **Argv
+ );
+```
+This way `Argc`/`Argv` are passed directly to the app entry point like it is usually happening in C programming.
+
+Let's create a `SimpleShellApp` based on our `HelloWorld` app.
+
+With the necessary modifications the INF file would look like this:
+```
+[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
+```
+Main changes:
+- `ENTRY_POINT = ShellCEntryLib` is added to the `[Defines]` section
+- `ShellCEntryLib` is added to the `[LibraryClasses]` section
+
+In the end it works this way. Shell C library is the main UEFI app with the standard entry point:
+```
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+```
+It parses incoming parameters with the `EFI_SHELL_PARAMETERS_PROTOCOL` like we did it and then calls our app entry point passing all of the parsed parameteres with the call:
+```
+INTN
+EFIAPI
+ShellAppMain (
+ IN UINTN Argc,
+ IN CHAR16 **Argv
+ );
+```
+You can look at the source code of `ShellAppMain` at the https://github.com/tianocore/edk2/blob/master/ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.c
+
+If you look at the source you could see that istead of a `HandleProtocol` API that we've used:
+```
+Status = gBS->HandleProtocol(
+ ImageHandle,
+ &gEfiShellParametersProtocolGuid,
+ (VOID **) &ShellParameters
+);
+```
+it uses `OpenProtocol` API: (I've modified a code a little bit to make it comparable to our version)
+```
+Status = gBS->OpenProtocol(
+ ImageHandle,
+ &gEfiShellParametersProtocolGuid,
+ (VOID **)&ShellParameters,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+);
+```
+According to the UEFI spec `HandleProtocol` API is outdated and `OpenProtocol` should be used instead.
+`OpenProtocol` API is a more general call that can cover more cases. It all would matter when you start develop UEFI drivers. You can read UEFI spec for more information. Right now just accept a fact that for the UEFI app these two calls are the same.
+
+Let's go back to our code. To find the necessary `ShellCEntryLib` library class search as usual:
+```
+$ grep ShellCEntryLib -r ./ --include=*.inf | grep LIBRARY_CLASS
+./ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf: LIBRARY_CLASS = ShellCEntryLib|UEFI_APPLICATION UEFI_DRIVER
+```
+
+Add this library class to our `UefiLessonsPkg/UefiLessonsPkg.dsc`:
+```
+ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf
+```
+Don't forget also to add our new app under the `[Components]` section:
+```
+UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf
+```
+
+
+Now let's look at the `*.c` file.
+
+We can't use our first print method as `SystemTable` now is unavailable, but we can simply use `SystemTable` with the help of `gST` pointer:
+```
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
+{
+ Print(L"Argc=%d\n", Argc);
+// SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello World!\n");
+ gST->ConOut->OutputString(gST->ConOut, L"Hello again!\n");
+ Print(L"Bye!\n");
+ return 0;
+}
+```
+
+Let's add some parameters handling code:
+```
+for (UINTN i=Argc; i>0; i--) {
+ Print(L"Arg[%d]=%s\n", Argc-i, Argv[Argc-i]);
+}
+```
+
+If we test our app under OVMF we would get:
+```
+FS0:\> SimpleShellApp.efi kkk ggg
+Hello again!
+Bye!
+Arg[0]=FS0:\SimpleShellApp.efi
+Arg[1]=kkk
+Arg[2]=ggg
+FS0:\> SimpleShellApp.efi
+Hello again!
+Bye!
+Arg[0]=FS0:\SimpleShellApp.efi
+```
diff --git a/Lessons/Lesson_13/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_13/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..1f05899
--- /dev/null
+++ b/Lessons/Lesson_13/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/Lessons/Lesson_13/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_13/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_13/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/Lessons/Lesson_13/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_13/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..32e9c43
--- /dev/null
+++ b/Lessons/Lesson_13/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/Lessons/Lesson_13/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_13/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_13/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/Lessons/Lesson_13/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lessons/Lesson_13/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lessons/Lesson_13/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/Lessons/Lesson_13/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_13/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lessons/Lesson_13/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/Lessons/Lesson_13/UefiLessonsPkg/MemoryInfo/MemoryInfo.c b/Lessons/Lesson_13/UefiLessonsPkg/MemoryInfo/MemoryInfo.c
new file mode 100644
index 0000000..8c3bcf2
--- /dev/null
+++ b/Lessons/Lesson_13/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/Lessons/Lesson_13/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf b/Lessons/Lesson_13/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
new file mode 100644
index 0000000..777010d
--- /dev/null
+++ b/Lessons/Lesson_13/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/Lessons/Lesson_13/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c b/Lessons/Lesson_13/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c
new file mode 100644
index 0000000..b13aa6c
--- /dev/null
+++ b/Lessons/Lesson_13/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/Lessons/Lesson_13/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf b/Lessons/Lesson_13/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf
new file mode 100644
index 0000000..013bf4e
--- /dev/null
+++ b/Lessons/Lesson_13/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/Lessons/Lesson_13/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_13/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_13/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/Lessons/Lesson_13/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_13/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_13/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/Lessons/Lesson_13/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_13/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..4339a2d
--- /dev/null
+++ b/Lessons/Lesson_13/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
+
+
diff --git a/Lessons/Lesson_14/Conf/target.txt b/Lessons/Lesson_14/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lessons/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/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
+```
+
diff --git a/Lessons/Lesson_14/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_14/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..1f05899
--- /dev/null
+++ b/Lessons/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/Lessons/Lesson_14/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_14/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/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/Lessons/Lesson_14/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_14/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..32e9c43
--- /dev/null
+++ b/Lessons/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/Lessons/Lesson_14/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_14/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/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/Lessons/Lesson_14/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lessons/Lesson_14/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lessons/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/Lessons/Lesson_14/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_14/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lessons/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/Lessons/Lesson_14/UefiLessonsPkg/ListVariables/ListVariables.c b/Lessons/Lesson_14/UefiLessonsPkg/ListVariables/ListVariables.c
new file mode 100644
index 0000000..1f3ef4a
--- /dev/null
+++ b/Lessons/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/Lessons/Lesson_14/UefiLessonsPkg/ListVariables/ListVariables.inf b/Lessons/Lesson_14/UefiLessonsPkg/ListVariables/ListVariables.inf
new file mode 100644
index 0000000..14e9fa2
--- /dev/null
+++ b/Lessons/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/Lessons/Lesson_14/UefiLessonsPkg/MemoryInfo/MemoryInfo.c b/Lessons/Lesson_14/UefiLessonsPkg/MemoryInfo/MemoryInfo.c
new file mode 100644
index 0000000..8c3bcf2
--- /dev/null
+++ b/Lessons/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/Lessons/Lesson_14/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf b/Lessons/Lesson_14/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
new file mode 100644
index 0000000..777010d
--- /dev/null
+++ b/Lessons/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/Lessons/Lesson_14/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c b/Lessons/Lesson_14/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c
new file mode 100644
index 0000000..b13aa6c
--- /dev/null
+++ b/Lessons/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/Lessons/Lesson_14/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf b/Lessons/Lesson_14/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf
new file mode 100644
index 0000000..013bf4e
--- /dev/null
+++ b/Lessons/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/Lessons/Lesson_14/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_14/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/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/Lessons/Lesson_14/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_14/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/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/Lessons/Lesson_14/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_14/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..dbe9b17
--- /dev/null
+++ b/Lessons/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/Lessons/Lesson_15/Conf/target.txt b/Lessons/Lesson_15/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lessons/Lesson_15/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/Lessons/Lesson_15/README.md b/Lessons/Lesson_15/README.md
new file mode 100644
index 0000000..55447ca
--- /dev/null
+++ b/Lessons/Lesson_15/README.md
@@ -0,0 +1,359 @@
+Let's print content of variables that define boot options in UEFI.
+
+To do it, we need to use `GetVariable()` API function from the EFI Runtime Services:
+```
+GetVariable()
+
+Summary:
+Returns the value of a variable.
+
+Prototype:
+typedef
+EFI_STATUS
+GetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data OPTIONAL
+ );
+
+Parameters:
+VariableName A Null-terminated string that is the name of the vendor’s variable.
+VendorGuid A unique identifier for the vendor
+Attributes If not NULL, a pointer to the memory location to return the
+ attributes bitmask for the variable.
+ If not NULL, then Attributes is set on output both when
+ EFI_SUCCESS and when EFI_BUFFER_TOO_SMALL is returned.
+DataSize On input, the size in bytes of the return Data buffer.
+ On output the size of data returned in Data.
+Data The buffer to return the contents of the variable. May be NULL
+ with a zero DataSize in order to determine the size buffer needed.
+
+Description:
+Each vendor may create and manage its own variables without the risk of name conflicts by using a
+unique VendorGuid. When a variable is set its Attributes are supplied to indicate how the data variable
+should be stored and maintained by the system. The attributes affect when the variable may be accessed
+and volatility of the data
+
+If the Data buffer is too small to hold the contents of the variable, the error EFI_BUFFER_TOO_SMALL is
+returned and DataSize is set to the required buffer size to obtain the data.
+
+Status Codes Returned:
+EFI_SUCCESS The function completed successfully.
+EFI_NOT_FOUND The variable was not found.
+EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has been
+ updated with the size needed to complete the request. If
+ Attributes is not NULL, then the attributes bitmask for the
+ variable has been stored to the memory location pointed-to by
+ Attributes.
+...
+
+```
+
+In previous lesson we've discovered that these options are present in our environment under GUID `EFI_GLOBAL_VARIABLE` (gEfiGlobalVariableGuid):
+```
+Boot0000
+Boot0001
+Boot0002
+Boot0003
+Boot0004
+BootCurrent
+BootOrder
+```
+
+If we look at the UEFI spec for these options description we would find:
+```
+Each Boot#### variable contains an EFI_LOAD_OPTION. Each Boot#### variable is the name “Boot”
+appended with a unique four digit hexadecimal number. For example, Boot0001, Boot0002, Boot0A02,
+etc.
+
+...
+
+The BootOrder variable contains an array of UINT16’s that make up an ordered list of the Boot####
+options. The first element in the array is the value for the first logical boot option, the second element is
+the value for the second logical boot option, etc. The BootOrder order list is used by the firmware’s
+boot manager as the default boot order.
+
+...
+
+The BootCurrent variable is a single UINT16 that defines the Boot#### option that was selected on
+the current boot.
+```
+
+Create `ShowBootVariables` for this lesson.
+
+First let's try to get simple `UINT16 BootCurrent` option.
+
+We would be getting variables a lot in this program, so it is best to create a function that abstracts all the necessities of the `GetVariable` API calls:
+```
+EFI_STATUS
+GetNvramVariable( CHAR16 *VariableName,
+ EFI_GUID *VariableOwnerGuid,
+ VOID **Buffer,
+ UINTN *BufferSize)
+{
+ UINTN Size = 0;
+ *BufferSize = 0;
+
+ EFI_STATUS Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Print(L"Error! 'gRT->GetVariable' call returned %r\n", Status);
+ return Status;
+ }
+
+ *Buffer = AllocateZeroPool(Size);
+ if (!Buffer) {
+ Print(L"Error! 'AllocateZeroPool' call returned %r\n", Status);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, *Buffer);
+ if (Status == EFI_SUCCESS) {
+ *BufferSize = Size;
+ } else {
+ FreePool( *Buffer );
+ *Buffer = NULL;
+ }
+
+ return Status;
+}
+```
+
+As with many other different UEFI APIs first `GetVariable` call gives us `EFI_BUFFER_TOO_SMALL` error, but fills `Size` variable with the size of the array that we need to allocate and pass to this function for the correct execution.
+We allocate necessary size with the `AllocateZeroPool` edk2 library call, like we did it in previous lesson. After that we call `GetVariable` function for the second time, expecting `EFI_SUCCESS` status.
+
+
+The main function would look like this:
+```
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+EFI_STATUS
+GetNvramVariable( CHAR16 *VariableName,
+ EFI_GUID *VariableOwnerGuid,
+ VOID **Buffer,
+ UINTN *BufferSize)
+{
+ ...
+}
+
+INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
+{
+ UINTN OptionSize;
+ EFI_STATUS Status;
+
+ UINT16* BootCurrent;
+ Status = GetNvramVariable(L"BootCurrent", &gEfiGlobalVariableGuid, (VOID**)&BootCurrent, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ Print(L"BootCurrent=%d\n", *BootCurrent);
+ } else {
+ Print(L"Can't get BootCurrent variable\n");
+ }
+
+ return EFI_SUCCESS;
+}
+```
+
+If we execute this code under OVMF we would get:
+```
+FS0:\> ShowBootVariables.efi
+3
+```
+This means that `Boot0003` is active.
+
+
+Now let's get `UINT16 BootOrder[]` variable. It is an array of XXXX numbers that describe Boot option priority.
+So `{0,2,4,1,3}` for example would mean this order:
+```
+Boot0000
+Boot0002
+Boot0004
+Boot0001
+Boot0003
+```
+
+This is the code to get and print this array:
+```
+UINT16* BootOrderArray;
+Status = GetNvramVariable(L"BootOrder", &gEfiGlobalVariableGuid, (VOID**)&BootOrderArray, &OptionSize);
+if (Status == EFI_SUCCESS) {
+ for (UINTN i=0; i<(OptionSize/sizeof(UINT16)); i++) {
+ Print(L"Boot%04d%s\n", BootOrderArray[i], (BootOrderArray[i] == *BootCurrent)? L"*" : L"" );
+ }
+} else {
+ Print(L"Can't get BootOrder variable\n");
+}
+```
+
+If we execute this code under OVMF we would get:
+```
+Boot0000
+Boot0001
+Boot0002
+Boot0003*
+Boot0004
+```
+
+
+Now let's print information about every `Boot####` option.
+
+According to the UEFI the spec these options are stored in a `EFI_LOAD_OPTION` structure:
+```
+typedef struct _EFI_LOAD_OPTION {
+ UINT32 Attributes;
+ UINT16 FilePathListLength;
+ // CHAR16 Description[];
+ // EFI_DEVICE_PATH_PROTOCOL FilePathList[];
+ // UINT8 OptionalData[];
+} EFI_LOAD_OPTION;
+
+Parameters
+Attributes The attributes for this load option entry. All unused bits must be zero
+ and are reserved by the UEFI specification for future growth.
+FilePathListLength Length in bytes of the FilePathList. OptionalData starts at
+ offset sizeof(UINT32) + sizeof(UINT16) +
+ StrSize(Description) + FilePathListLength of the
+ EFI_LOAD_OPTION descriptor.
+Description The user readable description for the load option. This field ends
+ with a Null character.
+FilePathList A packed array of UEFI device paths. The first element of the array is
+ a device path that describes the device and location of the Image for
+ this load option. The FilePathList[0] is specific to the device
+ type. Other device paths may optionally exist in the FilePathList,
+ but their usage is OSV specific. Each element in the array is variable
+ length, and ends at the device path end structure. Because the size
+ of Description is arbitrary, this data structure is not guaranteed
+ to be aligned on a natural boundary. This data structure may have to
+ be copied to an aligned natural boundary before it is used.
+OptionalData The remaining bytes in the load option descriptor are a binary data
+ buffer that is passed to the loaded image. If the field is zero bytes
+ long, a NULL pointer is passed to the loaded image. The number of
+ bytes in OptionalData can be computed by subtracting the
+ starting offset of OptionalData from total size in bytes of the
+ EFI_LOAD_OPTION.
+```
+In edk2 it is defined in a file https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Uefi/UefiSpec.h
+
+Pay attention to the fact that some fields in this structure are commented:
+```
+// CHAR16 Description[];
+// EFI_DEVICE_PATH_PROTOCOL FilePathList[];
+// UINT8 OptionalData[];
+```
+It is because these fields are variable size arrays, so we need to calculate offsets to them dynamically.
+
+Create a function that accepts names of a Boot variable (such as "Boot0003") and outputs all the needed information about it:
+```
+VOID PrintBootOption(CHAR16* BootOptionName)
+{
+ UINTN OptionSize;
+ UINT8* Buffer;
+
+ EFI_STATUS Status = GetNvramVariable(BootOptionName, &gEfiGlobalVariableGuid, (VOID**)&Buffer, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ EFI_LOAD_OPTION* LoadOption = (EFI_LOAD_OPTION*) Buffer;
+ CHAR16* Description = (CHAR16*)(Buffer + sizeof (EFI_LOAD_OPTION));
+ UINTN DescriptionSize = StrSize(Description);
+
+ Print(L"%s\n", Description);
+ if (LoadOption->FilePathListLength != 0) {
+ VOID* FilePathList = (UINT8 *)Description + DescriptionSize;
+ CHAR16* DevPathString = ConvertDevicePathToText(FilePathList, TRUE, FALSE);
+ Print(L"%s\n", DevPathString);
+ }
+ } else {
+ Print(L"Can't get %s variable\n", BootOptionName);
+ }
+}
+```
+
+This code uses pointer arithmetics that we've discussed above. To get `Description` field size we simply use `StrSize(Description)` call as `Description` field always ends with Null.
+
+To print DevicePath as a string we use `ConvertDevicePathToText` call (we've used it earlier in our `ImageInfo` application). To use it we need to add `#include <Library/DevicePathLib.h>` to our program.
+
+Now we need to construct "BootXXXX" variables from a `BootOrder` numbers.
+
+To do so we would use `UnicodeSPrint` function from the https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PrintLib.h
+```
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ Unicode format string and variable argument list.
+ This function is similar as snprintf_s defined in C11.
+
+ ...
+
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated Unicode format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+**/
+
+UINTN
+EFIAPI
+UnicodeSPrint (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR16 *FormatString,
+ ...
+ );
+```
+
+Just in case in the same file there is a similar function for ASCII:
+```
+UINTN
+EFIAPI
+AsciiSPrint (
+ OUT CHAR8 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ ...
+ );
+```
+
+
+So the code inside BootOrder loop now would look like this:
+```
+CHAR16 BootOptionStr[sizeof("Boot####")+1];
+UnicodeSPrint(BootOptionStr, (sizeof("Boot####")+1)*sizeof(CHAR16), L"Boot%04x", BootOrderArray[i]);
+Print(L"%s%s\n", BootOptionStr, (BootOrderArray[i] == *BootCurrent)? L"*" : L"" );
+PrintBootOption(BootOptionStr);
+Print(L"\n");
+```
+
+Don't forget to add `#include <Library/PrintLib.h>` to the start of the file.
+
+
+If we compile our app and execute it under OVMF we would get:
+```
+FS0:\> ShowBootVariables.efi
+Boot0000
+UiApp
+Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(462CAA21-7614-4503-836E-8AB6F4662331)
+
+Boot0001
+UEFI QEMU DVD-ROM QM00003
+PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+
+Boot0002
+UEFI QEMU HARDDISK QM00001
+PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+
+Boot0003*
+EFI Internal Shell
+Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
+
+Boot0004
+UEFI PXEv4 (MAC:525400123456)
+PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400123456,0x1)/IPv4(0.0.0.0)
+```
+
+We are definitely in the UEFI shell, so the `BootCurrent`(="*") is placed correctly.
+
+
diff --git a/Lessons/Lesson_15/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_15/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..1f05899
--- /dev/null
+++ b/Lessons/Lesson_15/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/Lessons/Lesson_15/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_15/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_15/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/Lessons/Lesson_15/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_15/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..32e9c43
--- /dev/null
+++ b/Lessons/Lesson_15/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/Lessons/Lesson_15/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_15/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_15/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/Lessons/Lesson_15/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lessons/Lesson_15/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lessons/Lesson_15/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/Lessons/Lesson_15/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_15/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lessons/Lesson_15/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/Lessons/Lesson_15/UefiLessonsPkg/ListVariables/ListVariables.c b/Lessons/Lesson_15/UefiLessonsPkg/ListVariables/ListVariables.c
new file mode 100644
index 0000000..1f3ef4a
--- /dev/null
+++ b/Lessons/Lesson_15/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/Lessons/Lesson_15/UefiLessonsPkg/ListVariables/ListVariables.inf b/Lessons/Lesson_15/UefiLessonsPkg/ListVariables/ListVariables.inf
new file mode 100644
index 0000000..14e9fa2
--- /dev/null
+++ b/Lessons/Lesson_15/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/Lessons/Lesson_15/UefiLessonsPkg/MemoryInfo/MemoryInfo.c b/Lessons/Lesson_15/UefiLessonsPkg/MemoryInfo/MemoryInfo.c
new file mode 100644
index 0000000..8c3bcf2
--- /dev/null
+++ b/Lessons/Lesson_15/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/Lessons/Lesson_15/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf b/Lessons/Lesson_15/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
new file mode 100644
index 0000000..777010d
--- /dev/null
+++ b/Lessons/Lesson_15/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/Lessons/Lesson_15/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c b/Lessons/Lesson_15/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
new file mode 100644
index 0000000..7f6b58c
--- /dev/null
+++ b/Lessons/Lesson_15/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
@@ -0,0 +1,93 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+
+
+EFI_STATUS
+GetNvramVariable( CHAR16 *VariableName,
+ EFI_GUID *VariableOwnerGuid,
+ VOID **Buffer,
+ UINTN *BufferSize)
+{
+ UINTN Size = 0;
+ *BufferSize = 0;
+
+ EFI_STATUS Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Print(L"Error! 'gRT->GetVariable' call returned %r\n", Status);
+ return Status;
+ }
+
+ *Buffer = AllocateZeroPool(Size);
+ if (!Buffer) {
+ Print(L"Error! 'AllocateZeroPool' call returned %r\n", Status);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, *Buffer);
+ if (Status == EFI_SUCCESS) {
+ *BufferSize = Size;
+ } else {
+ FreePool( *Buffer );
+ *Buffer = NULL;
+ }
+
+ return Status;
+}
+
+
+VOID PrintBootOption(CHAR16* BootOptionName)
+{
+ UINTN OptionSize;
+ UINT8* Buffer;
+
+ EFI_STATUS Status = GetNvramVariable(BootOptionName, &gEfiGlobalVariableGuid, (VOID**)&Buffer, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ EFI_LOAD_OPTION* LoadOption = (EFI_LOAD_OPTION*) Buffer;
+ CHAR16* Description = (CHAR16*)(Buffer + sizeof (EFI_LOAD_OPTION));
+ UINTN DescriptionSize = StrSize(Description);
+
+ Print(L"%s\n", Description);
+ if (LoadOption->FilePathListLength != 0) {
+ VOID* FilePathList = (UINT8 *)Description + DescriptionSize;
+ CHAR16* DevPathString = ConvertDevicePathToText(FilePathList, TRUE, FALSE);
+ Print(L"%s\n", DevPathString);
+ }
+ } else {
+ Print(L"Can't get %s variable\n", BootOptionName);
+ }
+}
+
+
+INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
+{
+ UINTN OptionSize;
+ EFI_STATUS Status;
+
+ UINT16* BootCurrent;
+ Status = GetNvramVariable(L"BootCurrent", &gEfiGlobalVariableGuid, (VOID**)&BootCurrent, &OptionSize);
+ if (Status != EFI_SUCCESS) {
+ Print(L"Can't get BootCurrent variable\n");
+ }
+
+ UINT16* BootOrderArray;
+ Status = GetNvramVariable(L"BootOrder", &gEfiGlobalVariableGuid, (VOID**)&BootOrderArray, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ for (UINTN i=0; i<(OptionSize/sizeof(UINT16)); i++) {
+ CHAR16 BootOptionStr[sizeof("Boot####")+1];
+ UnicodeSPrint(BootOptionStr, (sizeof("Boot####")+1)*sizeof(CHAR16), L"Boot%04x", BootOrderArray[i]);
+ Print(L"%s%s\n", BootOptionStr, (BootOrderArray[i] == *BootCurrent)? L"*" : L"" );
+ PrintBootOption(BootOptionStr);
+ Print(L"\n");
+ }
+ } else {
+ Print(L"Can't get BootOrder variable\n");
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_15/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf b/Lessons/Lesson_15/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
new file mode 100644
index 0000000..d2cfba9
--- /dev/null
+++ b/Lessons/Lesson_15/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
@@ -0,0 +1,19 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = ShowBootVariables
+ FILE_GUID = 31266d12-9c60-478e-905e-05d117a3a9df
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+[Sources]
+ ShowBootVariables.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ ShellCEntryLib
+
diff --git a/Lessons/Lesson_15/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c b/Lessons/Lesson_15/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c
new file mode 100644
index 0000000..b13aa6c
--- /dev/null
+++ b/Lessons/Lesson_15/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/Lessons/Lesson_15/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf b/Lessons/Lesson_15/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf
new file mode 100644
index 0000000..013bf4e
--- /dev/null
+++ b/Lessons/Lesson_15/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/Lessons/Lesson_15/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_15/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_15/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/Lessons/Lesson_15/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_15/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_15/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/Lessons/Lesson_15/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_15/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..5a3ae1c
--- /dev/null
+++ b/Lessons/Lesson_15/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,36 @@
+[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
+ UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
+
diff --git a/Lessons/Lesson_16/Conf/target.txt b/Lessons/Lesson_16/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lessons/Lesson_16/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/Lessons/Lesson_16/Ovmf.diff b/Lessons/Lesson_16/Ovmf.diff
new file mode 100644
index 0000000..01238c5
--- /dev/null
+++ b/Lessons/Lesson_16/Ovmf.diff
@@ -0,0 +1,59 @@
+diff --git a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
+index b0e9742937..840e6afa16 100644
+--- a/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
++++ b/OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
+@@ -1535,6 +1535,13 @@ PlatformBootManagerAfterConsole (
+ &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
+ );
+
++ //
++ // Register HelloWorld app
++ //
++ PlatformRegisterFvBootOption (
++ &gHelloWorldFileGuid, L"Hello World", LOAD_OPTION_ACTIVE
++ );
++
+ RemoveStaleFvFileOptions ();
+ SetBootOrderFromQemu ();
+
+diff --git a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+index e470b9a6a3..62ae7be761 100644
+--- a/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
++++ b/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
+@@ -33,6 +33,7 @@
+ OvmfPkg/OvmfPkg.dec
+ SecurityPkg/SecurityPkg.dec
+ ShellPkg/ShellPkg.dec
++ UefiLessonsPkg/UefiLessonsPkg.dec
+
+ [LibraryClasses]
+ BaseLib
+@@ -83,3 +84,4 @@
+ gEfiGlobalVariableGuid
+ gRootBridgesConnectedEventGroupGuid
+ gUefiShellFileGuid
++ gHelloWorldFileGuid
+diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
+index 0a237a9058..51eba5e225 100644
+--- a/OvmfPkg/OvmfPkgX64.dsc
++++ b/OvmfPkg/OvmfPkgX64.dsc
+@@ -951,6 +951,7 @@
+ gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
+ gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
+ }
++ UefiLessonsPkg/HelloWorld/HelloWorld.inf
+
+ !if $(SECURE_BOOT_ENABLE) == TRUE
+ SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
+diff --git a/OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
+index 5fa8c08958..ab4e021452 100644
+--- a/OvmfPkg/OvmfPkgX64.fdf
++++ b/OvmfPkg/OvmfPkgX64.fdf
+@@ -308,6 +308,7 @@ INF ShellPkg/DynamicCommand/HttpDynamicCommand/HttpDynamicCommand.inf
+ INF OvmfPkg/LinuxInitrdDynamicShellCommand/LinuxInitrdDynamicShellCommand.inf
+ !endif
+ INF ShellPkg/Application/Shell/Shell.inf
++INF UefiLessonsPkg/HelloWorld/HelloWorld.inf
+
+ INF MdeModulePkg/Logo/LogoDxe.inf
+
diff --git a/Lessons/Lesson_16/README.md b/Lessons/Lesson_16/README.md
new file mode 100644
index 0000000..f983b52
--- /dev/null
+++ b/Lessons/Lesson_16/README.md
@@ -0,0 +1,286 @@
+In previous lesson we've developed an app that showed us current boot options:
+```
+FS0:\> ShowBootVariables.efi
+Boot0000
+UiApp
+Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(462CAA21-7614-4503-836E-8AB6F4662331)
+
+Boot0001
+UEFI QEMU DVD-ROM QM00003
+PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+
+Boot0002
+UEFI QEMU HARDDISK QM00001
+PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+
+Boot0003*
+EFI Internal Shell
+Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
+
+Boot0004
+UEFI PXEv4 (MAC:525400123456)
+PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400123456,0x1)/IPv4(0.0.0.0)
+```
+
+If you want to know information about the printed GUIDs here it is:
+- `FILE_GUID = 7C04A583-9E3E-4f1c-AD65-E05268D0B4D1 # gUefiShellFileGuid`
+https://github.com/tianocore/edk2/blob/master/ShellPkg/Application/Shell/Shell.inf
+- `FILE_GUID = 462CAA21-7614-4503-836E-8AB6F4662331` - UiApp module is driver for BDS phase
+https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Application/UiApp/UiApp.inf
+
+As for the `7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1` it is a GUID for the firmware volume in our OVMF image.
+https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgX64.fdf
+
+This *.fdf file lists what drivers/apps are placed in every volume in the image (this includes volumes for SEC, PEI or DXE stages):
+```
+...
+
+[FV.SECFV]
+FvNameGuid = 763BED0D-DE9F-48F5-81F1-3E90E1B1A015
+BlockSize = 0x1000
+FvAlignment = 16
+...
+INF <...>
+...
+
+[FV.PEIFV]
+FvNameGuid = 6938079B-B503-4E3D-9D24-B28337A25806
+BlockSize = 0x10000
+FvAlignment = 16
+...
+INF <...>
+...
+
+[FV.DXEFV]
+FvForceRebase = FALSE
+FvNameGuid = 7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1 ### <---- this is a GUID from our output
+BlockSize = 0x10000
+FvAlignment = 16
+...
+INF ShellPkg/Application/Shell/Shell.inf <--- this apps are placed in the FV.DXEFV firmware volume
+...
+INF MdeModulePkg/Application/UiApp/UiApp.inf
+```
+
+For the complete edk2 FDF file specification look at the https://edk2-docs.gitbook.io/edk-ii-fdf-specification/
+
+If you look at the https://github.com/tianocore/edk2/blob/master/ShellPkg/Application/Shell/Shell.inf you'll see that EFI Shell is a simple `UEFI_APPLICATION`. We've developed a lot of those in these lessons, so let's try to add one of our apps to boot options.
+
+We will try to add our `HelloWorld` application to the boot options. We will look at how Shell app is included and try to do the same.
+
+First we need to add our app to OVMF image. So let's add `UefiLessonsPkg/HelloWorld/HelloWorld.inf` to the `[FV.DXEFV]` section next to `INF ShellPkg/Application/Shell/Shell.inf` in a `OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf` we've already discussed.
+
+```
+[FV.DXEFV]
+FvForceRebase = FALSE
+FvNameGuid = 7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1
+BlockSize = 0x10000
+FvAlignment = 16
+...
+
+ INF ShellPkg/Application/Shell/Shell.inf
++ INF UefiLessonsPkg/HelloWorld/HelloWorld.inf
+...
+```
+
+If we try to build OVMF now we would get:
+```
+$ build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5
+...
+build.py...
+ : error F001: Module /home/kostr/tiano/edk2/UefiLessonsPkg/HelloWorld/HelloWorld.inf NOT found in DSC file; Is it really a binary module?
+...
+```
+
+Ok, so we need to add information to the `OvmfPkg/OvmfPkgX64.dsc` file. If you look at this file, you'll see that `ShellPkg/Application/Shell/Shell.inf` is listed under `[Components]` section. We've already used it in our first lesson when we've tried to compile our app without package. Add `UefiLessonsPkg/HelloWorld/HelloWorld.inf` next to the Shell INF file.
+```
+[Components]
+ ...
+ ShellPkg/Application/Shell/Shell.inf {
+ ...
+ }
++ UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ ...
+```
+Shell.inf file has some information inside the brackets `{...}`. Don't mind it, we don't need such info for our simple `HelloWorld.inf`.
+
+
+Now we can compile OVMF without errors:
+```
+$ build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5
+```
+Our `HelloWorld` app would be compiled and embedded in the OVMF image but unfortunately in wouldn't be listed in a boot options.
+
+When we used our `ShowBootVariables.efi` app we saw that UEFI shell boot option had a description `EFI Internal Shell`. Let's try search for that in a edk2 codebase:
+```
+$ grep "EFI Internal Shell" -r ./ --exclude=Build
+./ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c: &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
+./OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c: &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
+./OvmfPkg/Library/PlatformBootManagerLibBhyve/BdsPlatform.c: &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
+./OvmfPkg/Library/PlatformBootManagerLibGrub/BdsPlatform.c: &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
+```
+
+For our case we're interested in a `./OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c` file:
+```
+VOID
+EFIAPI
+PlatformBootManagerAfterConsole (
+ VOID
+ )
+{
+ ...
+ //
+ // Register UEFI Shell
+ //
+ PlatformRegisterFvBootOption (
+ &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
+ );
+
+ ...
+}
+```
+If you grep for a `gUefiShellFileGuid`:
+```
+./OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c: &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
+./OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf: gUefiShellFileGuid
+./ShellPkg/Application/Shell/Shell.inf: FILE_GUID = 7C04A583-9E3E-4f1c-AD65-E05268D0B4D1 # gUefiShellFileGuid
+./ShellPkg/ShellPkg.dec: gUefiShellFileGuid = {0x7c04a583, 0x9e3e, 0x4f1c, {0xad, 0x65, 0xe0, 0x52, 0x68, 0xd0, 0xb4, 0xd1}}
+```
+
+Ok it looks like we need to create a `UefiLessonsPkg/UefiLessonsPkg.dec` file with something like `gHelloWorldFileGuid` with a value equal to the one that is listed in a `UefiLessonsPkg/HelloWorld/HelloWorld.inf` file.
+
+Let's do it:
+```
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = UefiLessonsPkg
+ PACKAGE_GUID = 7e7edbba-ca2c-4177-a3f0-d3371358773a
+ PACKAGE_VERSION = 1.01
+
+[Guids]
+ # FILE_GUID as defined in UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ gHelloWorldFileGuid = {0x2e55fa38, 0xf148, 0x42d3, {0xaf, 0x90, 0x1b, 0xe2, 0x47, 0x32, 0x3e, 0x30}}
+
+```
+EDK2 Package Declaration (DEC) File Format Specification can be found at link https://edk2-docs.gitbook.io/edk-ii-dec-specification/
+
+Let's add our GUID to the `OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf` file
+```
+[Guids]
+ ...
+ gUefiShellFileGuid
++ gHelloWorldFileGuid
+```
+So we could use it in a `OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c` file:
+```
+VOID
+EFIAPI
+PlatformBootManagerAfterConsole (
+ VOID
+ )
+{
+ ...
+ //
+ // Register UEFI Shell
+ //
+ PlatformRegisterFvBootOption (
+ &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
+ );
+
+ //
+ // Register HelloWorld app
+ //
+ PlatformRegisterFvBootOption (
+ &gHelloWorldFileGuid, L"Hello World", LOAD_OPTION_ACTIVE
+ );
+ ...
+}
+```
+
+If we try to build OVMF now we would get an error:
+```
+$ build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5
+...
+
+build.py...
+/home/kostr/tiano/edk2/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf(87): error 4000: Value of Guid [gHelloWorldFileGuid] is not found under [Guids] section in
+ /home/kostr/tiano/edk2/MdePkg/MdePkg.dec
+ /home/kostr/tiano/edk2/MdeModulePkg/MdeModulePkg.dec
+ /home/kostr/tiano/edk2/SourceLevelDebugPkg/SourceLevelDebugPkg.dec
+ /home/kostr/tiano/edk2/OvmfPkg/OvmfPkg.dec
+ /home/kostr/tiano/edk2/SecurityPkg/SecurityPkg.dec
+ /home/kostr/tiano/edk2/ShellPkg/ShellPkg.dec
+...
+```
+To correct in we need our newly created `UefiLessonsPkg/UefiLessonsPkg.dec` to the `OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf`:
+```
+[Packages]
+ ...
+ ShellPkg/ShellPkg.dec
+ UefiLessonsPkg/UefiLessonsPkg.dec
+```
+
+Finally we can successfully build OVMF. Let's run it and test our newly created boot option.
+
+Execute QEMU launch as usual. Now if you'll execute our `ShowBootVariables.efi` app you would get:
+```
+FS0:\> ShowBootVariables.efi
+Boot0000
+UiApp
+Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(462CAA21-7614-4503-836E-8AB6F4662331)
+
+Boot0001
+UEFI QEMU DVD-ROM QM00003
+PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+
+Boot0002
+UEFI QEMU HARDDISK QM00001
+PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+
+Boot0003*
+EFI Internal Shell
+Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
+
+Boot0004
+Hello World
+Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(2E55FA38-F148-42D3-AF90-1BE247323E30)
+
+Boot0005
+UEFI PXEv4 (MAC:525400123456)
+PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400123456,0x1)/IPv4(0.0.0.0)
+```
+
+Hooraay! Our boot option is present in the system.
+
+UEFI shell has a command `bcfg` to print boot variables. You can check that the data from our app is correct, if you execute `bcfg boot dump`:
+```
+Shell> bcfg boot dump
+Option: 00. Variable: Boot0000
+ Desc - UiApp
+ DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(462CAA21-7614-4503-836E-8AB6F4662331)
+ Optional- N
+Option: 01. Variable: Boot0001
+ Desc - UEFI QEMU DVD-ROM QM00003
+ DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ Optional- Y
+Option: 02. Variable: Boot0002
+ Desc - UEFI QEMU HARDDISK QM00001
+ DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ Optional- Y
+Shell> 03. Variable: Boot0003
+ Desc - EFI Internal Shell
+ DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
+ Optional- N
+Option: 04. Variable: Boot0004
+ Desc - Hello World
+ DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(2E55FA38-F148-42D3-AF90-1BE247323E30)
+ Optional- N
+Option: 05. Variable: Boot0005
+ Desc - UEFI PXEv4 (MAC:525400123456)
+ DevPath - PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400123456,0x1)/IPv4(0.0.0.0)
+ Optional- Y
+```
+
+Just in case I've placed `Ovmf.diff` in this lesson folder that shows all the necessary changes.
+
+
diff --git a/Lessons/Lesson_16/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_16/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..1f05899
--- /dev/null
+++ b/Lessons/Lesson_16/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/Lessons/Lesson_16/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_16/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_16/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/Lessons/Lesson_16/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_16/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..32e9c43
--- /dev/null
+++ b/Lessons/Lesson_16/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/Lessons/Lesson_16/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_16/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_16/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/Lessons/Lesson_16/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lessons/Lesson_16/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lessons/Lesson_16/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/Lessons/Lesson_16/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_16/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lessons/Lesson_16/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/Lessons/Lesson_16/UefiLessonsPkg/ListVariables/ListVariables.c b/Lessons/Lesson_16/UefiLessonsPkg/ListVariables/ListVariables.c
new file mode 100644
index 0000000..1f3ef4a
--- /dev/null
+++ b/Lessons/Lesson_16/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/Lessons/Lesson_16/UefiLessonsPkg/ListVariables/ListVariables.inf b/Lessons/Lesson_16/UefiLessonsPkg/ListVariables/ListVariables.inf
new file mode 100644
index 0000000..14e9fa2
--- /dev/null
+++ b/Lessons/Lesson_16/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/Lessons/Lesson_16/UefiLessonsPkg/MemoryInfo/MemoryInfo.c b/Lessons/Lesson_16/UefiLessonsPkg/MemoryInfo/MemoryInfo.c
new file mode 100644
index 0000000..8c3bcf2
--- /dev/null
+++ b/Lessons/Lesson_16/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/Lessons/Lesson_16/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf b/Lessons/Lesson_16/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
new file mode 100644
index 0000000..777010d
--- /dev/null
+++ b/Lessons/Lesson_16/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/Lessons/Lesson_16/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c b/Lessons/Lesson_16/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
new file mode 100644
index 0000000..7f6b58c
--- /dev/null
+++ b/Lessons/Lesson_16/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
@@ -0,0 +1,93 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+
+
+EFI_STATUS
+GetNvramVariable( CHAR16 *VariableName,
+ EFI_GUID *VariableOwnerGuid,
+ VOID **Buffer,
+ UINTN *BufferSize)
+{
+ UINTN Size = 0;
+ *BufferSize = 0;
+
+ EFI_STATUS Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Print(L"Error! 'gRT->GetVariable' call returned %r\n", Status);
+ return Status;
+ }
+
+ *Buffer = AllocateZeroPool(Size);
+ if (!Buffer) {
+ Print(L"Error! 'AllocateZeroPool' call returned %r\n", Status);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, *Buffer);
+ if (Status == EFI_SUCCESS) {
+ *BufferSize = Size;
+ } else {
+ FreePool( *Buffer );
+ *Buffer = NULL;
+ }
+
+ return Status;
+}
+
+
+VOID PrintBootOption(CHAR16* BootOptionName)
+{
+ UINTN OptionSize;
+ UINT8* Buffer;
+
+ EFI_STATUS Status = GetNvramVariable(BootOptionName, &gEfiGlobalVariableGuid, (VOID**)&Buffer, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ EFI_LOAD_OPTION* LoadOption = (EFI_LOAD_OPTION*) Buffer;
+ CHAR16* Description = (CHAR16*)(Buffer + sizeof (EFI_LOAD_OPTION));
+ UINTN DescriptionSize = StrSize(Description);
+
+ Print(L"%s\n", Description);
+ if (LoadOption->FilePathListLength != 0) {
+ VOID* FilePathList = (UINT8 *)Description + DescriptionSize;
+ CHAR16* DevPathString = ConvertDevicePathToText(FilePathList, TRUE, FALSE);
+ Print(L"%s\n", DevPathString);
+ }
+ } else {
+ Print(L"Can't get %s variable\n", BootOptionName);
+ }
+}
+
+
+INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
+{
+ UINTN OptionSize;
+ EFI_STATUS Status;
+
+ UINT16* BootCurrent;
+ Status = GetNvramVariable(L"BootCurrent", &gEfiGlobalVariableGuid, (VOID**)&BootCurrent, &OptionSize);
+ if (Status != EFI_SUCCESS) {
+ Print(L"Can't get BootCurrent variable\n");
+ }
+
+ UINT16* BootOrderArray;
+ Status = GetNvramVariable(L"BootOrder", &gEfiGlobalVariableGuid, (VOID**)&BootOrderArray, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ for (UINTN i=0; i<(OptionSize/sizeof(UINT16)); i++) {
+ CHAR16 BootOptionStr[sizeof("Boot####")+1];
+ UnicodeSPrint(BootOptionStr, (sizeof("Boot####")+1)*sizeof(CHAR16), L"Boot%04x", BootOrderArray[i]);
+ Print(L"%s%s\n", BootOptionStr, (BootOrderArray[i] == *BootCurrent)? L"*" : L"" );
+ PrintBootOption(BootOptionStr);
+ Print(L"\n");
+ }
+ } else {
+ Print(L"Can't get BootOrder variable\n");
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_16/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf b/Lessons/Lesson_16/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
new file mode 100644
index 0000000..d2cfba9
--- /dev/null
+++ b/Lessons/Lesson_16/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
@@ -0,0 +1,19 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = ShowBootVariables
+ FILE_GUID = 31266d12-9c60-478e-905e-05d117a3a9df
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+[Sources]
+ ShowBootVariables.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ ShellCEntryLib
+
diff --git a/Lessons/Lesson_16/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c b/Lessons/Lesson_16/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c
new file mode 100644
index 0000000..b13aa6c
--- /dev/null
+++ b/Lessons/Lesson_16/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/Lessons/Lesson_16/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf b/Lessons/Lesson_16/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf
new file mode 100644
index 0000000..013bf4e
--- /dev/null
+++ b/Lessons/Lesson_16/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/Lessons/Lesson_16/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_16/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_16/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/Lessons/Lesson_16/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_16/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_16/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/Lessons/Lesson_16/UefiLessonsPkg/UefiLessonsPkg.dec b/Lessons/Lesson_16/UefiLessonsPkg/UefiLessonsPkg.dec
new file mode 100644
index 0000000..d37e955
--- /dev/null
+++ b/Lessons/Lesson_16/UefiLessonsPkg/UefiLessonsPkg.dec
@@ -0,0 +1,22 @@
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = UefiLessonsPkg
+ PACKAGE_GUID = 7e7edbba-ca2c-4177-a3f0-d3371358773a
+ PACKAGE_VERSION = 1.01
+
+[Includes]
+
+[LibraryClasses]
+
+[Guids]
+ # FILE_GUID as defined in UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ gHelloWorldFileGuid = {0x2e55fa38, 0xf148, 0x42d3, {0xaf, 0x90, 0x1b, 0xe2, 0x47, 0x32, 0x3e, 0x30}}
+
+[Protocols]
+
+[PcdsFeatureFlag]
+
+[PcdsFixedAtBuild]
+
+[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
+
diff --git a/Lessons/Lesson_16/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_16/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..5a3ae1c
--- /dev/null
+++ b/Lessons/Lesson_16/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,36 @@
+[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
+ UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
+
diff --git a/Lessons/Lesson_17/BootManager.png b/Lessons/Lesson_17/BootManager.png
new file mode 100644
index 0000000..715b357
--- /dev/null
+++ b/Lessons/Lesson_17/BootManager.png
Binary files differ
diff --git a/Lessons/Lesson_17/Conf/target.txt b/Lessons/Lesson_17/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lessons/Lesson_17/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/Lessons/Lesson_17/README.md b/Lessons/Lesson_17/README.md
new file mode 100644
index 0000000..6dd3ed6
--- /dev/null
+++ b/Lessons/Lesson_17/README.md
@@ -0,0 +1,91 @@
+In the last lesson we've added our own boot option.
+
+Let's boot it.
+
+Type `exit` in the UEFI shell to go to the BIOS menu:
+```
+Shell> exit
+```
+Navigate to the `Boot Manager` window. Our `HelloWorld` option would be present here:
+![Boot Manager](BootManager.png?raw=true "Boot manager")
+
+If you'll try to boot it, app would print its strings and immediately return.
+
+Let's fix it. Let's add wait for a key input from user in our app code.
+To do it we will need `WaitForEvent` blocking function:
+
+```
+EFI_BOOT_SERVICES.WaitForEvent()
+
+Summary
+Stops execution until an event is signaled.
+
+Prototype
+typedef
+
+EFI_STATUS
+(EFIAPI *EFI_WAIT_FOR_EVENT) (
+ IN UINTN NumberOfEvents,
+ IN EFI_EVENT *Event,
+ OUT UINTN *Index
+);
+
+Parameters
+NumberOfEvents The number of events in the Event array.
+Event An array of EFI_EVENT.
+Index Pointer to the index of the event which satisfied the wait condition.
+```
+
+To our task we should use `EFI_EVENT WaitForKey` from the `EFI_SIMPLE_TEXT_INPUT_PROTOCOL` (which is placed in a `gST->ConIn`)
+```
+typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL {
+ EFI_INPUT_RESET Reset;
+ EFI_INPUT_READ_KEY ReadKeyStroke;
+ EFI_EVENT WaitForKey;
+} EFI_SIMPLE_TEXT_INPUT_PROTOCOL;
+```
+
+Now when we now all this API add this code to the end of the `HelloWorld` app main function:
+```
+UINTN Index;
+gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
+```
+
+Compile OVMF again and try to boot our `HelloWorld` boot option through the `Boot Manager` BIOS menu.
+Now output of the app stops and waits for the user keystroke.
+
+Everything works fine except a fact that if we choose `Enter` as our keystroke, `HelloWorld` app would be immediately launched again.
+
+This happens because we didn't read or clear the input buffer. As we don't need keystroke information let's simply reset it with a `Reset` function:
+```
+EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset()
+
+Summary:
+Resets the input device hardware.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INPUT_RESET) (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+Parameters:
+This A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.
+ExtendedVerification Indicates that the driver may perform a more exhaustive verification
+ operation of the device during reset.
+
+Description:
+The Reset() function resets the input device hardware.
+The implementation of Reset is required to clear the contents of any input queues resident in memory
+used for buffering keystroke data and put the input stream in a known empty state
+```
+
+Add this to the end of our app:
+```
+gST->ConIn->Reset(gST->ConIn, FALSE);
+```
+
+Now if we boot our app from the `Boot Manager` BIOS menu it would work correctly for any keystroke.
+
diff --git a/Lessons/Lesson_17/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_17/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..29a4812
--- /dev/null
+++ b/Lessons/Lesson_17/UefiLessonsPkg/HelloWorld/HelloWorld.c
@@ -0,0 +1,19 @@
+#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");
+
+ UINTN Index;
+ gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
+ gST->ConIn->Reset(gST->ConIn, FALSE);
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_17/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_17/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_17/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/Lessons/Lesson_17/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_17/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..32e9c43
--- /dev/null
+++ b/Lessons/Lesson_17/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/Lessons/Lesson_17/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_17/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_17/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/Lessons/Lesson_17/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lessons/Lesson_17/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lessons/Lesson_17/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/Lessons/Lesson_17/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_17/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lessons/Lesson_17/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/Lessons/Lesson_17/UefiLessonsPkg/ListVariables/ListVariables.c b/Lessons/Lesson_17/UefiLessonsPkg/ListVariables/ListVariables.c
new file mode 100644
index 0000000..1f3ef4a
--- /dev/null
+++ b/Lessons/Lesson_17/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/Lessons/Lesson_17/UefiLessonsPkg/ListVariables/ListVariables.inf b/Lessons/Lesson_17/UefiLessonsPkg/ListVariables/ListVariables.inf
new file mode 100644
index 0000000..14e9fa2
--- /dev/null
+++ b/Lessons/Lesson_17/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/Lessons/Lesson_17/UefiLessonsPkg/MemoryInfo/MemoryInfo.c b/Lessons/Lesson_17/UefiLessonsPkg/MemoryInfo/MemoryInfo.c
new file mode 100644
index 0000000..8c3bcf2
--- /dev/null
+++ b/Lessons/Lesson_17/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/Lessons/Lesson_17/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf b/Lessons/Lesson_17/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
new file mode 100644
index 0000000..777010d
--- /dev/null
+++ b/Lessons/Lesson_17/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/Lessons/Lesson_17/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c b/Lessons/Lesson_17/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
new file mode 100644
index 0000000..7f6b58c
--- /dev/null
+++ b/Lessons/Lesson_17/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
@@ -0,0 +1,93 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+
+
+EFI_STATUS
+GetNvramVariable( CHAR16 *VariableName,
+ EFI_GUID *VariableOwnerGuid,
+ VOID **Buffer,
+ UINTN *BufferSize)
+{
+ UINTN Size = 0;
+ *BufferSize = 0;
+
+ EFI_STATUS Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Print(L"Error! 'gRT->GetVariable' call returned %r\n", Status);
+ return Status;
+ }
+
+ *Buffer = AllocateZeroPool(Size);
+ if (!Buffer) {
+ Print(L"Error! 'AllocateZeroPool' call returned %r\n", Status);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, *Buffer);
+ if (Status == EFI_SUCCESS) {
+ *BufferSize = Size;
+ } else {
+ FreePool( *Buffer );
+ *Buffer = NULL;
+ }
+
+ return Status;
+}
+
+
+VOID PrintBootOption(CHAR16* BootOptionName)
+{
+ UINTN OptionSize;
+ UINT8* Buffer;
+
+ EFI_STATUS Status = GetNvramVariable(BootOptionName, &gEfiGlobalVariableGuid, (VOID**)&Buffer, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ EFI_LOAD_OPTION* LoadOption = (EFI_LOAD_OPTION*) Buffer;
+ CHAR16* Description = (CHAR16*)(Buffer + sizeof (EFI_LOAD_OPTION));
+ UINTN DescriptionSize = StrSize(Description);
+
+ Print(L"%s\n", Description);
+ if (LoadOption->FilePathListLength != 0) {
+ VOID* FilePathList = (UINT8 *)Description + DescriptionSize;
+ CHAR16* DevPathString = ConvertDevicePathToText(FilePathList, TRUE, FALSE);
+ Print(L"%s\n", DevPathString);
+ }
+ } else {
+ Print(L"Can't get %s variable\n", BootOptionName);
+ }
+}
+
+
+INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
+{
+ UINTN OptionSize;
+ EFI_STATUS Status;
+
+ UINT16* BootCurrent;
+ Status = GetNvramVariable(L"BootCurrent", &gEfiGlobalVariableGuid, (VOID**)&BootCurrent, &OptionSize);
+ if (Status != EFI_SUCCESS) {
+ Print(L"Can't get BootCurrent variable\n");
+ }
+
+ UINT16* BootOrderArray;
+ Status = GetNvramVariable(L"BootOrder", &gEfiGlobalVariableGuid, (VOID**)&BootOrderArray, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ for (UINTN i=0; i<(OptionSize/sizeof(UINT16)); i++) {
+ CHAR16 BootOptionStr[sizeof("Boot####")+1];
+ UnicodeSPrint(BootOptionStr, (sizeof("Boot####")+1)*sizeof(CHAR16), L"Boot%04x", BootOrderArray[i]);
+ Print(L"%s%s\n", BootOptionStr, (BootOrderArray[i] == *BootCurrent)? L"*" : L"" );
+ PrintBootOption(BootOptionStr);
+ Print(L"\n");
+ }
+ } else {
+ Print(L"Can't get BootOrder variable\n");
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_17/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf b/Lessons/Lesson_17/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
new file mode 100644
index 0000000..d2cfba9
--- /dev/null
+++ b/Lessons/Lesson_17/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
@@ -0,0 +1,19 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = ShowBootVariables
+ FILE_GUID = 31266d12-9c60-478e-905e-05d117a3a9df
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+[Sources]
+ ShowBootVariables.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ ShellCEntryLib
+
diff --git a/Lessons/Lesson_17/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c b/Lessons/Lesson_17/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c
new file mode 100644
index 0000000..b13aa6c
--- /dev/null
+++ b/Lessons/Lesson_17/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/Lessons/Lesson_17/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf b/Lessons/Lesson_17/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf
new file mode 100644
index 0000000..013bf4e
--- /dev/null
+++ b/Lessons/Lesson_17/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/Lessons/Lesson_17/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_17/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_17/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/Lessons/Lesson_17/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_17/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_17/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/Lessons/Lesson_17/UefiLessonsPkg/UefiLessonsPkg.dec b/Lessons/Lesson_17/UefiLessonsPkg/UefiLessonsPkg.dec
new file mode 100644
index 0000000..d37e955
--- /dev/null
+++ b/Lessons/Lesson_17/UefiLessonsPkg/UefiLessonsPkg.dec
@@ -0,0 +1,22 @@
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = UefiLessonsPkg
+ PACKAGE_GUID = 7e7edbba-ca2c-4177-a3f0-d3371358773a
+ PACKAGE_VERSION = 1.01
+
+[Includes]
+
+[LibraryClasses]
+
+[Guids]
+ # FILE_GUID as defined in UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ gHelloWorldFileGuid = {0x2e55fa38, 0xf148, 0x42d3, {0xaf, 0x90, 0x1b, 0xe2, 0x47, 0x32, 0x3e, 0x30}}
+
+[Protocols]
+
+[PcdsFeatureFlag]
+
+[PcdsFixedAtBuild]
+
+[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
+
diff --git a/Lessons/Lesson_17/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_17/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..5a3ae1c
--- /dev/null
+++ b/Lessons/Lesson_17/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,36 @@
+[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
+ UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
+
diff --git a/Lessons/Lesson_18/Conf/target.txt b/Lessons/Lesson_18/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lessons/Lesson_18/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/Lessons/Lesson_18/README.md b/Lessons/Lesson_18/README.md
new file mode 100644
index 0000000..228b311
--- /dev/null
+++ b/Lessons/Lesson_18/README.md
@@ -0,0 +1,116 @@
+
+Let's create an app that can actually handle input from user.
+
+To do this we will need `ReadKeyStroke` function:
+```
+EFI_SIMPLE_TEXT_INPUT_PROTOCOL.ReadKeyStroke()
+
+Summary:
+Reads the next keystroke from the input device.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_INPUT_READ_KEY) (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ );
+
+Parameters:
+This A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL instance.
+Key A pointer to a buffer that is filled in with the keystroke information
+ for the key that was pressed.
+
+Description:
+The ReadKeyStroke() function reads the next keystroke from the input device.
+
+Status Codes Returned:
+EFI_SUCCESS The keystroke information was returned.
+EFI_NOT_READY There was no keystroke data available.
+EFI_DEVICE_ERROR The keystroke information was not returned due to hardware errors.
+```
+
+The `EFI_INPUT_KEY` function is defined like this:
+```
+typedef struct {
+ UINT16 ScanCode;
+ CHAR16 UnicodeChar;
+} EFI_INPUT_KEY;
+```
+
+
+Create `InteractiveApp` with the following code:
+```
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ UINTN Index;
+ EFI_INPUT_KEY Key;
+
+ Print(L"Try to guess the secret symbol!\n");
+ Print(L"To quit press 'q'\n");
+
+ while(TRUE) {
+ gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
+ gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
+ Print(L"ScanCode = %04x, UnicodeChar = %04x (%c)\n", Key.ScanCode, Key.UnicodeChar, Key.UnicodeChar);
+
+ if (Key.UnicodeChar == 'k') {
+ Print(L"Correct!\n");
+ break;
+ } else if (Key.UnicodeChar == 'q') {
+ Print(L"Bye!\n");
+ break;
+ } else {
+ Print(L"Wrong!\n");
+ }
+ }
+ gST->ConIn->Reset(gST->ConIn, FALSE);
+ return EFI_SUCCESS;
+}
+```
+
+The code is pretty simple, so I hope no detailed explanation is needed.
+App asks for the secret symbol and loops until user presses the correct one ('k'), or presses 'q'.
+
+```
+FS0:\> InteractiveApp.efi
+Try to guess the secret symbol!
+To quit press 'q'
+ScanCode = 0000, UnicodeChar = 0066 (f)
+Wrong!
+ScanCode = 0000, UnicodeChar = 0074 (t)
+Wrong!
+ScanCode = 0000, UnicodeChar = 0073 (s)
+Wrong!
+ScanCode = 0000, UnicodeChar = 0069 (i)
+Wrong!
+ScanCode = 0000, UnicodeChar = 0061 (a)
+Wrong!
+ScanCode = 0000, UnicodeChar = 006E (n)
+Wrong!
+ScanCode = 0000, UnicodeChar = 006B (k)
+Correct!
+FS0:\>
+```
+
+With this app you can also look at how special keys are handled.
+This is the output from "PageUp" key:
+```
+ScanCode = 0017, UnicodeChar = 0000 ( )
+Wrong!
+ScanCode = 0000, UnicodeChar = 005B ([)
+Wrong!
+ScanCode = 0000, UnicodeChar = 0035 (5)
+Wrong!
+ScanCode = 0000, UnicodeChar = 007E (~)
+Wrong!
+```
+
diff --git a/Lessons/Lesson_18/UefiLessonsPkg/GOPInfo/GOPInfo.c b/Lessons/Lesson_18/UefiLessonsPkg/GOPInfo/GOPInfo.c
new file mode 100644
index 0000000..b13aa6c
--- /dev/null
+++ b/Lessons/Lesson_18/UefiLessonsPkg/GOPInfo/GOPInfo.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/Lessons/Lesson_18/UefiLessonsPkg/GOPInfo/GOPInfo.inf b/Lessons/Lesson_18/UefiLessonsPkg/GOPInfo/GOPInfo.inf
new file mode 100644
index 0000000..9bdd773
--- /dev/null
+++ b/Lessons/Lesson_18/UefiLessonsPkg/GOPInfo/GOPInfo.inf
@@ -0,0 +1,19 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = GOPInfo
+ FILE_GUID = 30f6fe85-328a-4d05-b154-58b54c335797
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+[Sources]
+ GOPInfo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ ShellCEntryLib
+
diff --git a/Lessons/Lesson_18/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_18/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..29a4812
--- /dev/null
+++ b/Lessons/Lesson_18/UefiLessonsPkg/HelloWorld/HelloWorld.c
@@ -0,0 +1,19 @@
+#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");
+
+ UINTN Index;
+ gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
+ gST->ConIn->Reset(gST->ConIn, FALSE);
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_18/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_18/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_18/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/Lessons/Lesson_18/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_18/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..32e9c43
--- /dev/null
+++ b/Lessons/Lesson_18/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/Lessons/Lesson_18/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_18/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_18/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/Lessons/Lesson_18/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lessons/Lesson_18/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lessons/Lesson_18/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/Lessons/Lesson_18/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_18/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lessons/Lesson_18/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/Lessons/Lesson_18/UefiLessonsPkg/InteractiveApp/InteractiveApp.c b/Lessons/Lesson_18/UefiLessonsPkg/InteractiveApp/InteractiveApp.c
new file mode 100644
index 0000000..59c89a9
--- /dev/null
+++ b/Lessons/Lesson_18/UefiLessonsPkg/InteractiveApp/InteractiveApp.c
@@ -0,0 +1,34 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ UINTN Index;
+ EFI_INPUT_KEY Key;
+
+ Print(L"Try to guess the secret symbol!\n");
+ Print(L"To quit press 'q'\n");
+
+ while(TRUE) {
+ gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
+ gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
+ Print(L"ScanCode = %04x, UnicodeChar = %04x (%c)\n", Key.ScanCode, Key.UnicodeChar, Key.UnicodeChar);
+
+ if (Key.UnicodeChar == 'k') {
+ Print(L"Correct!\n");
+ break;
+ } else if (Key.UnicodeChar == 'q') {
+ Print(L"Bye!\n");
+ break;
+ } else {
+ Print(L"Wrong!\n");
+ }
+ }
+ gST->ConIn->Reset(gST->ConIn, FALSE);
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_18/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf b/Lessons/Lesson_18/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
new file mode 100644
index 0000000..700b779
--- /dev/null
+++ b/Lessons/Lesson_18/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
@@ -0,0 +1,18 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = InteractiveApp
+ FILE_GUID = 1539451b-f300-41fa-a565-dde69c1bed66
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ InteractiveApp.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
diff --git a/Lessons/Lesson_18/UefiLessonsPkg/ListVariables/ListVariables.c b/Lessons/Lesson_18/UefiLessonsPkg/ListVariables/ListVariables.c
new file mode 100644
index 0000000..1f3ef4a
--- /dev/null
+++ b/Lessons/Lesson_18/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/Lessons/Lesson_18/UefiLessonsPkg/ListVariables/ListVariables.inf b/Lessons/Lesson_18/UefiLessonsPkg/ListVariables/ListVariables.inf
new file mode 100644
index 0000000..14e9fa2
--- /dev/null
+++ b/Lessons/Lesson_18/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/Lessons/Lesson_18/UefiLessonsPkg/MemoryInfo/MemoryInfo.c b/Lessons/Lesson_18/UefiLessonsPkg/MemoryInfo/MemoryInfo.c
new file mode 100644
index 0000000..8c3bcf2
--- /dev/null
+++ b/Lessons/Lesson_18/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/Lessons/Lesson_18/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf b/Lessons/Lesson_18/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
new file mode 100644
index 0000000..777010d
--- /dev/null
+++ b/Lessons/Lesson_18/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/Lessons/Lesson_18/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c b/Lessons/Lesson_18/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
new file mode 100644
index 0000000..7f6b58c
--- /dev/null
+++ b/Lessons/Lesson_18/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
@@ -0,0 +1,93 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+
+
+EFI_STATUS
+GetNvramVariable( CHAR16 *VariableName,
+ EFI_GUID *VariableOwnerGuid,
+ VOID **Buffer,
+ UINTN *BufferSize)
+{
+ UINTN Size = 0;
+ *BufferSize = 0;
+
+ EFI_STATUS Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Print(L"Error! 'gRT->GetVariable' call returned %r\n", Status);
+ return Status;
+ }
+
+ *Buffer = AllocateZeroPool(Size);
+ if (!Buffer) {
+ Print(L"Error! 'AllocateZeroPool' call returned %r\n", Status);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, *Buffer);
+ if (Status == EFI_SUCCESS) {
+ *BufferSize = Size;
+ } else {
+ FreePool( *Buffer );
+ *Buffer = NULL;
+ }
+
+ return Status;
+}
+
+
+VOID PrintBootOption(CHAR16* BootOptionName)
+{
+ UINTN OptionSize;
+ UINT8* Buffer;
+
+ EFI_STATUS Status = GetNvramVariable(BootOptionName, &gEfiGlobalVariableGuid, (VOID**)&Buffer, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ EFI_LOAD_OPTION* LoadOption = (EFI_LOAD_OPTION*) Buffer;
+ CHAR16* Description = (CHAR16*)(Buffer + sizeof (EFI_LOAD_OPTION));
+ UINTN DescriptionSize = StrSize(Description);
+
+ Print(L"%s\n", Description);
+ if (LoadOption->FilePathListLength != 0) {
+ VOID* FilePathList = (UINT8 *)Description + DescriptionSize;
+ CHAR16* DevPathString = ConvertDevicePathToText(FilePathList, TRUE, FALSE);
+ Print(L"%s\n", DevPathString);
+ }
+ } else {
+ Print(L"Can't get %s variable\n", BootOptionName);
+ }
+}
+
+
+INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
+{
+ UINTN OptionSize;
+ EFI_STATUS Status;
+
+ UINT16* BootCurrent;
+ Status = GetNvramVariable(L"BootCurrent", &gEfiGlobalVariableGuid, (VOID**)&BootCurrent, &OptionSize);
+ if (Status != EFI_SUCCESS) {
+ Print(L"Can't get BootCurrent variable\n");
+ }
+
+ UINT16* BootOrderArray;
+ Status = GetNvramVariable(L"BootOrder", &gEfiGlobalVariableGuid, (VOID**)&BootOrderArray, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ for (UINTN i=0; i<(OptionSize/sizeof(UINT16)); i++) {
+ CHAR16 BootOptionStr[sizeof("Boot####")+1];
+ UnicodeSPrint(BootOptionStr, (sizeof("Boot####")+1)*sizeof(CHAR16), L"Boot%04x", BootOrderArray[i]);
+ Print(L"%s%s\n", BootOptionStr, (BootOrderArray[i] == *BootCurrent)? L"*" : L"" );
+ PrintBootOption(BootOptionStr);
+ Print(L"\n");
+ }
+ } else {
+ Print(L"Can't get BootOrder variable\n");
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_18/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf b/Lessons/Lesson_18/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
new file mode 100644
index 0000000..d2cfba9
--- /dev/null
+++ b/Lessons/Lesson_18/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
@@ -0,0 +1,19 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = ShowBootVariables
+ FILE_GUID = 31266d12-9c60-478e-905e-05d117a3a9df
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+[Sources]
+ ShowBootVariables.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ ShellCEntryLib
+
diff --git a/Lessons/Lesson_18/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c b/Lessons/Lesson_18/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c
new file mode 100644
index 0000000..b13aa6c
--- /dev/null
+++ b/Lessons/Lesson_18/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/Lessons/Lesson_18/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf b/Lessons/Lesson_18/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf
new file mode 100644
index 0000000..013bf4e
--- /dev/null
+++ b/Lessons/Lesson_18/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/Lessons/Lesson_18/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_18/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_18/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/Lessons/Lesson_18/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_18/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_18/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/Lessons/Lesson_18/UefiLessonsPkg/UefiLessonsPkg.dec b/Lessons/Lesson_18/UefiLessonsPkg/UefiLessonsPkg.dec
new file mode 100644
index 0000000..d37e955
--- /dev/null
+++ b/Lessons/Lesson_18/UefiLessonsPkg/UefiLessonsPkg.dec
@@ -0,0 +1,22 @@
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = UefiLessonsPkg
+ PACKAGE_GUID = 7e7edbba-ca2c-4177-a3f0-d3371358773a
+ PACKAGE_VERSION = 1.01
+
+[Includes]
+
+[LibraryClasses]
+
+[Guids]
+ # FILE_GUID as defined in UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ gHelloWorldFileGuid = {0x2e55fa38, 0xf148, 0x42d3, {0xaf, 0x90, 0x1b, 0xe2, 0x47, 0x32, 0x3e, 0x30}}
+
+[Protocols]
+
+[PcdsFeatureFlag]
+
+[PcdsFixedAtBuild]
+
+[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
+
diff --git a/Lessons/Lesson_18/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_18/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..616ccee
--- /dev/null
+++ b/Lessons/Lesson_18/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,37 @@
+[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
+ UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
+ UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
+
diff --git a/Lessons/Lesson_19/BootManager.png b/Lessons/Lesson_19/BootManager.png
new file mode 100644
index 0000000..30e4885
--- /dev/null
+++ b/Lessons/Lesson_19/BootManager.png
Binary files differ
diff --git a/Lessons/Lesson_19/Conf/target.txt b/Lessons/Lesson_19/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lessons/Lesson_19/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/Lessons/Lesson_19/README.md b/Lessons/Lesson_19/README.md
new file mode 100644
index 0000000..65e5cb2
--- /dev/null
+++ b/Lessons/Lesson_19/README.md
@@ -0,0 +1,186 @@
+In this lesson we would be messing with the NVRAM variables (BIOS settings), i.e. variables that are persistent between boots.
+
+As you remember after OVMF build we have these files:
+```
+$ ls -l Build/OvmfX64/RELEASE_GCC5/FV/OVMF*
+-rw-r--r-- 1 kostr kostr 4194304 Jun 25 14:40 Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd
+-rw-r--r-- 1 kostr kostr 3653632 Jun 25 14:40 Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd
+-rw-r--r-- 1 kostr kostr 540672 Jun 25 14:38 Build/OvmfX64/RELEASE_GCC5/FV/OVMF_VARS.fd
+```
+- `OVMF_CODE.fd` - code image (read-only)
+- `OVMF_VARS.fd` - NVRAM variables image (read-write)
+- `OVMF.fd` - combined image (`OVMF_CODE.fd` + `OVMF_VARS.fd`)
+
+We can boot QEMU either with:
+```
+$ qemu-system-x86_64 -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
+ ...
+```
+or with
+```
+$ qemu-system-x86_64 -drive if=pflash,format=raw,readonly,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd \
+ -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF_VARS.fd \
+ ...
+```
+
+It was fine to use short form earlier, but in this lesson we would modify NVRAM variables, so it is best to use full form with a separate copy of `OVMF_VARS.fd`, so you could always revert things to their initial state.
+
+Let's undo our modifications to the `OvmfPkg` package and rebuild it:
+```
+$ git restore OvmfPkg
+$ build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5
+```
+
+After that create a backup copy of `OVMF_VARS.fd` and run QEMU with it:
+```
+$ cp Build/OvmfX64/RELEASE_GCC5/FV/OVMF_VARS.fd ../
+$ qemu-system-x86_64 -drive if=pflash,format=raw,readonly,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd \
+ -drive if=pflash,format=raw,file=../OVMF_VARS.fd \
+ -drive format=raw,file=fat:rw:~/UEFI_disk \
+ -nographic \
+ -net none
+```
+
+Check boot variables with the help of `bcfg boot dump`:
+```
+Shell> bcfg boot dump
+Option: 00. Variable: Boot0000
+ Desc - UiApp
+ DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(462CAA21-7614-4503-836E-8AB6F4662331)
+ OVMF_VARS.fdiOptional- N
+Option: 01. Variable: Boot0001
+ Desc - UEFI QEMU DVD-ROM QM00003
+ DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ Optional- Y
+Option: 02. Variable: Boot0002
+ Desc - UEFI QEMU HARDDISK QM00001
+ DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ Optional- Y
+Option: 03. Variable: Boot0003
+ Desc - EFI Internal Shell
+ DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
+ Optional- N
+```
+
+Besides showing boot options `bcfg` command can add/remove boot options or change their order.
+You can check out help for `bcfg` via:
+```
+bcfg -? -b
+```
+
+Now let's try to add our `InteractiveApp.efi` to the boot options.
+
+```
+Shell> fs0:
+FS0:\> bcfg boot add 4 InteractiveApp.efi "Interactive app"
+Target = 0004.
+bcfg: Add Boot0004 as 4
+FS0:\> bcfg boot dump
+Option: 00. Variable: Boot0000
+ Desc - UiApp
+ DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(462CAA21-7614-4503-836E-8AB6F4662331)
+ Optional- N
+Option: 01. Variable: Boot0001
+ Desc - UEFI QEMU DVD-ROM QM00003
+ DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ Optional- Y
+Option: 02. Variable: Boot0002
+ Desc - UEFI QEMU HARDDISK QM00001
+ DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ Optional- Y
+Option: 03. Variable: Boot0003
+ Desc - EFI Internal Shell
+ DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
+ Optional- N
+Option: 04. Variable: Boot0004
+ Desc - Interactive app
+ DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)/\InteractiveApp.efi
+ Optional- N
+```
+
+Now if you navigate to the `Boot Manager` you'll see our app:
+![Boot Manager](BootManager.png?raw=true "Boot manager")
+
+As soon as you don't change `OVMF_VARS.fd` this option would be present even between QEMU restarts.
+
+We can go further and even place our app as a first boot source:
+```
+Shell> bcfg boot mv 4 0
+Shell> bcfg boot dump
+Option: 00. Variable: Boot0004
+ Desc - Interactive app
+ DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)/\InteractiveApp.efi
+ Optional- N
+Option: 01. Variable: Boot0000
+ Desc - UiApp
+ DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(462CAA21-7614-4503-836E-8AB6F4662331)
+ Optional- N
+Option: 02. Variable: Boot0001
+ Desc - UEFI QEMU DVD-ROM QM00003
+ DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ Optional- Y
+Option: 03. Variable: Boot0002
+ Desc - UEFI QEMU HARDDISK QM00001
+ DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ Optional- Y
+Option: 04. Variable: Boot0003
+ Desc - EFI Internal Shell
+ DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
+ Optional- N
+```
+
+Now if you reboot UEFI shell with a `reset` command, or rerun QEMU, you will need to pass our app before you can go to the BIOS menu:
+```
+BdsDxe: loading Boot0004 "Interactive app" from PciRoot(0x0)/Pci(0x1,0x1)/Ata(Primary,Master,0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)/\InteractiveApp.efi
+BdsDxe: starting Boot0004 "Interactive app" from PciRoot(0x0)/Pci(0x1,0x1)/Ata(Primary,Master,0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)/\InteractiveApp.efi
+Try to guess the secret symbol!
+```
+
+Input correct symbol, go to the `Boot manager` menu and run UEFI shell so we could delete our app from the boot sources:
+```
+FS0:\> bcfg boot dump
+Option: 00. Variable: Boot0004
+ Desc - Interactive app
+ DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)/\InteractiveApp.efi
+ Optional- N
+Option: 01. Variable: Boot0000
+ Desc - UiApp
+ DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(462CAA21-7614-4503-836E-8AB6F4662331)
+ Optional- N
+Option: 02. Variable: Boot0001
+ Desc - UEFI QEMU DVD-ROM QM00003
+ DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ Optional- Y
+Option: 03. Variable: Boot0002
+ Desc - UEFI QEMU HARDDISK QM00001
+ DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ Optional- Y
+Option: 04. Variable: Boot0003
+ Desc - EFI Internal Shell
+ DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
+ Optional- N
+
+FS0:\> bcfg boot rm 0
+
+FS0:\> bcfg boot dump
+Option: 00. Variable: Boot0000
+ Desc - UiApp
+ DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(462CAA21-7614-4503-836E-8AB6F4662331)
+ Optional- N
+Option: 01. Variable: Boot0001
+ Desc - UEFI QEMU DVD-ROM QM00003
+ DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ Optional- Y
+Option: 02. Variable: Boot0002
+ Desc - UEFI QEMU HARDDISK QM00001
+ DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ Optional- Y
+Option: 03. Variable: Boot0003
+ Desc - EFI Internal Shell
+ DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
+ Optional- N
+```
+
+
+
+
diff --git a/Lessons/Lesson_19/UefiLessonsPkg/GOPInfo/GOPInfo.c b/Lessons/Lesson_19/UefiLessonsPkg/GOPInfo/GOPInfo.c
new file mode 100644
index 0000000..b13aa6c
--- /dev/null
+++ b/Lessons/Lesson_19/UefiLessonsPkg/GOPInfo/GOPInfo.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/Lessons/Lesson_19/UefiLessonsPkg/GOPInfo/GOPInfo.inf b/Lessons/Lesson_19/UefiLessonsPkg/GOPInfo/GOPInfo.inf
new file mode 100644
index 0000000..9bdd773
--- /dev/null
+++ b/Lessons/Lesson_19/UefiLessonsPkg/GOPInfo/GOPInfo.inf
@@ -0,0 +1,19 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = GOPInfo
+ FILE_GUID = 30f6fe85-328a-4d05-b154-58b54c335797
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+[Sources]
+ GOPInfo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ ShellCEntryLib
+
diff --git a/Lessons/Lesson_19/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_19/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..29a4812
--- /dev/null
+++ b/Lessons/Lesson_19/UefiLessonsPkg/HelloWorld/HelloWorld.c
@@ -0,0 +1,19 @@
+#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");
+
+ UINTN Index;
+ gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
+ gST->ConIn->Reset(gST->ConIn, FALSE);
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_19/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_19/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_19/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/Lessons/Lesson_19/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_19/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..32e9c43
--- /dev/null
+++ b/Lessons/Lesson_19/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/Lessons/Lesson_19/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_19/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_19/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/Lessons/Lesson_19/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lessons/Lesson_19/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lessons/Lesson_19/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/Lessons/Lesson_19/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_19/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lessons/Lesson_19/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/Lessons/Lesson_19/UefiLessonsPkg/InteractiveApp/InteractiveApp.c b/Lessons/Lesson_19/UefiLessonsPkg/InteractiveApp/InteractiveApp.c
new file mode 100644
index 0000000..59c89a9
--- /dev/null
+++ b/Lessons/Lesson_19/UefiLessonsPkg/InteractiveApp/InteractiveApp.c
@@ -0,0 +1,34 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ UINTN Index;
+ EFI_INPUT_KEY Key;
+
+ Print(L"Try to guess the secret symbol!\n");
+ Print(L"To quit press 'q'\n");
+
+ while(TRUE) {
+ gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
+ gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
+ Print(L"ScanCode = %04x, UnicodeChar = %04x (%c)\n", Key.ScanCode, Key.UnicodeChar, Key.UnicodeChar);
+
+ if (Key.UnicodeChar == 'k') {
+ Print(L"Correct!\n");
+ break;
+ } else if (Key.UnicodeChar == 'q') {
+ Print(L"Bye!\n");
+ break;
+ } else {
+ Print(L"Wrong!\n");
+ }
+ }
+ gST->ConIn->Reset(gST->ConIn, FALSE);
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_19/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf b/Lessons/Lesson_19/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
new file mode 100644
index 0000000..700b779
--- /dev/null
+++ b/Lessons/Lesson_19/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
@@ -0,0 +1,18 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = InteractiveApp
+ FILE_GUID = 1539451b-f300-41fa-a565-dde69c1bed66
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ InteractiveApp.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
diff --git a/Lessons/Lesson_19/UefiLessonsPkg/ListVariables/ListVariables.c b/Lessons/Lesson_19/UefiLessonsPkg/ListVariables/ListVariables.c
new file mode 100644
index 0000000..1f3ef4a
--- /dev/null
+++ b/Lessons/Lesson_19/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/Lessons/Lesson_19/UefiLessonsPkg/ListVariables/ListVariables.inf b/Lessons/Lesson_19/UefiLessonsPkg/ListVariables/ListVariables.inf
new file mode 100644
index 0000000..14e9fa2
--- /dev/null
+++ b/Lessons/Lesson_19/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/Lessons/Lesson_19/UefiLessonsPkg/MemoryInfo/MemoryInfo.c b/Lessons/Lesson_19/UefiLessonsPkg/MemoryInfo/MemoryInfo.c
new file mode 100644
index 0000000..8c3bcf2
--- /dev/null
+++ b/Lessons/Lesson_19/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/Lessons/Lesson_19/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf b/Lessons/Lesson_19/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
new file mode 100644
index 0000000..777010d
--- /dev/null
+++ b/Lessons/Lesson_19/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/Lessons/Lesson_19/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c b/Lessons/Lesson_19/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
new file mode 100644
index 0000000..7f6b58c
--- /dev/null
+++ b/Lessons/Lesson_19/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
@@ -0,0 +1,93 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+
+
+EFI_STATUS
+GetNvramVariable( CHAR16 *VariableName,
+ EFI_GUID *VariableOwnerGuid,
+ VOID **Buffer,
+ UINTN *BufferSize)
+{
+ UINTN Size = 0;
+ *BufferSize = 0;
+
+ EFI_STATUS Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Print(L"Error! 'gRT->GetVariable' call returned %r\n", Status);
+ return Status;
+ }
+
+ *Buffer = AllocateZeroPool(Size);
+ if (!Buffer) {
+ Print(L"Error! 'AllocateZeroPool' call returned %r\n", Status);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, *Buffer);
+ if (Status == EFI_SUCCESS) {
+ *BufferSize = Size;
+ } else {
+ FreePool( *Buffer );
+ *Buffer = NULL;
+ }
+
+ return Status;
+}
+
+
+VOID PrintBootOption(CHAR16* BootOptionName)
+{
+ UINTN OptionSize;
+ UINT8* Buffer;
+
+ EFI_STATUS Status = GetNvramVariable(BootOptionName, &gEfiGlobalVariableGuid, (VOID**)&Buffer, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ EFI_LOAD_OPTION* LoadOption = (EFI_LOAD_OPTION*) Buffer;
+ CHAR16* Description = (CHAR16*)(Buffer + sizeof (EFI_LOAD_OPTION));
+ UINTN DescriptionSize = StrSize(Description);
+
+ Print(L"%s\n", Description);
+ if (LoadOption->FilePathListLength != 0) {
+ VOID* FilePathList = (UINT8 *)Description + DescriptionSize;
+ CHAR16* DevPathString = ConvertDevicePathToText(FilePathList, TRUE, FALSE);
+ Print(L"%s\n", DevPathString);
+ }
+ } else {
+ Print(L"Can't get %s variable\n", BootOptionName);
+ }
+}
+
+
+INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
+{
+ UINTN OptionSize;
+ EFI_STATUS Status;
+
+ UINT16* BootCurrent;
+ Status = GetNvramVariable(L"BootCurrent", &gEfiGlobalVariableGuid, (VOID**)&BootCurrent, &OptionSize);
+ if (Status != EFI_SUCCESS) {
+ Print(L"Can't get BootCurrent variable\n");
+ }
+
+ UINT16* BootOrderArray;
+ Status = GetNvramVariable(L"BootOrder", &gEfiGlobalVariableGuid, (VOID**)&BootOrderArray, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ for (UINTN i=0; i<(OptionSize/sizeof(UINT16)); i++) {
+ CHAR16 BootOptionStr[sizeof("Boot####")+1];
+ UnicodeSPrint(BootOptionStr, (sizeof("Boot####")+1)*sizeof(CHAR16), L"Boot%04x", BootOrderArray[i]);
+ Print(L"%s%s\n", BootOptionStr, (BootOrderArray[i] == *BootCurrent)? L"*" : L"" );
+ PrintBootOption(BootOptionStr);
+ Print(L"\n");
+ }
+ } else {
+ Print(L"Can't get BootOrder variable\n");
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_19/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf b/Lessons/Lesson_19/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
new file mode 100644
index 0000000..d2cfba9
--- /dev/null
+++ b/Lessons/Lesson_19/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
@@ -0,0 +1,19 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = ShowBootVariables
+ FILE_GUID = 31266d12-9c60-478e-905e-05d117a3a9df
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+[Sources]
+ ShowBootVariables.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ ShellCEntryLib
+
diff --git a/Lessons/Lesson_19/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c b/Lessons/Lesson_19/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c
new file mode 100644
index 0000000..b13aa6c
--- /dev/null
+++ b/Lessons/Lesson_19/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/Lessons/Lesson_19/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf b/Lessons/Lesson_19/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf
new file mode 100644
index 0000000..013bf4e
--- /dev/null
+++ b/Lessons/Lesson_19/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/Lessons/Lesson_19/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_19/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_19/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/Lessons/Lesson_19/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_19/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_19/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/Lessons/Lesson_19/UefiLessonsPkg/UefiLessonsPkg.dec b/Lessons/Lesson_19/UefiLessonsPkg/UefiLessonsPkg.dec
new file mode 100644
index 0000000..d37e955
--- /dev/null
+++ b/Lessons/Lesson_19/UefiLessonsPkg/UefiLessonsPkg.dec
@@ -0,0 +1,22 @@
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = UefiLessonsPkg
+ PACKAGE_GUID = 7e7edbba-ca2c-4177-a3f0-d3371358773a
+ PACKAGE_VERSION = 1.01
+
+[Includes]
+
+[LibraryClasses]
+
+[Guids]
+ # FILE_GUID as defined in UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ gHelloWorldFileGuid = {0x2e55fa38, 0xf148, 0x42d3, {0xaf, 0x90, 0x1b, 0xe2, 0x47, 0x32, 0x3e, 0x30}}
+
+[Protocols]
+
+[PcdsFeatureFlag]
+
+[PcdsFixedAtBuild]
+
+[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
+
diff --git a/Lessons/Lesson_19/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_19/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..616ccee
--- /dev/null
+++ b/Lessons/Lesson_19/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,37 @@
+[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
+ UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
+ UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
+
diff --git a/Lessons/Lesson_20/Conf/target.txt b/Lessons/Lesson_20/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lessons/Lesson_20/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/Lessons/Lesson_20/README.md b/Lessons/Lesson_20/README.md
new file mode 100644
index 0000000..46a4c5b
--- /dev/null
+++ b/Lessons/Lesson_20/README.md
@@ -0,0 +1,108 @@
+The Platform Configuration Database (PCD) is a database that contains a variety of current platform settings or directives that can be accessed by a driver or application.
+
+You can checkout edk2 specification https://edk2-docs.gitbook.io/edk-ii-pcd-specification/ or https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/edkii-platform-config-database-entries-paper.pdf for more explanation on PCD.
+
+PCD entry is also called PCD, so we will use this term further.
+
+The PCD entry is defined in a DEC file in a format:
+```
+<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>
+```
+`<TokenSpaceGuidCName>` is a GUID value, `<Token>` is a 32-bit value. Together they are used to uniqely identify PCD.
+
+First let's declare a Token Space that would contain all our PCDs.
+Usually in is defined as a `g<PackageName>TokenSpaceGuid`, so add this to our `UefiLessonsPkg/UefiLessonsPkg.dec`:
+```
+[Guids]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid = {0x150cab53, 0xad47, 0x4385, {0xb5, 0xdd, 0xbc, 0xfc, 0x76, 0xba, 0xca, 0xf0}}
+```
+
+Now we can define our PCDs in the same *.dec file. Let's start with `UINT32 PcdMyVar32 = 42`:
+```
+[PcdsFixedAtBuild]
+ gEfiUefiLessonsPkgTokenSpaceGuid.PcdMyVar32|42|UINT32|0x00000001
+```
+
+Now create an app `PCDLesson` with the following code in its entry point function:
+```
+Print(L"PcdMyVar32=%d\n", FixedPcdGet32(PcdMyVar32));
+```
+To use `FixedPcdGet32` in our code we need to add the necessary include:
+```
+#include <Library/PcdLib.h>
+```
+If you check out this file (https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h) you'll see that `FixedPcdGet32` is simply a define statement:
+```
+#define FixedPcdGet32(TokenName) _PCD_VALUE_##TokenName
+```
+
+If we try to build our app now, build will fail, as we don't have such define in our app:
+```
+/home/kostr/tiano/edk2/MdePkg/Include/Library/PcdLib.h:97:45: error: ‘_PCD_VALUE_PcdMyVar32’ undeclared (first use in this function)
+ 97 | #define FixedPcdGet32(TokenName) _PCD_VALUE_##TokenName
+ | ^~~~~~~~~~~
+```
+
+To fix this we need to add this PCD to our app `*.inf` file:
+```
+[FixedPcd]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32
+```
+
+Also we need to include "dec" file that defines this PCD:
+```
+[Packages]
+ ...
+ UefiLessonsPkg/UefiLessonsPkg.dec
+```
+
+Now compilation would succeed.
+
+If you check out the content of autogenerated files `AutoGen.h`/`AutoGen.c`, you'll see, that our PCD is there.
+
+Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h
+```
+// Definition of PCDs used in this module
+
+#define _PCD_TOKEN_PcdMyVar32 0U
+#define _PCD_SIZE_PcdMyVar32 4
+#define _PCD_GET_MODE_SIZE_PcdMyVar32 _PCD_SIZE_PcdMyVar32
+#define _PCD_VALUE_PcdMyVar32 42U
+extern const UINT32 _gPcd_FixedAtBuild_PcdMyVar32;
+#define _PCD_GET_MODE_32_PcdMyVar32 _gPcd_FixedAtBuild_PcdMyVar32
+//#define _PCD_SET_MODE_32_PcdMyVar32 ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+```
+
+Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.c
+```
+// Definition of PCDs used in this module
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMyVar32 = _PCD_VALUE_PcdMyVar32;
+```
+
+So in our case preprocessor expands code like this:
+```
+FixedPcdGet32(PcdMyVar32) -> _PCD_VALUE_PcdMyVar32 -> 42U
+```
+
+If you execute app code under OVMF:
+```
+FS0:\> PCDLesson.efi
+PcdMyVar32=42
+```
+
+There are multiple types of PCDs. `FixedAtBuild` PCD is only one of them. In our code we've used `FixedPcdGet` call to get PCD value, this call would only work if PCD is `FixedAtBuild`. However there is a generic `PcdGet` call that can be used to get a value of PCD regardless its type.
+https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h:
+```
+#define PcdGet32(TokenName) _PCD_GET_MODE_32_##TokenName
+```
+
+In our case this would expand to:
+```
+PcdGet32(PcdMyVar32) -> _PCD_GET_MODE_32_PcdMyVar32 -> _gPcd_FixedAtBuild_PcdMyVar32
+```
+The latter one is a variable that is defined in a `AutoGen.c` file:
+```
+ GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMyVar32 = 42U;
+```
+So as you can see result would be the same. The difference is that `PcdGet` would work with other PCD types, that we would cover in the next lessons.
diff --git a/Lessons/Lesson_20/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_20/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..29a4812
--- /dev/null
+++ b/Lessons/Lesson_20/UefiLessonsPkg/HelloWorld/HelloWorld.c
@@ -0,0 +1,19 @@
+#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");
+
+ UINTN Index;
+ gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
+ gST->ConIn->Reset(gST->ConIn, FALSE);
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_20/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_20/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_20/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/Lessons/Lesson_20/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_20/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..32e9c43
--- /dev/null
+++ b/Lessons/Lesson_20/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/Lessons/Lesson_20/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_20/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_20/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/Lessons/Lesson_20/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lessons/Lesson_20/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lessons/Lesson_20/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/Lessons/Lesson_20/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_20/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lessons/Lesson_20/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/Lessons/Lesson_20/UefiLessonsPkg/InteractiveApp/InteractiveApp.c b/Lessons/Lesson_20/UefiLessonsPkg/InteractiveApp/InteractiveApp.c
new file mode 100644
index 0000000..59c89a9
--- /dev/null
+++ b/Lessons/Lesson_20/UefiLessonsPkg/InteractiveApp/InteractiveApp.c
@@ -0,0 +1,34 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ UINTN Index;
+ EFI_INPUT_KEY Key;
+
+ Print(L"Try to guess the secret symbol!\n");
+ Print(L"To quit press 'q'\n");
+
+ while(TRUE) {
+ gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
+ gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
+ Print(L"ScanCode = %04x, UnicodeChar = %04x (%c)\n", Key.ScanCode, Key.UnicodeChar, Key.UnicodeChar);
+
+ if (Key.UnicodeChar == 'k') {
+ Print(L"Correct!\n");
+ break;
+ } else if (Key.UnicodeChar == 'q') {
+ Print(L"Bye!\n");
+ break;
+ } else {
+ Print(L"Wrong!\n");
+ }
+ }
+ gST->ConIn->Reset(gST->ConIn, FALSE);
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_20/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf b/Lessons/Lesson_20/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
new file mode 100644
index 0000000..700b779
--- /dev/null
+++ b/Lessons/Lesson_20/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
@@ -0,0 +1,18 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = InteractiveApp
+ FILE_GUID = 1539451b-f300-41fa-a565-dde69c1bed66
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ InteractiveApp.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
diff --git a/Lessons/Lesson_20/UefiLessonsPkg/ListVariables/ListVariables.c b/Lessons/Lesson_20/UefiLessonsPkg/ListVariables/ListVariables.c
new file mode 100644
index 0000000..1f3ef4a
--- /dev/null
+++ b/Lessons/Lesson_20/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/Lessons/Lesson_20/UefiLessonsPkg/ListVariables/ListVariables.inf b/Lessons/Lesson_20/UefiLessonsPkg/ListVariables/ListVariables.inf
new file mode 100644
index 0000000..14e9fa2
--- /dev/null
+++ b/Lessons/Lesson_20/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/Lessons/Lesson_20/UefiLessonsPkg/MemoryInfo/MemoryInfo.c b/Lessons/Lesson_20/UefiLessonsPkg/MemoryInfo/MemoryInfo.c
new file mode 100644
index 0000000..8c3bcf2
--- /dev/null
+++ b/Lessons/Lesson_20/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/Lessons/Lesson_20/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf b/Lessons/Lesson_20/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
new file mode 100644
index 0000000..777010d
--- /dev/null
+++ b/Lessons/Lesson_20/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/Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.c b/Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.c
new file mode 100644
index 0000000..7ed3081
--- /dev/null
+++ b/Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.c
@@ -0,0 +1,15 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/PcdLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ Print(L"PcdMyVar32=%d\n", FixedPcdGet32(PcdMyVar32));
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.inf b/Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.inf
new file mode 100644
index 0000000..11dafe9
--- /dev/null
+++ b/Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.inf
@@ -0,0 +1,22 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = PCDLesson
+ FILE_GUID = 8c1a6b71-0c4b-4497-aaad-07404edf142c
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ PCDLesson.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiLessonsPkg/UefiLessonsPkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
+[FixedPcd]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32
+
diff --git a/Lessons/Lesson_20/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c b/Lessons/Lesson_20/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
new file mode 100644
index 0000000..7f6b58c
--- /dev/null
+++ b/Lessons/Lesson_20/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
@@ -0,0 +1,93 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+
+
+EFI_STATUS
+GetNvramVariable( CHAR16 *VariableName,
+ EFI_GUID *VariableOwnerGuid,
+ VOID **Buffer,
+ UINTN *BufferSize)
+{
+ UINTN Size = 0;
+ *BufferSize = 0;
+
+ EFI_STATUS Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Print(L"Error! 'gRT->GetVariable' call returned %r\n", Status);
+ return Status;
+ }
+
+ *Buffer = AllocateZeroPool(Size);
+ if (!Buffer) {
+ Print(L"Error! 'AllocateZeroPool' call returned %r\n", Status);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, *Buffer);
+ if (Status == EFI_SUCCESS) {
+ *BufferSize = Size;
+ } else {
+ FreePool( *Buffer );
+ *Buffer = NULL;
+ }
+
+ return Status;
+}
+
+
+VOID PrintBootOption(CHAR16* BootOptionName)
+{
+ UINTN OptionSize;
+ UINT8* Buffer;
+
+ EFI_STATUS Status = GetNvramVariable(BootOptionName, &gEfiGlobalVariableGuid, (VOID**)&Buffer, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ EFI_LOAD_OPTION* LoadOption = (EFI_LOAD_OPTION*) Buffer;
+ CHAR16* Description = (CHAR16*)(Buffer + sizeof (EFI_LOAD_OPTION));
+ UINTN DescriptionSize = StrSize(Description);
+
+ Print(L"%s\n", Description);
+ if (LoadOption->FilePathListLength != 0) {
+ VOID* FilePathList = (UINT8 *)Description + DescriptionSize;
+ CHAR16* DevPathString = ConvertDevicePathToText(FilePathList, TRUE, FALSE);
+ Print(L"%s\n", DevPathString);
+ }
+ } else {
+ Print(L"Can't get %s variable\n", BootOptionName);
+ }
+}
+
+
+INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
+{
+ UINTN OptionSize;
+ EFI_STATUS Status;
+
+ UINT16* BootCurrent;
+ Status = GetNvramVariable(L"BootCurrent", &gEfiGlobalVariableGuid, (VOID**)&BootCurrent, &OptionSize);
+ if (Status != EFI_SUCCESS) {
+ Print(L"Can't get BootCurrent variable\n");
+ }
+
+ UINT16* BootOrderArray;
+ Status = GetNvramVariable(L"BootOrder", &gEfiGlobalVariableGuid, (VOID**)&BootOrderArray, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ for (UINTN i=0; i<(OptionSize/sizeof(UINT16)); i++) {
+ CHAR16 BootOptionStr[sizeof("Boot####")+1];
+ UnicodeSPrint(BootOptionStr, (sizeof("Boot####")+1)*sizeof(CHAR16), L"Boot%04x", BootOrderArray[i]);
+ Print(L"%s%s\n", BootOptionStr, (BootOrderArray[i] == *BootCurrent)? L"*" : L"" );
+ PrintBootOption(BootOptionStr);
+ Print(L"\n");
+ }
+ } else {
+ Print(L"Can't get BootOrder variable\n");
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_20/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf b/Lessons/Lesson_20/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
new file mode 100644
index 0000000..d2cfba9
--- /dev/null
+++ b/Lessons/Lesson_20/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
@@ -0,0 +1,19 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = ShowBootVariables
+ FILE_GUID = 31266d12-9c60-478e-905e-05d117a3a9df
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+[Sources]
+ ShowBootVariables.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ ShellCEntryLib
+
diff --git a/Lessons/Lesson_20/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c b/Lessons/Lesson_20/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c
new file mode 100644
index 0000000..b13aa6c
--- /dev/null
+++ b/Lessons/Lesson_20/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/Lessons/Lesson_20/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf b/Lessons/Lesson_20/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf
new file mode 100644
index 0000000..013bf4e
--- /dev/null
+++ b/Lessons/Lesson_20/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/Lessons/Lesson_20/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_20/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_20/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/Lessons/Lesson_20/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_20/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_20/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/Lessons/Lesson_20/UefiLessonsPkg/UefiLessonsPkg.dec b/Lessons/Lesson_20/UefiLessonsPkg/UefiLessonsPkg.dec
new file mode 100644
index 0000000..94a42ff
--- /dev/null
+++ b/Lessons/Lesson_20/UefiLessonsPkg/UefiLessonsPkg.dec
@@ -0,0 +1,20 @@
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = UefiLessonsPkg
+ PACKAGE_GUID = 7e7edbba-ca2c-4177-a3f0-d3371358773a
+ PACKAGE_VERSION = 1.01
+
+[Includes]
+
+[LibraryClasses]
+
+[Guids]
+ # FILE_GUID as defined in UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ gHelloWorldFileGuid = {0x2e55fa38, 0xf148, 0x42d3, {0xaf, 0x90, 0x1b, 0xe2, 0x47, 0x32, 0x3e, 0x30}}
+ gUefiLessonsPkgTokenSpaceGuid = {0x150cab53, 0xad47, 0x4385, {0xb5, 0xdd, 0xbc, 0xfc, 0x76, 0xba, 0xca, 0xf0}}
+
+[Protocols]
+
+[PcdsFixedAtBuild]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32|42|UINT32|0x00000001
+
diff --git a/Lessons/Lesson_20/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_20/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..c4adde7
--- /dev/null
+++ b/Lessons/Lesson_20/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,39 @@
+[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
+ UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
+ UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
+ UefiLessonsPkg/PCDLesson/PCDLesson.inf
+
+
diff --git a/Lessons/Lesson_21/Conf/target.txt b/Lessons/Lesson_21/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lessons/Lesson_21/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/Lessons/Lesson_21/README.md b/Lessons/Lesson_21/README.md
new file mode 100644
index 0000000..4e53c04
--- /dev/null
+++ b/Lessons/Lesson_21/README.md
@@ -0,0 +1,71 @@
+Let's create a another variable `PcdMyVar32_1` the same way we did in the previous lesson.
+
+Add a PCD definition to the `UefiLessonsPkg/UefiLessonsPkg.dec`:
+```
+[PcdsFixedAtBuild]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_1|42|UINT32|0x00000002
+```
+
+Add print statement to `UefiLessonsPkg/PCDLesson/PCDLesson.c`:
+```
+Print(L"PcdMyVar32_1=%d\n", FixedPcdGet32(PcdMyVar32_1));
+```
+
+As for the `PCDLesson.inf` this time add an override for a value this time:
+```
+[FixedPcd]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_1|43
+```
+
+If you build execute our app under OVMF you would get:
+```
+FS0:\> PCDLesson.efi
+PcdMyVar32=42
+PcdMyVar32_1=43
+```
+
+So it means that every App/Driver can override a PCD declared in *.dec file differently.
+
+______________
+
+Now let's create a third variable `PcdMyVar32_2` the same way as `PcdMyVar32_1`.
+`UefiLessonsPkg/UefiLessonsPkg.dec`
+ ```
+[PcdsFixedAtBuild]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|42|UINT32|0x00000003
+```
+UefiLessonsPkg/PCDLesson/PCDLesson.c
+```
+Print(L"PcdMyVar32_2=%d\n", FixedPcdGet32(PcdMyVar32_2));
+```
+UefiLessonsPkg/PCDLesson/PCDLesson.inf
+```
+[FixedPcd]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|43
+```
+Only this time add an override for the variable to our `UefiLessonsPkg/UefiLessonsPkg.dsc` file:
+```
+[PcdsFixedAtBuild]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|44
+```
+
+If you build our app and execute in under OVMF now you would get:
+```
+FS0:\> PCDLesson.efi
+PcdMyVar32=42
+PcdMyVar32_1=43
+PcdMyVar32_2=44
+```
+
+So override order would be:
+```
+DEC < INF < DSC
+```
+- Declaration file (DEC) declares PCD with its default value
+- Every App/Driver Information file (INF) can override the value of this PCD differently
+- However a package description file that contains all these Apps/Drivers (DSC) can override this PCD for all of them
+
diff --git a/Lessons/Lesson_21/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_21/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..29a4812
--- /dev/null
+++ b/Lessons/Lesson_21/UefiLessonsPkg/HelloWorld/HelloWorld.c
@@ -0,0 +1,19 @@
+#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");
+
+ UINTN Index;
+ gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
+ gST->ConIn->Reset(gST->ConIn, FALSE);
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_21/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_21/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_21/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/Lessons/Lesson_21/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_21/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..32e9c43
--- /dev/null
+++ b/Lessons/Lesson_21/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/Lessons/Lesson_21/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_21/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_21/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/Lessons/Lesson_21/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lessons/Lesson_21/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lessons/Lesson_21/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/Lessons/Lesson_21/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_21/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lessons/Lesson_21/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/Lessons/Lesson_21/UefiLessonsPkg/InteractiveApp/InteractiveApp.c b/Lessons/Lesson_21/UefiLessonsPkg/InteractiveApp/InteractiveApp.c
new file mode 100644
index 0000000..59c89a9
--- /dev/null
+++ b/Lessons/Lesson_21/UefiLessonsPkg/InteractiveApp/InteractiveApp.c
@@ -0,0 +1,34 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ UINTN Index;
+ EFI_INPUT_KEY Key;
+
+ Print(L"Try to guess the secret symbol!\n");
+ Print(L"To quit press 'q'\n");
+
+ while(TRUE) {
+ gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
+ gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
+ Print(L"ScanCode = %04x, UnicodeChar = %04x (%c)\n", Key.ScanCode, Key.UnicodeChar, Key.UnicodeChar);
+
+ if (Key.UnicodeChar == 'k') {
+ Print(L"Correct!\n");
+ break;
+ } else if (Key.UnicodeChar == 'q') {
+ Print(L"Bye!\n");
+ break;
+ } else {
+ Print(L"Wrong!\n");
+ }
+ }
+ gST->ConIn->Reset(gST->ConIn, FALSE);
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_21/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf b/Lessons/Lesson_21/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
new file mode 100644
index 0000000..700b779
--- /dev/null
+++ b/Lessons/Lesson_21/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
@@ -0,0 +1,18 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = InteractiveApp
+ FILE_GUID = 1539451b-f300-41fa-a565-dde69c1bed66
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ InteractiveApp.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
diff --git a/Lessons/Lesson_21/UefiLessonsPkg/ListVariables/ListVariables.c b/Lessons/Lesson_21/UefiLessonsPkg/ListVariables/ListVariables.c
new file mode 100644
index 0000000..1f3ef4a
--- /dev/null
+++ b/Lessons/Lesson_21/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/Lessons/Lesson_21/UefiLessonsPkg/ListVariables/ListVariables.inf b/Lessons/Lesson_21/UefiLessonsPkg/ListVariables/ListVariables.inf
new file mode 100644
index 0000000..14e9fa2
--- /dev/null
+++ b/Lessons/Lesson_21/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/Lessons/Lesson_21/UefiLessonsPkg/MemoryInfo/MemoryInfo.c b/Lessons/Lesson_21/UefiLessonsPkg/MemoryInfo/MemoryInfo.c
new file mode 100644
index 0000000..8c3bcf2
--- /dev/null
+++ b/Lessons/Lesson_21/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/Lessons/Lesson_21/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf b/Lessons/Lesson_21/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
new file mode 100644
index 0000000..777010d
--- /dev/null
+++ b/Lessons/Lesson_21/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/Lessons/Lesson_21/UefiLessonsPkg/PCDLesson/PCDLesson.c b/Lessons/Lesson_21/UefiLessonsPkg/PCDLesson/PCDLesson.c
new file mode 100644
index 0000000..3c88a9b
--- /dev/null
+++ b/Lessons/Lesson_21/UefiLessonsPkg/PCDLesson/PCDLesson.c
@@ -0,0 +1,17 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/PcdLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ Print(L"PcdMyVar32=%d\n", FixedPcdGet32(PcdMyVar32));
+ Print(L"PcdMyVar32_1=%d\n", FixedPcdGet32(PcdMyVar32_1));
+ Print(L"PcdMyVar32_2=%d\n", FixedPcdGet32(PcdMyVar32_2));
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_21/UefiLessonsPkg/PCDLesson/PCDLesson.inf b/Lessons/Lesson_21/UefiLessonsPkg/PCDLesson/PCDLesson.inf
new file mode 100644
index 0000000..cc85c26
--- /dev/null
+++ b/Lessons/Lesson_21/UefiLessonsPkg/PCDLesson/PCDLesson.inf
@@ -0,0 +1,24 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = PCDLesson
+ FILE_GUID = 8c1a6b71-0c4b-4497-aaad-07404edf142c
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ PCDLesson.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiLessonsPkg/UefiLessonsPkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
+[FixedPcd]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_1|43
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|43
+
diff --git a/Lessons/Lesson_21/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c b/Lessons/Lesson_21/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
new file mode 100644
index 0000000..7f6b58c
--- /dev/null
+++ b/Lessons/Lesson_21/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
@@ -0,0 +1,93 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+
+
+EFI_STATUS
+GetNvramVariable( CHAR16 *VariableName,
+ EFI_GUID *VariableOwnerGuid,
+ VOID **Buffer,
+ UINTN *BufferSize)
+{
+ UINTN Size = 0;
+ *BufferSize = 0;
+
+ EFI_STATUS Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Print(L"Error! 'gRT->GetVariable' call returned %r\n", Status);
+ return Status;
+ }
+
+ *Buffer = AllocateZeroPool(Size);
+ if (!Buffer) {
+ Print(L"Error! 'AllocateZeroPool' call returned %r\n", Status);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, *Buffer);
+ if (Status == EFI_SUCCESS) {
+ *BufferSize = Size;
+ } else {
+ FreePool( *Buffer );
+ *Buffer = NULL;
+ }
+
+ return Status;
+}
+
+
+VOID PrintBootOption(CHAR16* BootOptionName)
+{
+ UINTN OptionSize;
+ UINT8* Buffer;
+
+ EFI_STATUS Status = GetNvramVariable(BootOptionName, &gEfiGlobalVariableGuid, (VOID**)&Buffer, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ EFI_LOAD_OPTION* LoadOption = (EFI_LOAD_OPTION*) Buffer;
+ CHAR16* Description = (CHAR16*)(Buffer + sizeof (EFI_LOAD_OPTION));
+ UINTN DescriptionSize = StrSize(Description);
+
+ Print(L"%s\n", Description);
+ if (LoadOption->FilePathListLength != 0) {
+ VOID* FilePathList = (UINT8 *)Description + DescriptionSize;
+ CHAR16* DevPathString = ConvertDevicePathToText(FilePathList, TRUE, FALSE);
+ Print(L"%s\n", DevPathString);
+ }
+ } else {
+ Print(L"Can't get %s variable\n", BootOptionName);
+ }
+}
+
+
+INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
+{
+ UINTN OptionSize;
+ EFI_STATUS Status;
+
+ UINT16* BootCurrent;
+ Status = GetNvramVariable(L"BootCurrent", &gEfiGlobalVariableGuid, (VOID**)&BootCurrent, &OptionSize);
+ if (Status != EFI_SUCCESS) {
+ Print(L"Can't get BootCurrent variable\n");
+ }
+
+ UINT16* BootOrderArray;
+ Status = GetNvramVariable(L"BootOrder", &gEfiGlobalVariableGuid, (VOID**)&BootOrderArray, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ for (UINTN i=0; i<(OptionSize/sizeof(UINT16)); i++) {
+ CHAR16 BootOptionStr[sizeof("Boot####")+1];
+ UnicodeSPrint(BootOptionStr, (sizeof("Boot####")+1)*sizeof(CHAR16), L"Boot%04x", BootOrderArray[i]);
+ Print(L"%s%s\n", BootOptionStr, (BootOrderArray[i] == *BootCurrent)? L"*" : L"" );
+ PrintBootOption(BootOptionStr);
+ Print(L"\n");
+ }
+ } else {
+ Print(L"Can't get BootOrder variable\n");
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_21/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf b/Lessons/Lesson_21/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
new file mode 100644
index 0000000..d2cfba9
--- /dev/null
+++ b/Lessons/Lesson_21/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
@@ -0,0 +1,19 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = ShowBootVariables
+ FILE_GUID = 31266d12-9c60-478e-905e-05d117a3a9df
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+[Sources]
+ ShowBootVariables.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ ShellCEntryLib
+
diff --git a/Lessons/Lesson_21/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c b/Lessons/Lesson_21/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c
new file mode 100644
index 0000000..b13aa6c
--- /dev/null
+++ b/Lessons/Lesson_21/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/Lessons/Lesson_21/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf b/Lessons/Lesson_21/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf
new file mode 100644
index 0000000..013bf4e
--- /dev/null
+++ b/Lessons/Lesson_21/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/Lessons/Lesson_21/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_21/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_21/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/Lessons/Lesson_21/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_21/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_21/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/Lessons/Lesson_21/UefiLessonsPkg/UefiLessonsPkg.dec b/Lessons/Lesson_21/UefiLessonsPkg/UefiLessonsPkg.dec
new file mode 100644
index 0000000..1bf2c6c
--- /dev/null
+++ b/Lessons/Lesson_21/UefiLessonsPkg/UefiLessonsPkg.dec
@@ -0,0 +1,22 @@
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = UefiLessonsPkg
+ PACKAGE_GUID = 7e7edbba-ca2c-4177-a3f0-d3371358773a
+ PACKAGE_VERSION = 1.01
+
+[Includes]
+
+[LibraryClasses]
+
+[Guids]
+ # FILE_GUID as defined in UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ gHelloWorldFileGuid = {0x2e55fa38, 0xf148, 0x42d3, {0xaf, 0x90, 0x1b, 0xe2, 0x47, 0x32, 0x3e, 0x30}}
+ gUefiLessonsPkgTokenSpaceGuid = {0x150cab53, 0xad47, 0x4385, {0xb5, 0xdd, 0xbc, 0xfc, 0x76, 0xba, 0xca, 0xf0}}
+
+[Protocols]
+
+[PcdsFixedAtBuild]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32|42|UINT32|0x00000001
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_1|42|UINT32|0x00000002
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|42|UINT32|0x00000003
+
diff --git a/Lessons/Lesson_21/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_21/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..e50a2c6
--- /dev/null
+++ b/Lessons/Lesson_21/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,41 @@
+[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
+ UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
+ UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
+ UefiLessonsPkg/PCDLesson/PCDLesson.inf
+
+[PcdsFixedAtBuild]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|44
+
diff --git a/Lessons/Lesson_22/README.md b/Lessons/Lesson_22/README.md
new file mode 100644
index 0000000..5280e72
--- /dev/null
+++ b/Lessons/Lesson_22/README.md
@@ -0,0 +1,117 @@
+Let's explore another PCD type - feature flag PCD.
+
+Add PCD to DEC file UefiLessonsPkg/UefiLessonsPkg.dec:
+```
+[PcdsFeatureFlag]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyFeatureFlagVar|FALSE|BOOLEAN|0x20000001
+```
+
+Populate it to INF UefiLessonsPkg/PCDLesson/PCDLesson.inf:
+```
+[FeaturePcd]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyFeatureFlagVar
+```
+
+To get PCD value in a *.c file either `FeaturePcdGet` or `PcdGetBool` can be used which are practically the same https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h:
+```
+#define FeaturePcdGet(TokenName) _PCD_GET_MODE_BOOL_##TokenName
+#define PcdGetBool(TokenName) _PCD_GET_MODE_BOOL_##TokenName
+```
+Let's add both to our UefiLessonsPkg/PCDLesson/PCDLesson.c
+```
+Print(L"PcdMyFeatureFlagVar=%d\n", FeaturePcdGet(PcdMyFeatureFlagVar));
+Print(L"PcdMyFeatureFlagVar=%d\n", PcdGetBool(PcdMyFeatureFlagVar));
+```
+Ok, we are ready to build. Build your module and check out AutoGen files.
+
+Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h
+```
+#define _PCD_TOKEN_PcdMyFeatureFlagVar 0U
+#define _PCD_SIZE_PcdMyFeatureFlagVar 1
+#define _PCD_GET_MODE_SIZE_PcdMyFeatureFlagVar _PCD_SIZE_PcdMyFeatureFlagVar
+#define _PCD_VALUE_PcdMyFeatureFlagVar ((BOOLEAN)0U)
+extern const BOOLEAN _gPcd_FixedAtBuild_PcdMyFeatureFlagVar;
+#define _PCD_GET_MODE_BOOL_PcdMyFeatureFlagVar _gPcd_FixedAtBuild_PcdMyFeatureFlagVar
+//#define _PCD_SET_MODE_BOOL_PcdMyFeatureFlagVar ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+```
+
+Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.c
+```
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdMyFeatureFlagVar = _PCD_VALUE_PcdMyFeatureFlagVar;
+```
+
+So both calls for our PCD would translate to:
+```
+FeaturePcdGet/PcdGetBool(PcdMyFeatureFlagVar) --> _PCD_GET_MODE_BOOL_PcdMyFeatureFlagVar --> _gPcd_FixedAtBuild_PcdMyFeatureFlagVar
+```
+And this variable is declared in AutoGen.c file:
+```
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdMyFeatureFlagVar = ((BOOLEAN)0U);
+```
+
+If you execute it under OVMF these print statements would get you:
+```
+PcdMyFeatureFlagVar=0
+PcdMyFeatureFlagVar=0
+```
+
+________________________
+
+So as you can see a feature PCD is similar to a BOOLEAN PCD defined under `PcdsFixedAtBuild` section
+
+Let's create a fixed bool PCD and compare results:
+
+UefiLessonsPkg/UefiLessonsPkg.dec:
+```
+[PcdsFixedAtBuild]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVarBool|FALSE|BOOLEAN|0x00000004
+
+[PcdsFeatureFlag]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyFeatureFlagVar|FALSE|BOOLEAN|0x20000001
+```
+UefiLessonsPkg/PCDLesson/PCDLesson.inf:
+```
+[FixedPcd]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVarBool
+
+[FeaturePcd]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyFeatureFlagVar
+```
+UefiLessonsPkg/PCDLesson/PCDLesson.c:
+```
+Print(L"PcdMyFeatureFlagVar=%d\n", FeaturePcdGet(PcdMyFeatureFlagVar));
+Print(L"PcdMyFeatureFlagVar=%d\n", PcdGetBool(PcdMyFeatureFlagVar));
+Print(L"PcdMyVarBool=%d\n", FixedPcdGetBool(PcdMyVarBool));
+Print(L"PcdMyVarBool=%d\n", PcdGetBool(PcdMyVarBool));
+```
+
+Ok, now let's build and look at AutoGen files:
+
+AutoGen.c
+```
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdMyVarBool = _PCD_VALUE_PcdMyVarBool;
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdMyFeatureFlagVar = _PCD_VALUE_PcdMyFeatureFlagVar;
+```
+AutoGen.h
+```
+#define _PCD_TOKEN_PcdMyVarBool 0U
+#define _PCD_SIZE_PcdMyVarBool 1
+#define _PCD_GET_MODE_SIZE_PcdMyVarBool _PCD_SIZE_PcdMyVarBool
+#define _PCD_VALUE_PcdMyVarBool 0U
+extern const BOOLEAN _gPcd_FixedAtBuild_PcdMyVarBool;
+#define _PCD_GET_MODE_BOOL_PcdMyVarBool _gPcd_FixedAtBuild_PcdMyVarBool
+//#define _PCD_SET_MODE_BOOL_PcdMyVarBool ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdMyFeatureFlagVar 0U
+#define _PCD_SIZE_PcdMyFeatureFlagVar 1
+#define _PCD_GET_MODE_SIZE_PcdMyFeatureFlagVar _PCD_SIZE_PcdMyFeatureFlagVar
+#define _PCD_VALUE_PcdMyFeatureFlagVar ((BOOLEAN)0U)
+extern const BOOLEAN _gPcd_FixedAtBuild_PcdMyFeatureFlagVar;
+#define _PCD_GET_MODE_BOOL_PcdMyFeatureFlagVar _gPcd_FixedAtBuild_PcdMyFeatureFlagVar
+//#define _PCD_SET_MODE_BOOL_PcdMyFeatureFlagVar ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+```
+
+As you see the differences are subtle. `FeaturePcd` is simply a syntactic sugar for BOOLEAN `FixedAtBuild` PCD.
+
diff --git a/Lessons/Lesson_23/README.md b/Lessons/Lesson_23/README.md
new file mode 100644
index 0000000..bae429d
--- /dev/null
+++ b/Lessons/Lesson_23/README.md
@@ -0,0 +1,225 @@
+Now let's explore `PatchableInModule` PCD.
+
+Add PCD to DEC file UefiLessonsPkg/UefiLessonsPkg.dec:
+```
+[PcdsPatchableInModule]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyPatchableVar32|0x31313131|UINT32|0x00000004
+```
+Populate it to INF UefiLessonsPkg/PCDLesson/PCDLesson.inf:
+```
+[PatchPcd]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyPatchableVar32
+```
+
+To get a value of PCD in a *.c file either `PatchPcdGet` or generic `PcdGet` should be used.
+
+Let's test both methods:
+```
+Print(L"PcdMyPatchableVar32=%d\n", PatchPcdGet32(PcdMyPatchableVar32));
+Print(L"PcdMyPatchableVar32=%d\n", PcdGet32(PcdMyPatchableVar32));
+```
+
+Now build and look to AutoGen files:
+
+Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h
+```
+#define _PCD_TOKEN_PcdMyPatchableVar32 0U
+#define _PCD_PATCHABLE_VALUE_PcdMyPatchableVar32 ((UINT32)0x31313131U)
+extern volatile UINT32 _gPcd_BinaryPatch_PcdMyPatchableVar32;
+#define _PCD_GET_MODE_32_PcdMyPatchableVar32 _gPcd_BinaryPatch_PcdMyPatchableVar32
+#define _PCD_PATCHABLE_PcdMyPatchableVar32_SIZE 4
+#define _PCD_GET_MODE_SIZE_PcdMyPatchableVar32 _gPcd_BinaryPatch_Size_PcdMyPatchableVar32
+extern UINTN _gPcd_BinaryPatch_Size_PcdMyPatchableVar32;
+#define _PCD_SET_MODE_32_PcdMyPatchableVar32(Value) (_gPcd_BinaryPatch_PcdMyPatchableVar32 = (Value))
+#define _PCD_SET_MODE_32_S_PcdMyPatchableVar32(Value) ((_gPcd_BinaryPatch_PcdMyPatchableVar32 = (Value)), RETURN_SUCCESS)
+```
+Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.c
+```
+volatile UINT32 _gPcd_BinaryPatch_PcdMyPatchableVar32 = _PCD_PATCHABLE_VALUE_PcdMyPatchableVar32;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN _gPcd_BinaryPatch_Size_PcdMyPatchableVar32 = 4;
+```
+
+So in this case our call to `PcdGet32(PcdMyPatchableVar32)` would be expanded to:
+```
+PcdGet32(PcdMyPatchableVar32) --> _PCD_GET_MODE_32_PcdMyPatchableVar32 --> _gPcd_BinaryPatch_PcdMyPatchableVar32
+```
+This variable would be assigned in `AutoGen.c`:
+```
+volatile UINT32 _gPcd_BinaryPatch_PcdMyPatchableVar32 = ((UINT32)0x31313131U);
+```
+So the main difference from the FixedAtBuild and FeatureFlag PCDs is that variable defined as `volatile` and set functions aren't blocked.
+
+Let's try to set our PCD then. As with get, there are two possibilities. You can use either `PatchPcdSet<Type>` or generic `PcdSet<Type>S`.
+
+Keep in mind that `PcdSet32S` unravels to a macro returning a value.
+https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h:
+```
+#define PcdSet32S(TokenName, Value) _PCD_SET_MODE_32_S_##TokenName ((Value))
+```
+Therefore:
+```
+PcdSet32S(PcdMyPatchableVar32, 44) --> _PCD_SET_MODE_32_S_PcdMyPatchableVar32 ((Value)) --> ((_gPcd_BinaryPatch_PcdMyPatchableVar32 = (Value)), RETURN_SUCCESS)
+```
+
+So if you don't want such error:
+```
+/home/kostr/tiano/edk2/Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h:108:106: error: right-hand operand of comma expression has no effect [-Werror=unused-value]
+ 108 | #define _PCD_SET_MODE_32_S_PcdMyPatchableVar32(Value) ((_gPcd_BinaryPatch_PcdMyPatchableVar32 = (Value)), RETURN_SUCCESS)
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~.
+```
+You should use something like this:
+```
+RETURN_STATUS PcdStatus = PcdSet32S(PcdMyPatchableVar32, 44);
+Print(L"PcdStatus=%r\n", PcdStatus);
+```
+
+Alternatively you can use `PatchPcdSet32` which don't require such thing as it is defined as follows:
+```
+#define PatchPcdSet32(TokenName, Value) (_gPcd_BinaryPatch_##TokenName = (Value))
+```
+
+Test both set methods in app code:
+```
+Print(L"PcdMyPatchableVar32=0x%x\n", PcdGet32(PcdMyPatchableVar32));
+RETURN_STATUS PcdStatus = PcdSet32S(PcdMyPatchableVar32, 44);
+Print(L"PcdStatus=%r\n", PcdStatus);
+Print(L"PcdMyPatchableVar32=%d\n", PcdGet32(PcdMyPatchableVar32));
+PatchPcdSet32(PcdMyPatchableVar32, 45);
+Print(L"PcdMyPatchableVar32=%d\n", PatchPcdGet32(PcdMyPatchableVar32));
+```
+
+
+Now if you execute our app under OVMF prints for patchable PCDs would output:
+```
+PcdMyPatchableVar32=0x31313131
+PcdStatus=Success
+PcdMyPatchableVar32=44
+PcdMyPatchableVar32=45
+```
+
+_________________________________
+
+In case you've wondered why I've assigned a hex value for PCD default value or why this PCD type is named `PatchableInModule` this section is for you.
+
+This PCD type is named like that because the value of this PCD can be changed in a binary PE/COFF image (*.efi file). To do this two utilities are used:
+- `GenPatchPcdTable` - this tool is used to get the patchable PCD offset for the EFI image by parsing the map file
+- `PatchPcdValue` - this tool is used to actually patch PCD value
+
+You can download rtf manuals for these utilities from edk2 repo:
+-https://github.com/tianocore/edk2/blob/master/BaseTools/UserManuals/GenPatchPcdTable_Utility_Man_Page.rtf
+-https://github.com/tianocore/edk2/blob/master/BaseTools/UserManuals/PatchPcdValue_Utility_Man_Page.rtf
+
+Let's start with `GenPatchPcdTable`. First check out help for this tool:
+```
+$ ./BaseTools/BinWrappers/PosixLike/GenPatchPcdTable -h
+Usage: GenPatchPcdTable.py -m <MapFile> -e <EfiFile> -o <OutFile>
+
+Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.
+
+Options:
+ --version show program's version number and exit
+ -h, --help show this help message and exit
+ -m MAPFILE, --mapfile=MAPFILE
+ Absolute path of module map file.
+ -e EFIFILE, --efifile=EFIFILE
+ Absolute path of EFI binary file.
+ -o OUTFILE, --outputfile=OUTFILE
+ Absolute path of output file to store the got
+ patchable PCD table.
+```
+Now let's create a `PatchPcdTable` for our app:
+
+For the *.efi file we can use one of:
+```
+Build/UefiLessonsPkg/RELEASE_GCC5/X64/PCDLesson.efi
+Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/OUTPUT/PCDLesson.efi
+Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.efi
+```
+For the *.map file we can use one of:
+```
+Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.map
+Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/OUTPUT/PCDLesson.map
+```
+In case you wonder how our PCD can be found in a map file, execute:
+```
+$ grep MyPatchableVar32 Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.map -A2
+ .data._gPcd_BinaryPatch_PcdMyPatchableVar32
+ 0x0000000000001920 0x4 /tmp/PCDLesson.dll.m6t8YL.ltrans0.ltrans.o
+ *fill* 0x0000000000001924 0xc
+```
+So as you can see the default value for our PCD is placed under 0x1920 offset.
+
+Now let's execute `GenPatchPcdTable` and create a file `PCDLessonPatchPcdTable` in app Build DEBUG folder:
+```
+./BaseTools/BinWrappers/PosixLike/GenPatchPcdTable \
+ -m Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.map \
+ -e Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.efi \
+ -o Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLessonPatchPcdTable
+```
+
+Checkout the created `PCDLessonPatchPcdTable` file.
+```
+$ cat Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLessonPatchPcdTable
+PCD Name Offset Section Name
+PcdMyPatchableVar32 0x1920 .data
+```
+As you can see it has the same offset that we've seen in a map file.
+
+Now let's get a final look at our default PCD value in an *.elf file:
+```
+hexdump -s 0x1920 Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.efi -n 4
+0001920 3131 3131
+0001924
+```
+
+Checkout help for the `PatchPcdValue` tool:
+```
+$ ./BaseTools/BinWrappers/PosixLike/PatchPcdValue -h
+Usage: PatchPcdValue.py -f Offset -u Value -t Type [-s MaxSize] <input_file>
+
+Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+
+Options:
+ -f PCDOFFSET, --offset=PCDOFFSET
+ Start offset to the image is used to store PCD value.
+ -u PCDVALUE, --value=PCDVALUE
+ PCD value will be updated into the image.
+ -t PCDTYPENAME, --type=PCDTYPENAME
+ The name of PCD data type may be one of VOID*,BOOLEAN,
+ UINT8, UINT16, UINT32, UINT64.
+ -s PCDMAXSIZE, --maxsize=PCDMAXSIZE
+ Max size of data buffer is taken by PCD value.It must
+ be set when PCD type is VOID*.
+ -v, --verbose Run verbosely
+ -d LOGLEVEL, --debug=LOGLEVEL
+ Run with debug information
+ -q, --quiet Run quietly
+ -? show this help message and exit
+ --version show program's version number and exit
+ -h, --help show this help message and exit
+```
+
+Now use it to patch our PCD in an *.elf file:
+```
+./BaseTools/BinWrappers/PosixLike/PatchPcdValue \
+ --offset=0x1920 \
+ --value=0xDEADDEAD \
+ --type=UINT32 \
+ Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.efi
+```
+Look at hexdump again:
+```
+$ hexdump -s 0x1920 Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.efi -n 4
+0001920 dead dead
+0001924
+```
+We've successfully changed our PCD in a binary!
+
+Now if you execute our app under OVMF prints for patchable PCDs would output:
+```
+PcdMyPatchableVar32=0xDEADDEAD
+PcdStatus=Success
+PcdMyPatchableVar32=44
+PcdMyPatchableVar32=45
+```
+
diff --git a/Lessons/Lesson_25/README.md b/Lessons/Lesson_25/README.md
new file mode 100644
index 0000000..39af37e
--- /dev/null
+++ b/Lessons/Lesson_25/README.md
@@ -0,0 +1,13 @@
+Summary table:
+
+| | Fixed at build | Feature Flag | Patchable | Dynamic | DynamicEx |
+|---------------|-----------------------------------|-----------------------------------|------------------------------------|--------------------------------------------------------------|--------------------------------------------------------------------|
+| .dec section: | [PcdsFixedAtBuild] | [PcdsFeatureFlag] | [PcdsPatchableInModule] | [PcdsDynamic] | [PcdsDynamicEx] |
+| .dsc section: | [PcdsFixedAtBuild] | [PcdsFeatureFlag] | [PcdsPatchableInModule] | [PcdsDynamicDefault]<br>[PcdsDynamicHii]<br>[PcdsDynamicVpd] | [PcdsDynamicExDefault]<br>[PcdsDynamicExHii]<br>[PcdsDynamicExVpd] |
+| .inf section: | [FixedPcd]<br>[Pcd] | [FeaturePcd]<br>[Pcd] | [PatchPcd]<br>[Pcd] | [Pcd] | [PcdEx] |
+| Get: | PcdGet<Type><br>FixedPcdGet<Type> | PcdGetBool<br>FeaturePcdGet | PcdGet<Type><br>PatchPcdGet<Type> | PcdGet<Type> | PcdGet<Type><br>PcdGetEx<Type> |
+| Set: | - | - | PcdSet<Type>S<br>PatchPcdSet<Type> | PcdSet<Type>S | PcdSet<Type>S<br>PcdSetEx<Type>S |
+| Scope: | Every module have its own copy | Every module have its own copy | Every module have its own copy | Global for<br>platform | Global for<br>platform |
+
+
+\<Type\> = 8|16|32|64|Bool|Ptr
diff --git a/Lessons/Lesson_26/README.md b/Lessons/Lesson_26/README.md
new file mode 100644
index 0000000..255d139
--- /dev/null
+++ b/Lessons/Lesson_26/README.md
@@ -0,0 +1,194 @@
+As you remember the entry point for our UEFI programs is:
+
+```
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+```
+
+The passed structure `EFI_SYSTEM_TABLE` looks like this according to UEFI specification:
+
+```
+typedef struct {
+ EFI_TABLE_HEADER Hdr;
+ CHAR16 *FirmwareVendor;
+ UINT32 FirmwareRevision;
+ EFI_HANDLE ConsoleInHandle;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
+ EFI_HANDLE ConsoleOutHandle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
+ EFI_HANDLE StandardErrorHandle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *StdErr;
+ EFI_RUNTIME_SERVICES *RuntimeServices;
+ EFI_BOOT_SERVICES *BootServices;
+ UINTN NumberOfTableEntries;
+ EFI_CONFIGURATION_TABLE *ConfigurationTable;
+} EFI_SYSTEM_TABLE;
+```
+
+We've already used most of the fields of this structure. Now it is time to peek inside these fields:
+```
+UINTN NumberOfTableEntries;
+EFI_CONFIGURATION_TABLE *ConfigurationTable
+```
+According to the UEFI spec:
+```
+NumberOfTableEntries The number of system configuration tables in the buffer ConfigurationTable.
+ConfigurationTable A pointer to the system configuration tables. The number of entries in the table is NumberOfTableEntries.
+```
+
+As for EFI_CONFIGURATION_TABLE type:
+```
+EFI_CONFIGURATION_TABLE
+
+Summary:
+Contains a set of GUID/pointer pairs comprised of the ConfigurationTable field in the EFI System Table.
+
+typedef struct{
+ EFI_GUID VendorGuid;
+ VOID *VendorTable;
+} EFI_CONFIGURATION_TABLE;
+
+```
+
+Let's create a simple program `ShowTables` to look at tables referenced by this structure in OVMF:
+```
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ for (UINTN i=0; i<SystemTable->NumberOfTableEntries; i++) {
+ Print(L"%g, %p\n", SystemTable->ConfigurationTable[i].VendorGuid,
+ SystemTable->ConfigurationTable[i].VendorTable);
+ }
+ return EFI_SUCCESS;
+}
+```
+
+Build and execute it under OVMF:
+```
+FS0:\> ShowTables.efi
+EE4E5898-3914-4259-9D6E-DC7BD79403CF, 78EDF98
+05AD34BA-6F02-4214-952E-4DA0398E2BB9, 7ED2AC0
+7739F24C-93D7-11D4-9A3A-0090273FC14D, 78EA018
+4C19049F-4137-4DD3-9C10-8B97A83FFDFA, 7ED3AA0
+49152E77-1ADA-4764-B7A2-7AFEFED95E8B, 7ED5F10
+060CC026-4C0D-4DDA-8F41-595FEF00A502, 7942018
+EB9D2D31-2D88-11D3-9A16-0090273FC14D, 7941000
+EB9D2D30-2D88-11D3-9A16-0090273FC14D, 7B7E000
+8868E871-E4F1-11D3-BC22-0080C73C8881, 7B7E014
+DCFA911D-26EB-469F-A220-38B7DC461220, 6E86018
+```
+
+_______
+
+Let's search edk2 codebase for GUIDs:
+```
+EE4E5898-3914-4259-9D6E-DC7BD79403CF, 78EDF98
+```
+`gLzmaCustomDecompressGuid`
+
+LZMA_CUSTOM_DECOMPRESS_GUID
+
+https://github.com/tianocore/edk2/tree/master/MdeModulePkg/Include/Guid/LzmaDecompress.h
+
+GUID indicates the LZMA custom compress/decompress algorithm.
+The Global ID used to identify a section of an FFS file of type EFI_SECTION_GUID_DEFINED, whose contents have been compressed using LZMA.
+```
+05AD34BA-6F02-4214-952E-4DA0398E2BB9, 7ED2AC0
+```
+`gEfiDxeServicesTableGuid`
+
+DXE_SERVICES_TABLE_GUID
+
+https://github.com/tianocore/edk2/tree/master/MdePkg/Include/Guid/DxeServices.h (DXE Services Table)
+
+```
+7739F24C-93D7-11D4-9A3A-0090273FC14D, 78EA018
+```
+`gEfiHobListGuid`
+
+https://github.com/tianocore/edk2/tree/master/MdePkg/Include/Guid/HobList.h
+
+HOB List passed from PEI to DXE
+
+```
+4C19049F-4137-4DD3-9C10-8B97A83FFDFA, 7ED3AA0
+```
+`gEfiMemoryTypeInformationGuid`
+
+https://github.com/tianocore/edk2/tree/master/MdeModulePkg/Include/Guid/MemoryTypeInformation.h
+
+The memory type information HOB
+
+```
+49152E77-1ADA-4764-B7A2-7AFEFED95E8B, 7ED5F10
+```
+
+`gEfiDebugImageInfoTableGuid`
+
+https://github.com/tianocore/edk2/tree/master/MdePkg/Include/Guid/Debug ImageInfoTable.h
+
+Debug Image Info Table
+
+```
+060CC026-4C0D-4DDA-8F41-595FEF00A502, 7942018
+```
+`gMemoryStatusCodeRecordGuid`
+
+https://github.com/tianocore/edk2/tree/master/MdeModulePkg/Include/Guid/MemoryStatusCodeRecord.h
+
+Status code records HOB that originate from the PEI status code
+
+```
+EB9D2D31-2D88-11D3-9A16-0090273FC14D, 7941000
+```
+`gEfiSmbiosTableGuid`
+
+https://github.com/tianocore/edk2/tree/master/MdePkg/Include/Guid/SmBios.h
+
+SMBIOS tables
+
+```
+EB9D2D30-2D88-11D3-9A16-0090273FC14D, 7B7E000
+```
+
+`gEfiAcpi10TableGuid`
+
+ACPI_10_TABLE_GUID ACPI_TABLE_GUID
+
+https://github.com/tianocore/edk2/tree/master/MdePkg/Include/Guid/Acpi.h
+
+ACPI tables for old specifications
+
+```
+8868E871-E4F1-11D3-BC22-0080C73C8881, 7B7E014
+```
+gEfiAcpiTableGuid/gEfiAcpi20TableGuid
+
+EFI_ACPI_20_TABLE_GUID EFI_ACPI_TABLE_GUID
+
+https://github.com/tianocore/edk2/tree/master/MdePkg/Include/Guid/Acpi.h
+
+ACPI tables for modern specifications
+
+```
+DCFA911D-26EB-469F-A220-38B7DC461220, 6E77018
+```
+
+gEfiMemoryAttributesTableGuid
+
+https://github.com/tianocore/edk2/tree/master/MdePkg/Include/Guid/MemoryAttributesTable.h
+
+UEFI Memory Attributes Table [Defined in UEFI spec]
+
+
diff --git a/Lessons/Lesson_27/BIOS_menu.png b/Lessons/Lesson_27/BIOS_menu.png
new file mode 100644
index 0000000..cd28ef5
--- /dev/null
+++ b/Lessons/Lesson_27/BIOS_menu.png
Binary files differ
diff --git a/Lessons/Lesson_27/README.md b/Lessons/Lesson_27/README.md
new file mode 100644
index 0000000..5248b24
--- /dev/null
+++ b/Lessons/Lesson_27/README.md
@@ -0,0 +1,696 @@
+Let's try to get information from one of the system tables that we've discovered.
+
+You can find the most recent version of the "System Management BIOS (SMBIOS) Reference Specification" on the DMTF site https://www.dmtf.org/dsp/DSP0134
+For example now 3.4.0 is the most recent version https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.4.0.pdf
+
+From the previous lesson we now, that SMBIOS table is declared under `gEfiSmbiosTableGuid`.
+
+Let's create an app, that would print the address of this table.
+```
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/BaseMemoryLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ for (UINTN i=0; i<SystemTable->NumberOfTableEntries; i++) {
+ if (CompareGuid(&(SystemTable->ConfigurationTable[i].VendorGuid), &gEfiSmbiosTableGuid)) {
+ Print(L"SMBIOS table is placed at %p\n", SystemTable->ConfigurationTable[i].VendorTable);
+ }
+ }
+ return EFI_SUCCESS;
+}
+```
+
+In this code we've used `CompareGuid` function from the https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/BaseMemoryLib.h:
+```
+/**
+ Compares two GUIDs.
+ This function compares Guid1 to Guid2. If the GUIDs are identical then TRUE is returned.
+ If there are any bit differences in the two GUIDs, then FALSE is returned.
+ If Guid1 is NULL, then ASSERT().
+ If Guid2 is NULL, then ASSERT().
+ @param Guid1 A pointer to a 128 bit GUID.
+ @param Guid2 A pointer to a 128 bit GUID.
+ @retval TRUE Guid1 and Guid2 are identical.
+ @retval FALSE Guid1 and Guid2 are not identical.
+**/
+BOOLEAN
+EFIAPI
+CompareGuid (
+ IN CONST GUID *Guid1,
+ IN CONST GUID *Guid2
+ );
+```
+
+Don't forget to add:
+```
+[Guids]
+ gEfiSmbiosTableGuid
+```
+to app *inf file.
+
+Let's build our app and execute it under OVMF:
+```
+FS0:\> SmbiosInfo.efi
+SMBIOS table is placed at 7941000
+```
+
+# Get SMBIOS tables with `dmem`
+
+UEFI shell has a command `dmem` for memory dump:
+```
+FS0:\> dmem -? -b
+Displays the contents of system or device memory.
+
+DMEM [-b] [address] [size] [-MMIO]
+
+ -b - Displays one screen at a time.
+ -MMIO - Forces address cycles to the PCI bus.
+ address - Specifies a starting address in hexadecimal format.
+ size - Specifies the number of bytes to display in hexadecimal format.
+
+NOTES:
+ 1. This command displays the contents of system memory or device memory.
+ 2. Enter address and size in hexadecimal format.
+ 3. If address is not specified, the contents of the UEFI System Table
+ are displayed. Otherwise, memory starting at the specified address is displayed.
+ 4. Size specifies the number of bytes to display. If size is not specified,
+ 512 bytes are displayed.
+ 5. If MMIO is not specified, main system memory is displayed. Otherwise,
+ device memory is displayed through the use of the
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+
+EXAMPLES:
+ * To display the UEFI system table pointer entries:
+ fs0:\> dmem
+
+ * To display memory contents from 1af3088 with size of 16 bytes:
+ Shell> dmem 1af3088 16
+
+ * To display memory mapped IO contents from 1af3088 with a size of 16 bytes:
+ Shell> dmem 1af3088 16 -MMIO
+```
+
+Let's use it to print 0x30 bytes from the 0x7941000 address that we count as a SMBIOS table pointer.
+```
+FS0:\> dmem 7941000 30
+Memory Address 0000000007941000 30 Bytes
+ 07941000: 5F 53 4D 5F 26 1F 02 08-53 00 00 00 00 00 00 00 *_SM_&...S.......*
+ 07941010: 5F 44 4D 49 5F 0A 91 01-00 00 94 07 09 00 28 AF *_DMI_.........(.*
+ 07941020: AF AF AF AF AF AF AF AF-AF AF AF AF AF AF AF AF *................*
+```
+
+If you look at SMBIOS specification for SMBIOS Entry Point structure you'll see, that `_SM_` and `_DMI_` are predefined values in this structure.
+
+![SMBIOS_entry_structure](SMBIOS_entry_structure.png?raw=true "SMBIOS_entry_structure")
+
+You can find definition for the structure itself in edk2 under https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/SmBios.h
+```
+typedef struct {
+ UINT8 AnchorString[4];
+ UINT8 EntryPointStructureChecksum;
+ UINT8 EntryPointLength;
+ UINT8 MajorVersion;
+ UINT8 MinorVersion;
+ UINT16 MaxStructureSize;
+ UINT8 EntryPointRevision;
+ UINT8 FormattedArea[5];
+ UINT8 IntermediateAnchorString[5];
+ UINT8 IntermediateChecksum;
+ UINT16 TableLength;
+ UINT32 TableAddress;
+ UINT16 NumberOfSmbiosStructures;
+ UINT8 SmbiosBcdRevision;
+} SMBIOS_TABLE_ENTRY_POINT;
+```
+
+If you calculate offsets for different fields you can parse memory dump:
+
+![SMBIOS_entry_structure_dump](SMBIOS_entry_structure_dump.png?raw=true "SMBIOS_entry_structure_dump")
+
+System has 9 SMBIOS structures placed from 0x07940000 to (0x07940000+0x191).
+
+Now when we know address for SMBIOS structures, we can dump them as well.
+```
+FS0:\> dmem 07940000 191
+Memory Address 0000000007940000 191 Bytes
+ 07940000: 01 1B 00 01 01 02 03 00-00 00 00 00 00 00 00 00 *................*
+ 07940010: 00 00 00 00 00 00 00 00-06 00 00 51 45 4D 55 00 *...........QEMU.*
+ 07940020: 53 74 61 6E 64 61 72 64-20 50 43 20 28 69 34 34 *Standard PC (i44*
+ 07940030: 30 46 58 20 2B 20 50 49-49 58 2C 20 31 39 39 36 *0FX + PIIX, 1996*
+ 07940040: 29 00 70 63 2D 69 34 34-30 66 78 2D 66 6F 63 61 *).pc-i440fx-foca*
+ 07940050: 6C 00 00 03 16 00 03 01-01 02 00 00 03 03 03 02 *l...............*
+ 07940060: 00 00 00 00 00 00 00 00-00 51 45 4D 55 00 70 63 *.........QEMU.pc*
+ 07940070: 2D 69 34 34 30 66 78 2D-66 6F 63 61 6C 00 00 04 *-i440fx-focal...*
+ 07940080: 2A 00 04 01 03 01 02 63-06 00 00 FD FB 8B 07 03 **......c........*
+ 07940090: 00 00 00 D0 07 D0 07 41-01 FF FF FF FF FF FF 00 *.......A........*
+ 079400A0: 00 00 01 01 01 02 00 01-00 43 50 55 20 30 00 51 *.........CPU 0.Q*
+ 079400B0: 45 4D 55 00 70 63 2D 69-34 34 30 66 78 2D 66 6F *EMU.pc-i440fx-fo*
+ 079400C0: 63 61 6C 00 00 10 17 00-10 01 03 06 00 00 02 00 *cal.............*
+ 079400D0: FE FF 01 00 00 00 00 00-00 00 00 00 00 00 11 28 *...............(*
+ 079400E0: 00 11 00 10 FE FF FF FF-FF FF 80 00 09 00 01 00 *................*
+ 079400F0: 07 02 00 00 00 02 00 00-00 00 00 00 00 00 00 00 *................*
+ 07940100: 00 00 00 00 00 00 44 49-4D 4D 20 30 00 51 45 4D *......DIMM 0.QEM*
+ 07940110: 55 00 00 13 1F 00 13 00-00 00 00 FF FF 01 00 00 *U...............*
+ 07940120: 10 01 00 00 00 00 00 00-00 00 00 00 00 00 00 00 *................*
+ 07940130: 00 00 00 00 20 0B 00 20-00 00 00 00 00 00 00 00 *.... .. ........*
+ 07940140: 00 00 1A 00 00 01 02 00-E8 03 00 08 00 00 00 00 *................*
+ 07940150: 00 00 00 00 1C 00 00 FF-FF 00 00 45 46 49 20 44 *...........EFI D*
+ 07940160: 65 76 65 6C 6F 70 6D 65-6E 74 20 4B 69 74 20 49 *evelopment Kit I*
+ 07940170: 49 20 2F 20 4F 56 4D 46-00 30 2E 30 2E 30 00 30 *I / OVMF.0.0.0.0*
+ 07940180: 32 2F 30 36 2F 32 30 31-35 00 00 7F 04 FF FE 00 *2/06/2015.......*
+ 07940190: 00 *.*
+```
+
+# Use EFI_SMBIOS_PROTOCOL to parse SMBIOS data
+
+We can use direct pointer arithmetics to parse SMBIOS tables, but that would be very tedious.
+
+Luckily UEFI PI specification defines a `EFI_SMBIOS_PROTOCOL`, that we can use to get SMBIOS data.
+
+```
+EFI_SMBIOS_PROTOCOL
+
+Summary:
+Allows consumers to log SMBIOS data records, and enables the producer to create the SMBIOS tables for a platform.
+
+Protocol Interface Structure:
+typedef struct _EFI_SMBIOS_PROTOCOL {
+ EFI_SMBIOS_ADD Add;
+ EFI_SMBIOS_UPDATE_STRINGUpdateString;
+ EFI_SMBIOS_REMOVE Remove;
+ EFI_SMBIOS_GET_NEXT GetNext;
+ UINT8 MajorVersion;
+ UINT8 MinorVersion;
+} EFI_SMBIOS_PROTOCOL;
+
+Member Description:
+Add Add an SMBIOS record including the formatted area and the optional strings
+ that follow the formatted area.
+UpdateString Update a string in the SMBIOS record.
+Remove Remove an SMBIOS record.
+GetNext Discover all SMBIOS records.
+MajorVersion The major revision of the SMBIOS specification supported.
+MinorVersion The minor revision of the SMBIOS specification supported.
+
+Description:
+This protocol provides an interface to add, remove or discover SMBIOS records. The driver which
+produces this protocol is responsible for creating the SMBIOS data tables and installing the pointer
+to the tables in the EFI System Configuration Table.
+```
+
+Right now we are interested in SMBIOS table parsing, so we need to utilize `GetNext` function:
+```
+EFI_SMBIOS_PROTOCOL.GetNext()
+
+Summary:
+Allow the caller to discover all or some of the SMBIOS records.
+Prototype
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SMBIOS_GET_NEXT) (
+ IN CONST EFI_SMBIOS_PROTOCOL *This,
+ IN OUT EFI_SMBIOS_HANDLE *SmbiosHandle,
+ IN EFI_SMBIOS_TYPE *Type, OPTIONAL
+ OUT EFI_SMBIOS_TABLE_HEADER **Record,
+ OUT EFI_HANDLE *ProducerHandle OPTIONAL
+ );
+
+Parameters:
+This The EFI_SMBIOS_PROTOCOL instance.
+SmbiosHandle On entry, points to the previous handle of the SMBIOS record. On exit, points to the
+ next SMBIOS record handle. If it is FFFEh on entry, then the first SMBIOS record
+ handle will be returned. If it returns FFFEh on exit, then there are no more SMBIOS
+ records.
+Type On entry, it points to the type of the next SMBIOS record to return. If NULL, it
+ indicates that the next record of any type will be returned. Type is not modified by
+ the this function.
+Record On exit, points to a pointer to the the SMBIOS Record consisting of the formatted area
+ followed by the unformatted area. The unformatted area optionally contains text
+ strings.
+ProducerHandle On exit, points to the ProducerHandle registered by Add(). If no
+ ProducerHandle was passed into Add() NULL is returned. If a NULL pointer is
+ passed in no data will be returned
+
+Description
+This function allows all of the SMBIOS records to be discovered. It's possible to find
+only the SMBIOS records that match the optional Type argument.
+
+Status Codes Returned:
+EFI_SUCCESS .SMBIOS record information was successfully returned in Record.
+ SmbiosHandle is the handle of the current SMBIOS record
+EFI_NOT_FOUND The SMBIOS record with SmbiosHandle was the last available record.
+```
+
+First let's get this protocol in our app.
+```
+EFI_SMBIOS_PROTOCOL* SmbiosProtocol;
+EFI_STATUS Status = gBS->LocateProtocol (
+ &gEfiSmbiosProtocolGuid,
+ NULL,
+ (VOID**)&SmbiosProtocol
+ );
+if (EFI_ERROR (Status)) {
+ return Status;
+}
+```
+To use it we need to add include to our app https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/Smbios.h:
+```
+#include <Protocol/Smbios.h>
+```
+And add protocol guid to our *.inf file:
+```
+[Protocols]
+ gEfiSmbiosProtocolGuid
+```
+
+Now let's try to get SMBIOS tables. We would be using `SMBIOS_HANDLE_PI_RESERVED` as `EFI_SMBIOS_HANDLE` in protocol calls. You can find explanation in https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/SmBios.h:
+```
+///
+/// Reference SMBIOS 2.7, chapter 6.1.2.
+/// The UEFI Platform Initialization Specification reserves handle number FFFEh for its
+/// EFI_SMBIOS_PROTOCOL.Add() function to mean "assign an unused handle number automatically."
+/// This number is not used for any other purpose by the SMBIOS specification.
+///
+#define SMBIOS_HANDLE_PI_RESERVED 0xFFFE
+```
+
+Also before we start writing code look at the definition of `EFI_SMBIOS_TABLE_HEADER` structure, that we would receive on `GetNext` calls.
+https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/Smbios.h
+```
+typedef SMBIOS_STRUCTURE EFI_SMBIOS_TABLE_HEADER;
+```
+https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/SmBios.h
+```
+///
+/// The Smbios structure header.
+///
+typedef struct {
+ SMBIOS_TYPE Type;
+ UINT8 Length;
+ SMBIOS_HANDLE Handle;
+} SMBIOS_STRUCTURE;
+```
+
+Now we are ready to write some code. Write a code to print all types of Smbios tables that are present in the system:
+```
+EFI_SMBIOS_HANDLE SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
+EFI_SMBIOS_TABLE_HEADER* Record;
+Status = SmbiosProtocol->GetNext(SmbiosProtocol,
+ &SmbiosHandle,
+ NULL,
+ &Record,
+ NULL);
+while (!EFI_ERROR(Status)) {
+ Print (L"SMBIOS Type %d \n", Record->Type);
+ Status = SmbiosProtocol->GetNext(SmbiosProtocol,
+ &SmbiosHandle,
+ NULL,
+ &Record,
+ NULL);
+}
+```
+
+If you build our app and test it under OVMF you would get:
+```
+SMBIOS table is placed at 7941000
+SMBIOS Type 1
+SMBIOS Type 3
+SMBIOS Type 4
+SMBIOS Type 16
+SMBIOS Type 17
+SMBIOS Type 19
+SMBIOS Type 32
+SMBIOS Type 0
+```
+
+Ok, now let's write code that can parse information in these tables.
+
+Let's start with Type 0 table. edk2 has a structure description at https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/SmBios.h:
+```
+///
+/// BIOS Information (Type 0).
+///
+typedef struct {
+ SMBIOS_STRUCTURE Hdr;
+ SMBIOS_TABLE_STRING Vendor;
+ SMBIOS_TABLE_STRING BiosVersion;
+ UINT16 BiosSegment;
+ SMBIOS_TABLE_STRING BiosReleaseDate;
+ UINT8 BiosSize;
+ MISC_BIOS_CHARACTERISTICS BiosCharacteristics;
+ UINT8 BIOSCharacteristicsExtensionBytes[2];
+ UINT8 SystemBiosMajorRelease;
+ UINT8 SystemBiosMinorRelease;
+ UINT8 EmbeddedControllerFirmwareMajorRelease;
+ UINT8 EmbeddedControllerFirmwareMinorRelease;
+ //
+ // Add for smbios 3.1.0
+ //
+ EXTENDED_BIOS_ROM_SIZE ExtendedBiosSize;
+} SMBIOS_TABLE_TYPE0;
+```
+
+In this structure `SMBIOS_STRUCTURE Hdr` is a mandatory field that is the same as `EFI_SMBIOS_TABLE_HEADER` that we receive from our protocol function call.
+
+Also `SMBIOS_TABLE_STRING` is just an UINT8 value that defines a string number in an ASCII string array that is placed directly after the structure.
+
+```
+///
+/// Text strings associated with a given SMBIOS structure are returned in the dmiStrucBuffer, appended directly after
+/// the formatted portion of the structure. This method of returning string information eliminates the need for
+/// application software to deal with pointers embedded in the SMBIOS structure. Each string is terminated with a null
+/// (00h) BYTE and the set of strings is terminated with an additional null (00h) BYTE. When the formatted portion of
+/// a SMBIOS structure references a string, it does so by specifying a non-zero string number within the structure's
+/// string-set. For example, if a string field contains 02h, it references the second string following the formatted portion
+/// of the SMBIOS structure. If a string field references no string, a null (0) is placed in that string field. If the
+/// formatted portion of the structure contains string-reference fields and all the string fields are set to 0 (no string
+/// references), the formatted section of the structure is followed by two null (00h) BYTES.
+///
+typedef UINT8 SMBIOS_TABLE_STRING;
+```
+
+So let's write a simple function that returns actual ASCII string from a `EFI_SMBIOS_TABLE_HEADER*` and a string number:
+```
+CHAR8* GetRecordString(EFI_SMBIOS_TABLE_HEADER* Record, UINTN number)
+{
+ if (!number)
+ return "";
+
+ CHAR8* String = (CHAR8*)Record + Record->Length;
+ UINTN i=1;
+ while (i < number) {
+ String = String + AsciiStrSize(String);
+ i++;
+ }
+ return String;
+}
+```
+Here we've used `AsciiStrSize` function that is defined in https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseLib/String.c file.
+```
+/**
+ Returns the size of a Null-terminated ASCII string in bytes, including the
+ Null terminator.
+ This function returns the size, in bytes, of the Null-terminated ASCII string
+ specified by String.
+ If String is NULL, then ASSERT().
+ If PcdMaximumAsciiStringLength is not zero and String contains more than
+ PcdMaximumAsciiStringLength ASCII characters, not including the Null-terminator,
+ then ASSERT().
+ @param String A pointer to a Null-terminated ASCII string.
+ @return The size of String.
+**/
+UINTN
+EFIAPI
+AsciiStrSize (
+ IN CONST CHAR8 *String
+ )
+```
+
+Now we have everything to write actual parsing code in our `while` loop:
+
+```
+while (!EFI_ERROR(Status)) {
+ Print (L"SMBIOS Type %d \n", Record->Type);
+ switch (Record->Type) {
+ case EFI_SMBIOS_TYPE_BIOS_INFORMATION: {
+ SMBIOS_TABLE_TYPE0* Type0Record = (SMBIOS_TABLE_TYPE0*) Record;
+ Print(L"\tVendor=%a\n", GetRecordString(Record, Type0Record->Vendor));
+ Print(L"\tBiosVersion=%a\n", GetRecordString(Record, Type0Record->BiosVersion));
+ Print(L"\tBiosReleaseDate=%a\n", GetRecordString(Record, Type0Record->BiosReleaseDate));
+ Print(L"\tBiosSegment=0x%x\n", Type0Record->BiosSegment);
+ Print(L"\tSystemBiosMajorRelease=0x%x\n", Type0Record->SystemBiosMajorRelease);
+ Print(L"\tSystemBiosMinorRelease=0x%x\n", Type0Record->SystemBiosMinorRelease);
+ break;
+ }
+ default:
+ Print(L"\tTODO: Parsing for this table is not ready yet\n");
+ break;
+ }
+ Status = SmbiosProtocol->GetNext(SmbiosProtocol,
+ &SmbiosHandle,
+ NULL,
+ &Record,
+ NULL);
+}
+```
+To print ASCII strings here we've used `%a` format code (https://github.com/tianocore/edk/blob/master/Foundation/Library/Pei/PeiLib/Print/Print.c).
+
+
+If you build and execute our app under OVMF you would get:
+```
+FS0:\> SmbiosInfo.efi
+SMBIOS table is placed at 7941000
+
+SMBIOS Type 1
+ TODO: Parsing for this table is not ready yet
+SMBIOS Type 3
+ TODO: Parsing for this table is not ready yet
+SMBIOS Type 4
+ TODO: Parsing for this table is not ready yet
+SMBIOS Type 16
+ TODO: Parsing for this table is not ready yet
+SMBIOS Type 17
+ TODO: Parsing for this table is not ready yet
+SMBIOS Type 19
+ TODO: Parsing for this table is not ready yet
+SMBIOS Type 32
+ TODO: Parsing for this table is not ready yet
+SMBIOS Type 0
+ Vendor=EFI Development Kit II / OVMF
+ BiosVersion=0.0.0
+ BiosReleaseDate=02/06/2015
+ BiosSegment=0xE800
+ SystemBiosMajorRelease=0x0
+ SystemBiosMinorRelease=0x0
+```
+
+If you look closely at `dmem` dump from earlier, you'll see that these are the exact strings that were actually present in memory.
+
+We can easily to add code to parse other SMBIOS tables.
+
+For example here is some parsing code for table type 1 structure:
+```
+case EFI_SMBIOS_TYPE_SYSTEM_INFORMATION: {
+ SMBIOS_TABLE_TYPE1* Type1Record = (SMBIOS_TABLE_TYPE1*) Record;
+ Print(L"\tManufacturer=%a\n", GetRecordString(Record, Type1Record->Manufacturer));
+ Print(L"\tProductName=%a\n", GetRecordString(Record, Type1Record->ProductName));
+ Print(L"\tVersion=%a\n", GetRecordString(Record, Type1Record->Version));
+ Print(L"\tSerialNumber=%a\n", GetRecordString(Record, Type1Record->SerialNumber));
+ Print(L"\tUUID=%g\n", Type1Record->Uuid);
+ Print(L"\tWakeUpType=%d\n", Type1Record->WakeUpType);
+ Print(L"\tSKUNumber=%a\n", GetRecordString(Record, Type1Record->SKUNumber));
+ Print(L"\tFamily=%a\n", GetRecordString(Record, Type1Record->Family));
+ break;
+}
+```
+Structure itself is:
+```
+typedef struct {
+ SMBIOS_STRUCTURE Hdr;
+ SMBIOS_TABLE_STRING Manufacturer;
+ SMBIOS_TABLE_STRING ProductName;
+ SMBIOS_TABLE_STRING Version;
+ SMBIOS_TABLE_STRING SerialNumber;
+ GUID Uuid;
+ UINT8 WakeUpType; ///< The enumeration value from MISC_SYSTEM_WAKEUP_TYPE.
+ SMBIOS_TABLE_STRING SKUNumber;
+ SMBIOS_TABLE_STRING Family;
+} SMBIOS_TABLE_TYPE1;
+```
+
+Build and execute:
+```
+FS0:\> SmbiosInfo.efi
+SMBIOS table is placed at 7941000
+
+SMBIOS Type 1
+ Manufacturer=QEMU
+ ProductName=Standard PC (i440FX + PIIX, 1996)
+ Version=pc-i440fx-focal
+ SerialNumber=
+ UUID=00000000-0000-0000-0000-000000000000
+ WakeUpType=6
+ SKUNumber=
+ Family=
+SMBIOS Type 3
+ TODO: Parsing for this table is not ready yet
+SMBIOS Type 4
+ TODO: Parsing for this table is not ready yet
+SMBIOS Type 16
+ TODO: Parsing for this table is not ready yet
+SMBIOS Type 17
+ TODO: Parsing for this table is not ready yet
+SMBIOS Type 19
+ TODO: Parsing for this table is not ready yet
+SMBIOS Type 32
+ TODO: Parsing for this table is not ready yet
+SMBIOS Type 0
+ Vendor=EFI Development Kit II / OVMF
+ BiosVersion=0.0.0
+ BiosReleaseDate=02/06/2015
+ BiosSegment=0xE800
+ SystemBiosMajorRelease=0x0
+ SystemBiosMinorRelease=0x0
+```
+
+As you remember the same information that is present in these SMBIOS tables is present in the main BIOS menu:
+
+![BIOS_menu](BIOS_menu.png?raw=true "BIOS_menu")
+
+And in case you wonder where OVMF defines all these information for its SMBIOS structures, checkout https://github.com/tianocore/edk2/blob/master/OvmfPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.c and implementation of a `EFI_SMBIOS_PROTOCOL` is placed here https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.c
+
+# `smbiosview` command
+
+We can use `EFI_SMBIOS_PROTOCOL` to parse SMBIOS table information, but actually if you just want to see SMBIOS information there is a better option.
+
+UEFI shell has a `smbiosview` command that does exactly what we need.
+
+You can checkout sources for this command here: https://github.com/tianocore/edk2/tree/master/ShellPkg/Library/UefiShellDebug1CommandsLib/SmbiosView
+
+First checkout help for this command:
+```
+FS0:\> smbiosview -?
+Displays SMBIOS information.
+
+SMBIOSVIEW [-t SmbiosType]|[-h SmbiosHandle]|[-s]|[-a]
+
+ -t - Displays all structures of SmbiosType.
+ -h - Displays structure of SmbiosHandle.
+ -s - Displays a statistics table.
+ -a - Displays all information.
+ SmbiosType - Specifies a SMBIOS structure type.
+ SmbiosHandle - Specifies a SMBIOS structure unique 16-bit handle.
+
+NOTES:
+ 1. The SmbiosType parameter supports the following types:
+ 0 - BIOS Information
+ 1 - System Information
+ 2 - Baseboard Information
+ 3 - System Enclosure
+ 4 - Processor Information
+ 5 - Memory Controller Information
+ 6 - Memory Module Information
+ 7 - Cache Information
+ 8 - Port Connector Information
+ 9 - System Slots
+ 10 - On Board Devices Information
+ 11 - OEM Strings
+ 12 - System Configuration Options
+ 13 - BIOS Language Information
+ 14 - Group Associations
+ 15 - System Event Log
+ 16 - Physical Memory Array
+ 17 - Memory Device
+ 18 - 32-bit Memory Error Information
+ 19 - Memory Array Mapped Address
+ 20 - Memory Device Mapped Address
+ 21 - Built-in Pointing Device
+ 22 - Portable Battery
+ 23 - System Reset
+ 24 - Hardware Security
+ 25 - System Power Controls
+ 26 - Voltage Probe
+ 27 - Cooling Device
+ 28 - Temperature Probe
+ 29 - Electrical Current Probe
+ 30 - Out-Of-Band Remote Access
+ 31 - Boot Integrity Services (BIS) Entry Point
+ 32 - System Boot Information
+ 33 - 64-Bit Memory Error Information
+ 34 - Management Device
+ 35 - Management Device Component
+ 36 - Management Device Threshold Data
+ 37 - Memory Channel
+ 38 - IPMI Device Information
+ 39 - System Power Supply
+ 40 - Additional Information
+ 41 - Onboard Devices Extended Information
+ 42 - Management Controller Host Interface
+ 43 - TPM Device
+ 44 - Processor Additional Information
+ 2. Enter the SmbiosHandle parameter in hexadecimal format.
+ Do not use the '0x' prefix format for hexadecimal values.
+ 3. Internal commands:
+ :q -------- quit smbiosview
+ :0 -------- Change smbiosview display NONE info
+ :1 -------- Change smbiosview display OUTLINE info
+ :2 -------- Change smbiosview display NORMAL info
+ :3 -------- Change smbiosview display DETAIL info
+ /? -------- Show help
+```
+
+Try to dump one of the structures that we've tried to parse manually:
+```
+FS0:\> smbiosview -t 0
+SMBIOS Entry Point Structure:
+Anchor String: _SM_
+EPS Checksum: 0x26
+Entry Point Len: 31
+Version: 2.8
+Number of Structures: 9
+Max Struct size: 83
+Table Address: 0x7940000
+Table Length: 401
+Entry Point revision: 0x0
+SMBIOS BCD Revision: 0x28
+Inter Anchor: _DMI_
+Inter Checksum: 0xA
+Formatted Area:
+ 00000000: 00 00 00 00 00 *.....*
+
+=========================================================
+Query Structure, conditions are:
+QueryType = 0
+QueryHandle = Random
+ShowType = SHOW_DETAIL
+
+
+=========================================================
+Type=0, Handle=0x0
+Dump Structure as:
+Index=7,Length=0x4A,Addr=0x7940141
+00000000: 00 1A 00 00 01 02 00 E8-03 00 08 00 00 00 00 00 *................*
+FS0:\> 0: 00 00 00 1C 00 00 FF FF-00 00 45 46 49 20 44 65 *..........EFI De*
+00000020: 76 65 6C 6F 70 6D 65 6E-74 20 4B 69 74 20 49 49 *velopment Kit II*
+00000030: 20 2F 20 4F 56 4D 46 00-30 2E 30 2E 30 00 30 32 * / OVMF.0.0.0.02*
+00000040: 2F 30 36 2F 32 30 31 35-00 00 */06/2015..*
+Structure Type: BIOS Information
+Format part Len : 26
+Structure Handle: 0
+Vendor: EFI Development Kit II / OVMF
+BiosVersion: 0.0.0
+BiosSegment: 0xE800
+BiosReleaseDate: 02/06/2015
+BiosSize: 64 KB
+BIOS Characteristics:
+BIOS Characteristics Not Supported
+ Bits 32:47 are reserved for BIOS Vendor
+ Bits 48:64 are reserved for System Vendor
+BIOS Characteristics Extension Byte1:
+BIOS Characteristics Extension Byte2:
+Enable Targeted Content Distribution
+UEFI Specification is supported
+The SMBIOS table describes a virtual machine
+ Bits 5:7 are reserved for future assignment
+SystemBiosMajorRelease: 0
+SystemBiosMinorRelease: 0
+EmbeddedControllerFirmwareMajorRelease: 255
+EmbeddedControllerFirmwareMinorRelease: 255
+```
+As you can see it is all the same info that we've received using `EFI_SMBIOS_PROTOCOL`.
+
+You can use this command to see what is inside all of the SMBIOS structures using:
+```
+FS0:\> smbiosview -b
+...
+```
+
+The output is too big to paste here, so check it out yourself!
diff --git a/Lessons/Lesson_27/SMBIOS_entry_structure.png b/Lessons/Lesson_27/SMBIOS_entry_structure.png
new file mode 100644
index 0000000..f488425
--- /dev/null
+++ b/Lessons/Lesson_27/SMBIOS_entry_structure.png
Binary files differ
diff --git a/Lessons/Lesson_27/SMBIOS_entry_structure_dump.png b/Lessons/Lesson_27/SMBIOS_entry_structure_dump.png
new file mode 100644
index 0000000..ff27b9b
--- /dev/null
+++ b/Lessons/Lesson_27/SMBIOS_entry_structure_dump.png
Binary files differ
diff --git a/Lessons/Lesson_27/UefiLessonsPkg/SmbiosInfo/SmbiosInfo.c b/Lessons/Lesson_27/UefiLessonsPkg/SmbiosInfo/SmbiosInfo.c
new file mode 100644
index 0000000..b75026d
--- /dev/null
+++ b/Lessons/Lesson_27/UefiLessonsPkg/SmbiosInfo/SmbiosInfo.c
@@ -0,0 +1,88 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Protocol/Smbios.h>
+
+CHAR8* GetRecordString(EFI_SMBIOS_TABLE_HEADER* Record, UINTN number)
+{
+ if (!number)
+ return "";
+
+ CHAR8* String = (CHAR8*)Record + Record->Length;
+ UINTN i=1;
+ while (i < number) {
+ String = String + AsciiStrSize(String);
+ i++;
+ }
+ return String;
+}
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ for (UINTN i=0; i<SystemTable->NumberOfTableEntries; i++) {
+ if (CompareGuid(&(SystemTable->ConfigurationTable[i].VendorGuid), &gEfiSmbiosTableGuid)) {
+ Print(L"SMBIOS table is placed at %p\n\n", SystemTable->ConfigurationTable[i].VendorTable);
+ }
+ }
+
+ EFI_SMBIOS_PROTOCOL* SmbiosProtocol;
+ EFI_STATUS Status = gBS->LocateProtocol (
+ &gEfiSmbiosProtocolGuid,
+ NULL,
+ (VOID**)&SmbiosProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ EFI_SMBIOS_HANDLE SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
+ EFI_SMBIOS_TABLE_HEADER* Record;
+ Status = SmbiosProtocol->GetNext(SmbiosProtocol,
+ &SmbiosHandle,
+ NULL,
+ &Record,
+ NULL);
+ while (!EFI_ERROR(Status)) {
+ Print (L"SMBIOS Type %d \n", Record->Type);
+ switch (Record->Type) {
+ case EFI_SMBIOS_TYPE_BIOS_INFORMATION: {
+ SMBIOS_TABLE_TYPE0* Type0Record = (SMBIOS_TABLE_TYPE0*) Record;
+ Print(L"\tVendor=%a\n", GetRecordString(Record, Type0Record->Vendor));
+ Print(L"\tBiosVersion=%a\n", GetRecordString(Record, Type0Record->BiosVersion));
+ Print(L"\tBiosReleaseDate=%a\n", GetRecordString(Record, Type0Record->BiosReleaseDate));
+ Print(L"\tBiosSegment=0x%x\n", Type0Record->BiosSegment);
+ Print(L"\tSystemBiosMajorRelease=0x%x\n", Type0Record->SystemBiosMajorRelease);
+ Print(L"\tSystemBiosMinorRelease=0x%x\n", Type0Record->SystemBiosMinorRelease);
+ break;
+ }
+ case EFI_SMBIOS_TYPE_SYSTEM_INFORMATION: {
+ SMBIOS_TABLE_TYPE1* Type1Record = (SMBIOS_TABLE_TYPE1*) Record;
+ Print(L"\tManufacturer=%a\n", GetRecordString(Record, Type1Record->Manufacturer));
+ Print(L"\tProductName=%a\n", GetRecordString(Record, Type1Record->ProductName));
+ Print(L"\tVersion=%a\n", GetRecordString(Record, Type1Record->Version));
+ Print(L"\tSerialNumber=%a\n", GetRecordString(Record, Type1Record->SerialNumber));
+ Print(L"\tUUID=%g\n", Type1Record->Uuid);
+ Print(L"\tWakeUpType=%d\n", Type1Record->WakeUpType);
+ Print(L"\tSKUNumber=%a\n", GetRecordString(Record, Type1Record->SKUNumber));
+ Print(L"\tFamily=%a\n", GetRecordString(Record, Type1Record->Family));
+ break;
+ }
+ default:
+ Print(L"\tTODO: Parsing for this table is not ready yet\n");
+ break;
+ }
+ Status = SmbiosProtocol->GetNext(SmbiosProtocol,
+ &SmbiosHandle,
+ NULL,
+ &Record,
+ NULL);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_27/UefiLessonsPkg/SmbiosInfo/SmbiosInfo.inf b/Lessons/Lesson_27/UefiLessonsPkg/SmbiosInfo/SmbiosInfo.inf
new file mode 100644
index 0000000..ab6013a
--- /dev/null
+++ b/Lessons/Lesson_27/UefiLessonsPkg/SmbiosInfo/SmbiosInfo.inf
@@ -0,0 +1,24 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = SmbiosInfo
+ FILE_GUID = 4a8836db-9e1d-4b7d-a785-f552340fba59
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ SmbiosInfo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
+[Guids]
+ gEfiSmbiosTableGuid
+
+[Protocols]
+ gEfiSmbiosProtocolGuid
+
diff --git a/Lessons/Lesson_28/README.md b/Lessons/Lesson_28/README.md
new file mode 100644
index 0000000..3927045
--- /dev/null
+++ b/Lessons/Lesson_28/README.md
@@ -0,0 +1,551 @@
+The latest ACPI specification can be found under UEFI specifications page https://uefi.org/specifications
+
+The current latest specification is "ACPI Specification Version 6.4 (released January 2021)" (https://uefi.org/specs/ACPI/6.4/)
+
+
+Use the same tactic we used for SMBIOS tables to print ACPI entry point table address:
+```
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/BaseMemoryLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ for (UINTN i=0; i<SystemTable->NumberOfTableEntries; i++) {
+ if (CompareGuid(&(SystemTable->ConfigurationTable[i].VendorGuid), &gEfiAcpi20TableGuid)) {
+ Print(L"ACPI table is placed at %p\n\n", SystemTable->ConfigurationTable[i].VendorTable);
+ }
+ }
+ return EFI_SUCCESS;
+}
+```
+
+Use `dmem` to peak inside ACPI table memory:
+```
+FS0:\> AcpiInfo.efi
+ACPI table is placed at 7B7E014
+
+FS0:\> dmem 7B7E014 30
+Memory Address 0000000007B7E014 30 Bytes
+ 07B7E014: 52 53 44 20 50 54 52 20-4E 42 4F 43 48 53 20 02 *RSD PTR NBOCHS .*
+ 07B7E024: 74 D0 B7 07 24 00 00 00-E8 D0 B7 07 00 00 00 00 *t...$...........*
+ 07B7E034: 66 00 00 00 AF AF AF AF-AF AF AF AF AF AF AF AF *f...............*
+FS0:\>
+```
+
+The signature `RSP PTR` stands for `Root System Description Pointer (RSDP) Structure` (https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#root-system-description-pointer-rsdp-structure).
+
+It contains addresses for `RSDT` and `XSDT` tables. If you calculate offsets, you'll get these addresses from our memory dump:
+```
+XSDT=0x07B7D0E8
+RSDT=0x07B7D074
+```
+These tables in turn would cointain pointers to other ACPI tables that actualy contain data useful to OS.
+
+According to the spec "platforms provide the RSDT to enable compatibility with ACPI 1.0 operating systems. The XSDT supersedes RSDT functionality". So if you peak these addresses with `dmem`, table contents would be pretty much the same except table signatures. Therefore in our app code we would be parsing XSDT table data.
+
+Ok, it's time to write some code. ACPI structures are defined in the following header files:
+```
+$ ls -1 MdePkg/Include/IndustryStandard/Acpi*
+MdePkg/Include/IndustryStandard/Acpi.h
+MdePkg/Include/IndustryStandard/Acpi10.h
+MdePkg/Include/IndustryStandard/Acpi20.h
+MdePkg/Include/IndustryStandard/Acpi30.h
+MdePkg/Include/IndustryStandard/Acpi40.h
+MdePkg/Include/IndustryStandard/Acpi50.h
+MdePkg/Include/IndustryStandard/Acpi51.h
+MdePkg/Include/IndustryStandard/Acpi60.h
+MdePkg/Include/IndustryStandard/Acpi61.h
+MdePkg/Include/IndustryStandard/Acpi62.h
+MdePkg/Include/IndustryStandard/Acpi63.h
+MdePkg/Include/IndustryStandard/AcpiAml.h
+```
+
+Keep in mind that headers for latter standards include headers for earlier standards in itself.
+```
+Acpi.h > Acpi63.h > Acpi62.h > ... > Acpi10.h > AcpiAml.h
+```
+
+Let's look at RSDP structure definition at the most latest ACPI standard header file
+https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Acpi63.h
+```
+///
+/// Root System Description Pointer Structure
+///
+typedef struct {
+ UINT64 Signature;
+ UINT8 Checksum;
+ UINT8 OemId[6];
+ UINT8 Revision;
+ UINT32 RsdtAddress;
+ UINT32 Length;
+ UINT64 XsdtAddress;
+ UINT8 ExtendedChecksum;
+ UINT8 Reserved[3];
+} EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER;
+```
+
+We can use it to print addresses of RSDT/XSDT tables.
+```
+EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER* RSDP = NULL;
+
+for (UINTN i=0; i<SystemTable->NumberOfTableEntries; i++) {
+ if (CompareGuid(&(SystemTable->ConfigurationTable[i].VendorGuid), &gEfiAcpi20TableGuid)) {
+ Print(L"RSDP table is placed at %p\n\n", SystemTable->ConfigurationTable[i].VendorTable);
+ RSDP = SystemTable->ConfigurationTable[i].VendorTable;
+ }
+}
+
+if (!RSDP) {
+ Print(L"No ACPI2.0 table was found in the system\n");
+ return EFI_SUCCESS;
+}
+
+if (((CHAR8)((RSDP->Signature >> 0) & 0xFF) != 'R') ||
+ ((CHAR8)((RSDP->Signature >> 8) & 0xFF) != 'S') ||
+ ((CHAR8)((RSDP->Signature >> 16) & 0xFF) != 'D') ||
+ ((CHAR8)((RSDP->Signature >> 24) & 0xFF) != ' ') ||
+ ((CHAR8)((RSDP->Signature >> 32) & 0xFF) != 'P') ||
+ ((CHAR8)((RSDP->Signature >> 40) & 0xFF) != 'T') ||
+ ((CHAR8)((RSDP->Signature >> 48) & 0xFF) != 'R') ||
+ ((CHAR8)((RSDP->Signature >> 56) & 0xFF) != ' ')) {
+ Print(L"Error! RSDP signature is not valid!\n");
+ return EFI_SUCCESS;
+}
+
+Print(L"System description tables:\n");
+Print(L"\tRSDT table is placed at address %p\n", RSDP->RsdtAddress);
+Print(L"\tXSDT table is placed at address %p\n", RSDP->XsdtAddress);
+Print(L"\n");
+```
+
+In the same file (https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Acpi63.h) you can find description for XSDT structure:
+```
+//
+// Extended System Description Table
+// No definition needed as it is a common description table header, the same with
+// EFI_ACPI_DESCRIPTION_HEADER, followed by a variable number of UINT64 table pointers.
+//
+```
+
+The definition for `EFI_ACPI_DESCRIPTION_HEADER` can be found here https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Acpi10.h:
+```
+#pragma pack(1)
+///
+/// The common ACPI description table header. This structure prefaces most ACPI tables.
+///
+typedef struct {
+ UINT32 Signature;
+ UINT32 Length;
+ UINT8 Revision;
+ UINT8 Checksum;
+ UINT8 OemId[6];
+ UINT64 OemTableId;
+ UINT32 OemRevision;
+ UINT32 CreatorId;
+ UINT32 CreatorRevision;
+} EFI_ACPI_DESCRIPTION_HEADER;
+#pragma pack()
+```
+
+Let's check information about other ACPI tables that are present in the system:
+```
+EFI_ACPI_DESCRIPTION_HEADER* XSDT = (EFI_ACPI_DESCRIPTION_HEADER*)RSDP->XsdtAddress;
+if (((CHAR8)((XSDT->Signature >> 0) & 0xFF) != 'X') ||
+ ((CHAR8)((XSDT->Signature >> 8) & 0xFF) != 'S') ||
+ ((CHAR8)((XSDT->Signature >> 16) & 0xFF) != 'D') ||
+ ((CHAR8)((XSDT->Signature >> 24) & 0xFF) != 'T')) {
+ Print(L"Error! XSDT signature is not valid!\n");
+ return EFI_SUCCESS;
+}
+
+Print(L"Main ACPI tables:\n");
+UINT64 offset = sizeof(EFI_ACPI_DESCRIPTION_HEADER);
+while (offset < XSDT->Length) {
+ UINT64* table_address = (UINT64*)((UINT8*)XSDT + offset);
+ EFI_ACPI_6_3_COMMON_HEADER* table = (EFI_ACPI_6_3_COMMON_HEADER*)(*table_address);
+ TableName[0] = (CHAR16)((table->Signature>> 0)&0xFF);
+ TableName[1] = (CHAR16)((table->Signature>> 8)&0xFF);
+ TableName[2] = (CHAR16)((table->Signature>>16)&0xFF);
+ TableName[3] = (CHAR16)((table->Signature>>24)&0xFF);
+ TableName[4] = 0;
+
+ Print(L"\t%s table is placed at address %p with length 0x%x\n",
+ TableName,
+ table,
+ table->Length);
+ offset += sizeof(UINT64);
+}
+```
+
+If you build our app and execute it under OVMF now you would get:
+```
+FS0:\> AcpiInfo.efi
+RSDP table is placed at 7B7E014
+
+System description tables:
+ RSDT table is placed at address 7B7D074
+ XSDT table is placed at address 7B7D0E8
+
+Main ACPI tables:
+ FACP table is placed at address 7B7A000 with length 0x74
+ APIC table is placed at address 7B79000 with length 0x78
+ HPET table is placed at address 7B78000 with length 0x38
+ BGRT table is placed at address 7B77000 with length 0x38
+```
+
+Pretty neat, our system has 4 ACPI data tables:
+- Fixed ACPI Description Table (`FACP`) - https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#fixed-acpi-description-table-fadt
+- Multiple APIC Description Table (`MADT`) - https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#multiple-apic-description-table-madt
+- IA-PC High Precision Event Timer Table (`HPET`) - http://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/software-developers-hpet-spec-1-0a.pdf - This one is not present in ACPI spec, but in a separate document from the page https://uefi.org/acpi
+- Boot Graphics Resource Table (`BGRT`) - https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#boot-graphics-resource-table-bgrt
+
+
+Keep in mind that as with SMBIOS tables we could use a protocol to get the same data. `GetAcpiTable()` function of a `EFI_ACPI_SDT_PROTOCOL` can help to get the same information. This protocol also is defined by UEFI PI specification.
+
+In edk2 it is defined under https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/AcpiSystemDescriptionTable.h
+
+# Use `EFI_SHELL_PROTOCOL` to save table data
+
+Now let's try to save ACPI tables from memory to files.
+
+To do this we can utilize `EFI_SHELL_PROTOCOL` that is defined in UEFI Shell specification (https://uefi.org/sites/default/files/resources/UEFI_Shell_2_2.pdf). It has many functions for File I/O.
+
+The necessary header in edk2 is https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/Shell.h
+```
+typedef struct _EFI_SHELL_PROTOCOL {
+ EFI_SHELL_EXECUTE Execute;
+ EFI_SHELL_GET_ENV GetEnv;
+ EFI_SHELL_SET_ENV SetEnv;
+ EFI_SHELL_GET_ALIAS GetAlias;
+ EFI_SHELL_SET_ALIAS SetAlias;
+ EFI_SHELL_GET_HELP_TEXT GetHelpText;
+ EFI_SHELL_GET_DEVICE_PATH_FROM_MAP GetDevicePathFromMap;
+ EFI_SHELL_GET_MAP_FROM_DEVICE_PATH GetMapFromDevicePath;
+ EFI_SHELL_GET_DEVICE_PATH_FROM_FILE_PATH GetDevicePathFromFilePath;
+ EFI_SHELL_GET_FILE_PATH_FROM_DEVICE_PATH GetFilePathFromDevicePath;
+ EFI_SHELL_SET_MAP SetMap;
+ EFI_SHELL_GET_CUR_DIR GetCurDir;
+ EFI_SHELL_SET_CUR_DIR SetCurDir;
+ EFI_SHELL_OPEN_FILE_LIST OpenFileList;
+ EFI_SHELL_FREE_FILE_LIST FreeFileList;
+ EFI_SHELL_REMOVE_DUP_IN_FILE_LIST RemoveDupInFileList;
+ EFI_SHELL_BATCH_IS_ACTIVE BatchIsActive;
+ EFI_SHELL_IS_ROOT_SHELL IsRootShell;
+ EFI_SHELL_ENABLE_PAGE_BREAK EnablePageBreak;
+ EFI_SHELL_DISABLE_PAGE_BREAK DisablePageBreak;
+ EFI_SHELL_GET_PAGE_BREAK GetPageBreak;
+ EFI_SHELL_GET_DEVICE_NAME GetDeviceName;
+ EFI_SHELL_GET_FILE_INFO GetFileInfo;
+ EFI_SHELL_SET_FILE_INFO SetFileInfo;
+ EFI_SHELL_OPEN_FILE_BY_NAME OpenFileByName;
+ EFI_SHELL_CLOSE_FILE CloseFile;
+ EFI_SHELL_CREATE_FILE CreateFile;
+ EFI_SHELL_READ_FILE ReadFile;
+ EFI_SHELL_WRITE_FILE WriteFile;
+ EFI_SHELL_DELETE_FILE DeleteFile;
+ EFI_SHELL_DELETE_FILE_BY_NAME DeleteFileByName;
+ EFI_SHELL_GET_FILE_POSITION GetFilePosition;
+ EFI_SHELL_SET_FILE_POSITION SetFilePosition;
+ EFI_SHELL_FLUSH_FILE FlushFile;
+ EFI_SHELL_FIND_FILES FindFiles;
+ EFI_SHELL_FIND_FILES_IN_DIR FindFilesInDir;
+ EFI_SHELL_GET_FILE_SIZE GetFileSize;
+ EFI_SHELL_OPEN_ROOT OpenRoot;
+ EFI_SHELL_OPEN_ROOT_BY_HANDLE OpenRootByHandle;
+ EFI_EVENT ExecutionBreak;
+ UINT32 MajorVersion;
+ UINT32 MinorVersion;
+ // Added for Shell 2.1
+ EFI_SHELL_REGISTER_GUID_NAME RegisterGuidName;
+ EFI_SHELL_GET_GUID_NAME GetGuidName;
+ EFI_SHELL_GET_GUID_FROM_NAME GetGuidFromName;
+ EFI_SHELL_GET_ENV_EX GetEnvEx;
+} EFI_SHELL_PROTOCOL;
+```
+
+We will use 3 functions from this protocol `OpenFileByName`/`WriteFile`/`CloseFile`:
+```
+EFI_SHELL_PROTOCOL.OpenFileByName()
+
+Summary:
+Opens a file or a directory by file name.
+
+Prototype:
+typdef
+EFI_STATUS
+(EFIAPI *EFI_SHELL_OPEN_FILE_BY_NAME) (
+ IN CONST CHAR16 *FileName,
+ OUT SHELL_FILE_HANDLE *FileHandle,
+ IN UINT64 OpenMode
+ );
+
+Parameters:
+FileName Points to the null-terminated UCS-2 encoded file name.
+FileHandle On return, points to the file handle.
+OpenMode File open mode.
+
+Description:
+This function opens the specified file in the specified OpenMode and returns a file handle.
+```
+```
+EFI_SHELL_PROTOCOL.WriteFile()
+
+Summary:
+Writes data to the file.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI EFI_SHELL_WRITE_FILE)(
+ IN SHELL_FILE_HANDLE FileHandle,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+Parameters:
+FileHandle The opened file handle for writing.
+BufferSize On input, size of Buffer.
+Buffer The buffer in which data to write.
+
+Description:
+This function writes the specified number of bytes to the file at the current file position. The current file position is advanced the actual number of bytes
+written, which is returned in BufferSize. Partial writes only occur when there has been a data error during the write attempt (such as “volume space full”).
+The file automatically grows to hold the data, if required.
+```
+```
+EFI_SHELL_PROTOCOL.CloseFile()
+
+Summary:
+Closes the file handle.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_SHELL_CLOSE_FILE)(
+ IN SHELL_FILE_HANDLE FileHandle
+ );
+
+Parameters:
+FileHandle The file handle to be closed
+Description This function closes a specified file handle. All “dirty” cached file data is flushed
+ to the device, and the file is closed. In all cases, the handle is closed.
+
+```
+
+Now let's start coding. Add necessary include to our *.c file:
+```
+#include <Protocol/Shell.h>
+```
+And necessary protocol guid to our *.inf file:
+```
+[Protocols]
+ gEfiShellProtocolGuid
+```
+
+In our program we need to acquire `EFI_SHELL_PROTOCOL`, this can be done via `LocateProtocol` function from the BootServices:
+```
+EFI_SHELL_PROTOCOL* ShellProtocol;
+EFI_STATUS Status = gBS->LocateProtocol(
+ &gEfiShellProtocolGuid,
+ NULL,
+ (VOID **)&ShellProtocol
+);
+
+if (EFI_ERROR(Status)) {
+ Print(L"Can't open EFI_SHELL_PROTOCOL: %r\n", Status);
+ return EFI_SUCCESS;
+}
+```
+
+Then use `EFI_SHELL_PROTOCOL` functions in our while loop to create files with ACPI table data. For every table we will create a file "<signature>.aml". We use `.aml` extension for our files because in ACPI language source files usually have *.asl/*.dsl extension (ACPI Source Language), and compiled files have *.aml extension (ACPI Machine Language):
+```
+CHAR16 FileName[9] = {0};
+StrCpyS(FileName, 9, TableName);
+StrCatS(FileName, 9, L".aml");
+Print(L"%s\n", FileName);
+SHELL_FILE_HANDLE FileHandle;
+Status = ShellProtocol->OpenFileByName(FileName,
+ &FileHandle,
+ EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ);
+
+if (!EFI_ERROR(Status)) {
+ UINTN size = table->Length;
+ Status = ShellProtocol->WriteFile(FileHandle, &size, (VOID*)table);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error in WriteFile: %r\n", Status);
+ }
+ Status = ShellProtocol->CloseFile(FileHandle);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error in CloseFile: %r\n", Status);
+ }
+} else {
+ Print(L"Error in OpenFileByName: %r\n", Status);
+}
+```
+
+To create a string with a file name we use `StrCatS` and `StrCpyS` functions. They are safe versions of string concatention/string copy functions similar to their C++ analogs `strcat_s`/`strcpy_s`. You can check out them in a library https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseLib/SafeString.c
+
+With a help of `EFI_SHELL_PROTOCOL` file operation functions writing data to a file is pretty similar to standard system programming. We open handle, write data to it, and finally close handle.
+
+If you build our app and execute it under OVMF you would get 4 files in our `UEFI_disk` shared folder:
+```
+$ ls -1 ~/UEFI_disk/*.aml
+/home/kostr/UEFI_disk/apic.aml
+/home/kostr/UEFI_disk/bgrt.aml
+/home/kostr/UEFI_disk/facp.aml
+/home/kostr/UEFI_disk/hpet.aml
+```
+
+You can use `iasl` compiler to disassemle ACPI table data:
+```
+$ iasl -d ~/UEFI_disk/*.aml
+
+Intel ACPI Component Architecture
+ASL+ Optimizing Compiler/Disassembler version 20190509
+Copyright (c) 2000 - 2019 Intel Corporation
+
+File appears to be binary: found 81 non-ASCII characters, disassembling
+Binary file appears to be a valid ACPI table, disassembling
+Input file /home/kostr/UEFI_disk/apic.aml, Length 0x78 (120) bytes
+ACPI: APIC 0x0000000000000000 000078 (v01 BOCHS BXPCAPIC 00000001 BXPC 00000001)
+Acpi Data Table [APIC] decoded
+Formatted output: /home/kostr/UEFI_disk/apic.dsl - 4935 bytes
+File appears to be binary: found 32 non-ASCII characters, disassembling
+Binary file appears to be a valid ACPI table, disassembling
+Input file /home/kostr/UEFI_disk/bgrt.aml, Length 0x38 (56) bytes
+ACPI: BGRT 0x0000000000000000 000038 (v01 INTEL EDK2 00000002 01000013)
+Acpi Data Table [BGRT] decoded
+Formatted output: /home/kostr/UEFI_disk/bgrt.dsl - 1628 bytes
+File appears to be binary: found 91 non-ASCII characters, disassembling
+Binary file appears to be a valid ACPI table, disassembling
+Input file /home/kostr/UEFI_disk/facp.aml, Length 0x74 (116) bytes
+ACPI: FACP 0x0000000000000000 000074 (v01 BOCHS BXPCFACP 00000001 BXPC 00000001)
+Acpi Data Table [FACP] decoded
+Formatted output: /home/kostr/UEFI_disk/facp.dsl - 4892 bytes
+File appears to be binary: found 33 non-ASCII characters, disassembling
+Binary file appears to be a valid ACPI table, disassembling
+Input file /home/kostr/UEFI_disk/hpet.aml, Length 0x38 (56) bytes
+ACPI: HPET 0x0000000000000000 000038 (v01 BOCHS BXPCHPET 00000001 BXPC 00000001)
+Acpi Data Table [HPET] decoded
+Formatted output: /home/kostr/UEFI_disk/hpet.dsl - 1887 bytes
+```
+
+Now you have *.dsl files in the same `UEFI_disk` shared folder.
+
+For example here is a content for `APIC` table:
+```
+$ cat ~/UEFI_disk/apic.dsl
+/*
+ * Intel ACPI Component Architecture
+ * AML/ASL+ Disassembler version 20190509 (64-bit version)
+ * Copyright (c) 2000 - 2019 Intel Corporation
+ *
+ * Disassembly of /home/kostr/UEFI_disk/apic.aml, Sat Jul 3 00:09:16 2021
+ *
+ * ACPI Data Table [APIC]
+ *
+ * Format: [HexOffset DecimalOffset ByteLength] FieldName : FieldValue
+ */
+
+[000h 0000 4] Signature : "APIC" [Multiple APIC Description Table (MADT)]
+[004h 0004 4] Table Length : 00000078
+[008h 0008 1] Revision : 01
+[009h 0009 1] Checksum : ED
+[00Ah 0010 6] Oem ID : "BOCHS "
+[010h 0016 8] Oem Table ID : "BXPCAPIC"
+[018h 0024 4] Oem Revision : 00000001
+[01Ch 0028 4] Asl Compiler ID : "BXPC"
+[020h 0032 4] Asl Compiler Revision : 00000001
+
+[024h 0036 4] Local Apic Address : FEE00000
+[028h 0040 4] Flags (decoded below) : 00000001
+ PC-AT Compatibility : 1
+
+[02Ch 0044 1] Subtable Type : 00 [Processor Local APIC]
+[02Dh 0045 1] Length : 08
+[02Eh 0046 1] Processor ID : 00
+[02Fh 0047 1] Local Apic ID : 00
+[030h 0048 4] Flags (decoded below) : 00000001
+ Processor Enabled : 1
+ Runtime Online Capable : 0
+
+[034h 0052 1] Subtable Type : 01 [I/O APIC]
+[035h 0053 1] Length : 0C
+[036h 0054 1] I/O Apic ID : 00
+[037h 0055 1] Reserved : 00
+[038h 0056 4] Address : FEC00000
+[03Ch 0060 4] Interrupt : 00000000
+
+[040h 0064 1] Subtable Type : 02 [Interrupt Source Override]
+[041h 0065 1] Length : 0A
+[042h 0066 1] Bus : 00
+[043h 0067 1] Source : 00
+[044h 0068 4] Interrupt : 00000002
+[048h 0072 2] Flags (decoded below) : 0000
+ Polarity : 0
+ Trigger Mode : 0
+
+[04Ah 0074 1] Subtable Type : 02 [Interrupt Source Override]
+[04Bh 0075 1] Length : 0A
+[04Ch 0076 1] Bus : 00
+[04Dh 0077 1] Source : 05
+[04Eh 0078 4] Interrupt : 00000005
+[052h 0082 2] Flags (decoded below) : 000D
+ Polarity : 1
+ Trigger Mode : 3
+
+[054h 0084 1] Subtable Type : 02 [Interrupt Source Override]
+[055h 0085 1] Length : 0A
+[056h 0086 1] Bus : 00
+[057h 0087 1] Source : 09
+[058h 0088 4] Interrupt : 00000009
+[05Ch 0092 2] Flags (decoded below) : 000D
+ Polarity : 1
+ Trigger Mode : 3
+
+[05Eh 0094 1] Subtable Type : 02 [Interrupt Source Override]
+[05Fh 0095 1] Length : 0A
+[060h 0096 1] Bus : 00
+[061h 0097 1] Source : 0A
+[062h 0098 4] Interrupt : 0000000A
+[066h 0102 2] Flags (decoded below) : 000D
+ Polarity : 1
+ Trigger Mode : 3
+
+[068h 0104 1] Subtable Type : 02 [Interrupt Source Override]
+[069h 0105 1] Length : 0A
+[06Ah 0106 1] Bus : 00
+[06Bh 0107 1] Source : 0B
+[06Ch 0108 4] Interrupt : 0000000B
+[070h 0112 2] Flags (decoded below) : 000D
+ Polarity : 1
+ Trigger Mode : 3
+
+[072h 0114 1] Subtable Type : 04 [Local APIC NMI]
+[073h 0115 1] Length : 06
+[074h 0116 1] Processor ID : FF
+[075h 0117 2] Flags (decoded below) : 0000
+ Polarity : 0
+ Trigger Mode : 0
+[077h 0119 1] Interrupt Input LINT : 01
+
+Raw Table Data: Length 120 (0x78)
+
+ 0000: 41 50 49 43 78 00 00 00 01 ED 42 4F 43 48 53 20 // APICx.....BOCHS
+ 0010: 42 58 50 43 41 50 49 43 01 00 00 00 42 58 50 43 // BXPCAPIC....BXPC
+ 0020: 01 00 00 00 00 00 E0 FE 01 00 00 00 00 08 00 00 // ................
+ 0030: 01 00 00 00 01 0C 00 00 00 00 C0 FE 00 00 00 00 // ................
+ 0040: 02 0A 00 00 02 00 00 00 00 00 02 0A 00 05 05 00 // ................
+ 0050: 00 00 0D 00 02 0A 00 09 09 00 00 00 0D 00 02 0A // ................
+ 0060: 00 0A 0A 00 00 00 0D 00 02 0A 00 0B 0B 00 00 00 // ................
+ 0070: 0D 00 04 06 FF 00 00 01 // ........
+```
+
+
diff --git a/Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.c b/Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.c
new file mode 100644
index 0000000..0511f59
--- /dev/null
+++ b/Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.c
@@ -0,0 +1,106 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Protocol/Shell.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_SHELL_PROTOCOL* ShellProtocol;
+ EFI_STATUS Status = gBS->LocateProtocol(
+ &gEfiShellProtocolGuid,
+ NULL,
+ (VOID **)&ShellProtocol
+ );
+
+ if (EFI_ERROR(Status)) {
+ Print(L"Can't open EFI_SHELL_PROTOCOL: %r\n", Status);
+ return EFI_SUCCESS;
+ }
+
+ EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER* RSDP = NULL;
+
+ for (UINTN i=0; i<SystemTable->NumberOfTableEntries; i++) {
+ if (CompareGuid(&(SystemTable->ConfigurationTable[i].VendorGuid), &gEfiAcpi20TableGuid)) {
+ Print(L"RSDP table is placed at %p\n\n", SystemTable->ConfigurationTable[i].VendorTable);
+ RSDP = SystemTable->ConfigurationTable[i].VendorTable;
+ }
+ }
+
+ if (!RSDP) {
+ Print(L"No ACPI2.0 table was found in the system\n");
+ return EFI_SUCCESS;
+ }
+
+ if (((CHAR8)((RSDP->Signature >> 0) & 0xFF) != 'R') ||
+ ((CHAR8)((RSDP->Signature >> 8) & 0xFF) != 'S') ||
+ ((CHAR8)((RSDP->Signature >> 16) & 0xFF) != 'D') ||
+ ((CHAR8)((RSDP->Signature >> 24) & 0xFF) != ' ') ||
+ ((CHAR8)((RSDP->Signature >> 32) & 0xFF) != 'P') ||
+ ((CHAR8)((RSDP->Signature >> 40) & 0xFF) != 'T') ||
+ ((CHAR8)((RSDP->Signature >> 48) & 0xFF) != 'R') ||
+ ((CHAR8)((RSDP->Signature >> 56) & 0xFF) != ' ')) {
+ Print(L"Error! RSDP signature is not valid!\n");
+ return EFI_SUCCESS;
+ }
+
+ Print(L"System description tables:\n");
+ Print(L"\tRSDT table is placed at address %p\n", RSDP->RsdtAddress);
+ Print(L"\tXSDT table is placed at address %p\n", RSDP->XsdtAddress);
+ Print(L"\n");
+
+ EFI_ACPI_DESCRIPTION_HEADER* XSDT = (EFI_ACPI_DESCRIPTION_HEADER*)RSDP->XsdtAddress;
+ if (((CHAR8)((XSDT->Signature >> 0) & 0xFF) != 'X') ||
+ ((CHAR8)((XSDT->Signature >> 8) & 0xFF) != 'S') ||
+ ((CHAR8)((XSDT->Signature >> 16) & 0xFF) != 'D') ||
+ ((CHAR8)((XSDT->Signature >> 24) & 0xFF) != 'T')) {
+ Print(L"Error! XSDT signature is not valid!\n");
+ return EFI_SUCCESS;
+ }
+
+ Print(L"Main ACPI tables:\n");
+ UINT64 offset = sizeof(EFI_ACPI_DESCRIPTION_HEADER);
+ while (offset < XSDT->Length) {
+ UINT64* table_address = (UINT64*)((UINT8*)XSDT + offset);
+ EFI_ACPI_6_3_COMMON_HEADER* table = (EFI_ACPI_6_3_COMMON_HEADER*)(*table_address);
+ CHAR16 TableName[5];
+ TableName[0] = (CHAR16)((table->Signature>> 0)&0xFF);
+ TableName[1] = (CHAR16)((table->Signature>> 8)&0xFF);
+ TableName[2] = (CHAR16)((table->Signature>>16)&0xFF);
+ TableName[3] = (CHAR16)((table->Signature>>24)&0xFF);
+ TableName[4] = 0;
+
+ Print(L"\t%s table is placed at address %p with length 0x%x\n",
+ TableName,
+ table,
+ table->Length);
+ CHAR16 FileName[9] = {0};
+ StrCpyS(FileName, 9, TableName);
+ StrCatS(FileName, 9, L".aml");
+ SHELL_FILE_HANDLE FileHandle;
+ Status = ShellProtocol->OpenFileByName(FileName,
+ &FileHandle,
+ EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ);
+ if (!EFI_ERROR(Status)) {
+ UINTN size = table->Length;
+ Status = ShellProtocol->WriteFile(FileHandle, &size, (VOID*)table);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error in WriteFile: %r\n", Status);
+ }
+ Status = ShellProtocol->CloseFile(FileHandle);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error in CloseFile: %r\n", Status);
+ }
+ } else {
+ Print(L"Error in OpenFileByName: %r\n", Status);
+ }
+ offset += sizeof(UINT64);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.inf b/Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.inf
new file mode 100644
index 0000000..53d0356
--- /dev/null
+++ b/Lessons/Lesson_28/UefiLessonsPkg/AcpiInfo/AcpiInfo.inf
@@ -0,0 +1,24 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = AcpiInfo
+ FILE_GUID = 18998798-69a2-4ab5-9ffc-a8ee2494b029
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ AcpiInfo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
+[Guids]
+ gEfiAcpi20TableGuid
+
+[Protocols]
+ gEfiShellProtocolGuid
+
diff --git a/Lessons/Lesson_29/Conf/target.txt b/Lessons/Lesson_29/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lessons/Lesson_29/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/Lessons/Lesson_29/README.md b/Lessons/Lesson_29/README.md
new file mode 100644
index 0000000..1b613e7
--- /dev/null
+++ b/Lessons/Lesson_29/README.md
@@ -0,0 +1,427 @@
+In the last lesson we've discovered that our system has BGRT ACPI table.
+
+According to the ACPI specification:
+```
+The Boot Graphics Resource Table (BGRT) is an optional table that provides a mechanism to indicate that
+an image was drawn on the screen during boot, and some information about the image.
+The table is written when the image is drawn on the screen. This should be done after it is expected that
+any firmware components that may write to the screen are done doing so and it is known that the image
+is the only thing on the screen. If the boot path is interrupted (e.g., by a key press), the valid bit within the
+status field should be changed to 0 to indicate to the OS that the current image is invalidated
+```
+This table actually have a pointer to image data, check structure definition under https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Acpi63.h:
+```
+///
+/// Boot Graphics Resource Table definition.
+///
+typedef struct {
+ EFI_ACPI_DESCRIPTION_HEADER Header;
+ ///
+ /// 2-bytes (16 bit) version ID. This value must be 1.
+ ///
+ UINT16 Version;
+ ///
+ /// 1-byte status field indicating current status about the table.
+ /// Bits[7:1] = Reserved (must be zero)
+ /// Bit [0] = Valid. A one indicates the boot image graphic is valid.
+ ///
+ UINT8 Status;
+ ///
+ /// 1-byte enumerated type field indicating format of the image.
+ /// 0 = Bitmap
+ /// 1 - 255 Reserved (for future use)
+ ///
+ UINT8 ImageType;
+ ///
+ /// 8-byte (64 bit) physical address pointing to the firmware's in-memory copy
+ /// of the image bitmap.
+ ///
+ UINT64 ImageAddress;
+ ///
+ /// A 4-byte (32-bit) unsigned long describing the display X-offset of the boot image.
+ /// (X, Y) display offset of the top left corner of the boot image.
+ /// The top left corner of the display is at offset (0, 0).
+ ///
+ UINT32 ImageOffsetX;
+ ///
+ /// A 4-byte (32-bit) unsigned long describing the display Y-offset of the boot image.
+ /// (X, Y) display offset of the top left corner of the boot image.
+ /// The top left corner of the display is at offset (0, 0).
+ ///
+ UINT32 ImageOffsetY;
+} EFI_ACPI_6_3_BOOT_GRAPHICS_RESOURCE_TABLE;
+```
+
+
+Let's create an app that would save an image from BGRT.
+
+This time to get BGRT table we would utilize `EFI_ACPI_SDT_PROTOCOL` protocol.
+
+To get ACPI table data we would use `GetAcpiTable()` function from this protocol:
+```
+EFI_ACPI_SDT_PROTOCOL.GetAcpiTable()
+
+Summary:
+Returns a requested ACPI table.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ACPI_GET_ACPI_TABLE) (
+ IN UINTN Index,
+ OUT EFI_ACPI_SDT_HEADER **Table,
+ OUT EFI_ACPI_TABLE_VERSION *Version,
+ OUT UINTN *TableKey
+ );
+
+Parameters:
+Index The zero-based index of the table to retrieve.
+Table Pointer for returning the table buffer.
+Version On return, updated with the ACPI versions to which this table belongs.
+TableKey On return, points to the table key for the specified ACPI system definition table.
+
+Description:
+The GetAcpiTable() function returns a pointer to a buffer containing the ACPI table associated with the Index that was input. The following structures are not considered elements in the list of ACPI tables:
+- Root System Description Pointer (RSD_PTR)
+- Root System Description Table (RSDT)
+- Extended System Description Table (XSDT)
+```
+In edk2 it is defined here: https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/AcpiSystemDescriptionTable.h
+
+To get all tables we need to call `GetAcpiTable` with incrementing values for `Index` starting with 0, while function returns `EFI_SUCCESS`.
+
+On every success call we would get a pointer to a common header for a ACPI table:
+```
+typedef struct {
+ UINT32 Signature;
+ UINT32 Length;
+ UINT8 Revision;
+ UINT8 Checksum;
+ CHAR8 OemId[6];
+ CHAR8 OemTableId[8];
+ UINT32 OemRevision;
+ UINT32 CreatorId;
+ UINT32 CreatorRevision;
+} EFI_ACPI_SDT_HEADER;
+```
+
+To use `EFI_ACPI_SDT_PROTOCOL` we need to add include to our file:
+```
+#include <Protocol/AcpiSystemDescriptionTable.h>
+```
+And add protocol to the *.inf file:
+```
+[Protocols]
+ gEfiAcpiSdtProtocolGuid
+```
+
+Here is a code finding BGRT ACPI table:
+```
+EFI_ACPI_SDT_PROTOCOL* AcpiSdtProtocol;
+EFI_STATUS Status = gBS->LocateProtocol (
+ &gEfiAcpiSdtProtocolGuid,
+ NULL,
+ (VOID**)&AcpiSdtProtocol
+ );
+if (EFI_ERROR (Status)) {
+ return Status;
+}
+
+BOOLEAN BGRT_found = FALSE;
+UINTN Index = 0;
+EFI_ACPI_SDT_HEADER* Table;
+EFI_ACPI_TABLE_VERSION Version;
+UINTN TableKey;
+while (TRUE) {
+ Status = AcpiSdtProtocol->GetAcpiTable(Index,
+ &Table,
+ &Version,
+ &TableKey
+ );
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+ if (((CHAR8)((Table->Signature >> 0) & 0xFF) == 'B') &&
+ ((CHAR8)((Table->Signature >> 8) & 0xFF) == 'G') &&
+ ((CHAR8)((Table->Signature >> 16) & 0xFF) == 'R') &&
+ ((CHAR8)((Table->Signature >> 24) & 0xFF) == 'T')) {
+ BGRT_found = TRUE;
+ break;
+ }
+ Index++;
+}
+if (!BGRT_found) {
+ Print(L"BGRT table is not present in the system\n");
+ return EFI_UNSUPPORTED;
+}
+```
+
+Now we need to save an image from BGRT table.
+
+Currently ACPI specification support only BMP image type https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#image-type
+
+So first we check if the type is actually BMP:
+```
+EFI_ACPI_6_3_BOOT_GRAPHICS_RESOURCE_TABLE* BGRT = (EFI_ACPI_6_3_BOOT_GRAPHICS_RESOURCE_TABLE*)Table;
+if (BGRT->ImageType == 0) {
+ ...
+}
+```
+
+Now we need to actually save a BMP image. BGRT doesn't contain any size for an image, only offset to data: `ImageAddress`.
+
+To get image size we need to look at BMP header.
+
+In edk2 it is defined under https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Bmp.h:
+```
+typedef struct {
+ CHAR8 CharB;
+ CHAR8 CharM;
+ UINT32 Size;
+ UINT16 Reserved[2];
+ UINT32 ImageOffset;
+ UINT32 HeaderSize;
+ UINT32 PixelWidth;
+ UINT32 PixelHeight;
+ UINT16 Planes; ///< Must be 1
+ UINT16 BitPerPixel; ///< 1, 4, 8, or 24
+ UINT32 CompressionType;
+ UINT32 ImageSize; ///< Compressed image size in bytes
+ UINT32 XPixelsPerMeter;
+ UINT32 YPixelsPerMeter;
+ UINT32 NumberOfColors;
+ UINT32 ImportantColors;
+} BMP_IMAGE_HEADER;
+```
+
+Don't forget to include this file in our program:
+```
+#include <IndustryStandard/Bmp.h>
+```
+
+When we know that the image is BMP, we can check its signature (`BM`), parse its size and actually write its data to a file. Here we use `EFI_STATUS WriteFile(CHAR16* FileName, VOID* Data, UINTN* Size)` function to write data to a file, we will define it in a minute:
+```
+BMP_IMAGE_HEADER* BMP = (BMP_IMAGE_HEADER*)(BGRT->ImageAddress);
+
+if ((BMP->CharB != 'B') || (BMP->CharM != 'M')) {
+ Print(L"BMP image has wrong signature!\n");
+ return EFI_UNSUPPORTED;
+}
+Print(L"BGRT conatins BMP image with %dx%d resolution\n", BMP->PixelWidth, BMP->PixelHeight);
+UINTN Size = BMP->Size;
+Status = WriteFile(L"BGRT.bmp", BMP, &Size);
+if (EFI_ERROR(Status)) {
+ Print(L"Error! Can't write BGRT.bmp file\n");
+}
+```
+
+Last time we've used `EFI_SHELL_PROTOCOL` to create a file and write data to it. This time we will try to utilize ShelLib:
+
+https://github.com/tianocore/edk2/blob/master/ShellPkg/Include/Library/ShellLib.h
+
+https://github.com/tianocore/edk2/blob/master/ShellPkg/Library/UefiShellLib/UefiShellLib.c
+
+Again we will need 3 functions: for file open, write and close:
+```
+/**
+ This function will open a file or directory referenced by filename.
+ If return is EFI_SUCCESS, the Filehandle is the opened file's handle;
+ otherwise, the Filehandle is NULL. Attributes is valid only for
+ EFI_FILE_MODE_CREATE.
+ @param[in] FileName The pointer to file name.
+ @param[out] FileHandle The pointer to the file handle.
+ @param[in] OpenMode The mode to open the file with.
+ @param[in] Attributes The file's file attributes.
+ ...
+**/
+
+EFI_STATUS
+EFIAPI
+ShellOpenFileByName(
+ IN CONST CHAR16 *FileName,
+ OUT SHELL_FILE_HANDLE *FileHandle,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ );
+```
+```
+/**
+ Write data to a file.
+ This function writes the specified number of bytes to the file at the current
+ file position. The current file position is advanced the actual number of bytes
+ written, which is returned in BufferSize. Partial writes only occur when there
+ has been a data error during the write attempt (such as "volume space full").
+ The file is automatically grown to hold the data if required. Direct writes to
+ opened directories are not supported.
+ @param[in] FileHandle The opened file for writing.
+ @param[in, out] BufferSize On input the number of bytes in Buffer. On output
+ the number of bytes written.
+ @param[in] Buffer The buffer containing data to write is stored.
+ ...
+**/
+
+EFI_STATUS
+EFIAPI
+ShellWriteFile(
+ IN SHELL_FILE_HANDLE FileHandle,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ );
+```
+```
+/**
+ Close an open file handle.
+ This function closes a specified file handle. All "dirty" cached file data is
+ flushed to the device, and the file is closed. In all cases the handle is
+ closed.
+ @param[in] FileHandle The file handle to close.
+**/
+
+EFI_STATUS
+EFIAPI
+ShellCloseFile (
+ IN SHELL_FILE_HANDLE *FileHandle
+ );
+```
+
+Advantage of using `ShellLib` is that now we don't need to find `EFI_SHELL_PROTOCOL` and work with it manually.
+
+
+Our `WriteFile` function would look like this:
+```
+EFI_STATUS WriteFile(CHAR16* FileName, VOID* Data, UINTN* Size)
+{
+ SHELL_FILE_HANDLE FileHandle;
+ EFI_STATUS Status = ShellOpenFileByName(
+ FileName,
+ &FileHandle,
+ EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ,
+ 0
+ );
+ if (!EFI_ERROR(Status)) {
+ Print(L"Save it to %s\n", FileName);
+ UINTN ToWrite = *Size;
+ Status = ShellWriteFile(
+ FileHandle,
+ Size,
+ Data
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"Can't write file: %r\n", Status);
+ }
+ if (*Size != ToWrite) {
+ Print(L"Error! Not all data was written\n");
+ }
+ Status = ShellCloseFile(
+ &FileHandle
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"Can't close file: %r\n", Status);
+ }
+ } else {
+ Print(L"Can't open file: %r\n", Status);
+ }
+ return Status;
+}
+```
+
+To use ShellLib we need to include a header in our program:
+```
+#include <Library/ShellLib.h>
+```
+
+Also we need to add `ShellPkg.dec` to our packages and add `ShellLib` to our library classes:
+```
+[Packages]
+ MdePkg/MdePkg.dec
++ ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
++ ShellLib
+```
+Besides that our package `*.dsc` file needs to include a `ShellLib` library class:
+```
+[LibraryClasses]
+ ...
+ ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf
+```
+
+Unfortunately this is not enough, our current build would fail with a message, because `ShellLib` by itself needs another library:
+```
+build.py...
+/home/kostr/tiano/edk2/UefiLessonsPkg/UefiLessonsPkg.dsc(...): error 4000: Instance of library class [FileHandleLib] is not found
+```
+
+To find it use our standard tactic:
+```
+$ grep FileHandleLib -r ./ --include=*.inf | grep LIBRARY_CLASS
+```
+
+In the end we had to add several more LibraryClasses to make our build succeed:
+```
+[LibraryClasses]
+ ...
+ FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
+ HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+ SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
+ UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
+```
+
+Build our app and execute it under OVMF:
+```
+FS0:\> SaveBGRT.efi
+BGRT conatins BMP image with 193x58 resolution
+Save it to BGRT.bmp7
+FS0:\>
+```
+
+If you look at the BGRT.bmp picture that are app have produced, it would have the same content as https://raw.githubusercontent.com/tianocore/edk2/master/MdeModulePkg/Logo/Logo.bmp
+
+The file itself wouldn't be the same since BGRT driver don't use an image from flash, but actually grabs a boot screen and transforms it to a BMP image. For the proof checkout how https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.c uses `TranslateGopBltToBmp` function from the https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Library/BaseBmpSupportLib/BmpSupportLib.c library.
+If you find it strange that BGRT grabs a screen instead of using an image from flash, remember how BGRT is defined in ACPI specification:
+```
+The Boot Graphics Resource Table (BGRT) is an optional table that provides a mechanism to indicate that an image was drawn on the screen during boot
+```
+
+The file GUID for binary boot logo image is defined in the file https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Logo/Logo.inf
+```
+FILE_GUID = 7BB28B99-61BB-11D5-9A5D-0090273FC14D
+```
+It is a GUID that is usually used for the Logo image in BIOS. It is even hardcoded to https://github.com/tianocore/edk2/blob/master/BaseTools/Source/Python/Eot/Report.py
+```
+## GenerateFfs() method
+#
+# Generate FFS information
+#
+# @param self: The object pointer
+# @param FfsObj: FFS object after FV image is parsed
+#
+def GenerateFfs(self, FfsObj):
+ self.FfsIndex = self.FfsIndex + 1
+ if FfsObj is not None and FfsObj.Type in [0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0xA]:
+ FfsGuid = FfsObj.Guid
+ FfsOffset = FfsObj._OFF_
+ FfsName = 'Unknown-Module'
+ FfsPath = FfsGuid
+ FfsType = FfsObj._TypeName[FfsObj.Type]
+
+ # Hard code for Binary INF
+ if FfsGuid.upper() == '7BB28B99-61BB-11D5-9A5D-0090273FC14D':
+ FfsName = 'Logo'
+
+ if FfsGuid.upper() == '7E374E25-8E01-4FEE-87F2-390C23C606CD':
+ FfsName = 'AcpiTables'
+
+ if FfsGuid.upper() == '961578FE-B6B7-44C3-AF35-6BC705CD2B1F':
+ FfsName = 'Fat'
+ ...
+```
+
+If you want to know how Logo and BGRT are work in edk2, checkout these drivers:
+- https://github.com/tianocore/edk2/tree/master/MdeModulePkg/Library/BootLogoLib/
+- https://github.com/tianocore/edk2/tree/master/MdeModulePkg/Logo/
+- https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/
+- https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Library/BaseBmpSupportLib/
+
diff --git a/Lessons/Lesson_29/UefiLessonsPkg/AcpiInfo/AcpiInfo.c b/Lessons/Lesson_29/UefiLessonsPkg/AcpiInfo/AcpiInfo.c
new file mode 100644
index 0000000..0511f59
--- /dev/null
+++ b/Lessons/Lesson_29/UefiLessonsPkg/AcpiInfo/AcpiInfo.c
@@ -0,0 +1,106 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Protocol/Shell.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_SHELL_PROTOCOL* ShellProtocol;
+ EFI_STATUS Status = gBS->LocateProtocol(
+ &gEfiShellProtocolGuid,
+ NULL,
+ (VOID **)&ShellProtocol
+ );
+
+ if (EFI_ERROR(Status)) {
+ Print(L"Can't open EFI_SHELL_PROTOCOL: %r\n", Status);
+ return EFI_SUCCESS;
+ }
+
+ EFI_ACPI_6_3_ROOT_SYSTEM_DESCRIPTION_POINTER* RSDP = NULL;
+
+ for (UINTN i=0; i<SystemTable->NumberOfTableEntries; i++) {
+ if (CompareGuid(&(SystemTable->ConfigurationTable[i].VendorGuid), &gEfiAcpi20TableGuid)) {
+ Print(L"RSDP table is placed at %p\n\n", SystemTable->ConfigurationTable[i].VendorTable);
+ RSDP = SystemTable->ConfigurationTable[i].VendorTable;
+ }
+ }
+
+ if (!RSDP) {
+ Print(L"No ACPI2.0 table was found in the system\n");
+ return EFI_SUCCESS;
+ }
+
+ if (((CHAR8)((RSDP->Signature >> 0) & 0xFF) != 'R') ||
+ ((CHAR8)((RSDP->Signature >> 8) & 0xFF) != 'S') ||
+ ((CHAR8)((RSDP->Signature >> 16) & 0xFF) != 'D') ||
+ ((CHAR8)((RSDP->Signature >> 24) & 0xFF) != ' ') ||
+ ((CHAR8)((RSDP->Signature >> 32) & 0xFF) != 'P') ||
+ ((CHAR8)((RSDP->Signature >> 40) & 0xFF) != 'T') ||
+ ((CHAR8)((RSDP->Signature >> 48) & 0xFF) != 'R') ||
+ ((CHAR8)((RSDP->Signature >> 56) & 0xFF) != ' ')) {
+ Print(L"Error! RSDP signature is not valid!\n");
+ return EFI_SUCCESS;
+ }
+
+ Print(L"System description tables:\n");
+ Print(L"\tRSDT table is placed at address %p\n", RSDP->RsdtAddress);
+ Print(L"\tXSDT table is placed at address %p\n", RSDP->XsdtAddress);
+ Print(L"\n");
+
+ EFI_ACPI_DESCRIPTION_HEADER* XSDT = (EFI_ACPI_DESCRIPTION_HEADER*)RSDP->XsdtAddress;
+ if (((CHAR8)((XSDT->Signature >> 0) & 0xFF) != 'X') ||
+ ((CHAR8)((XSDT->Signature >> 8) & 0xFF) != 'S') ||
+ ((CHAR8)((XSDT->Signature >> 16) & 0xFF) != 'D') ||
+ ((CHAR8)((XSDT->Signature >> 24) & 0xFF) != 'T')) {
+ Print(L"Error! XSDT signature is not valid!\n");
+ return EFI_SUCCESS;
+ }
+
+ Print(L"Main ACPI tables:\n");
+ UINT64 offset = sizeof(EFI_ACPI_DESCRIPTION_HEADER);
+ while (offset < XSDT->Length) {
+ UINT64* table_address = (UINT64*)((UINT8*)XSDT + offset);
+ EFI_ACPI_6_3_COMMON_HEADER* table = (EFI_ACPI_6_3_COMMON_HEADER*)(*table_address);
+ CHAR16 TableName[5];
+ TableName[0] = (CHAR16)((table->Signature>> 0)&0xFF);
+ TableName[1] = (CHAR16)((table->Signature>> 8)&0xFF);
+ TableName[2] = (CHAR16)((table->Signature>>16)&0xFF);
+ TableName[3] = (CHAR16)((table->Signature>>24)&0xFF);
+ TableName[4] = 0;
+
+ Print(L"\t%s table is placed at address %p with length 0x%x\n",
+ TableName,
+ table,
+ table->Length);
+ CHAR16 FileName[9] = {0};
+ StrCpyS(FileName, 9, TableName);
+ StrCatS(FileName, 9, L".aml");
+ SHELL_FILE_HANDLE FileHandle;
+ Status = ShellProtocol->OpenFileByName(FileName,
+ &FileHandle,
+ EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ);
+ if (!EFI_ERROR(Status)) {
+ UINTN size = table->Length;
+ Status = ShellProtocol->WriteFile(FileHandle, &size, (VOID*)table);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error in WriteFile: %r\n", Status);
+ }
+ Status = ShellProtocol->CloseFile(FileHandle);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error in CloseFile: %r\n", Status);
+ }
+ } else {
+ Print(L"Error in OpenFileByName: %r\n", Status);
+ }
+ offset += sizeof(UINT64);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_29/UefiLessonsPkg/AcpiInfo/AcpiInfo.inf b/Lessons/Lesson_29/UefiLessonsPkg/AcpiInfo/AcpiInfo.inf
new file mode 100644
index 0000000..53d0356
--- /dev/null
+++ b/Lessons/Lesson_29/UefiLessonsPkg/AcpiInfo/AcpiInfo.inf
@@ -0,0 +1,24 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = AcpiInfo
+ FILE_GUID = 18998798-69a2-4ab5-9ffc-a8ee2494b029
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ AcpiInfo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
+[Guids]
+ gEfiAcpi20TableGuid
+
+[Protocols]
+ gEfiShellProtocolGuid
+
diff --git a/Lessons/Lesson_29/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lessons/Lesson_29/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..29a4812
--- /dev/null
+++ b/Lessons/Lesson_29/UefiLessonsPkg/HelloWorld/HelloWorld.c
@@ -0,0 +1,19 @@
+#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");
+
+ UINTN Index;
+ gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
+ gST->ConIn->Reset(gST->ConIn, FALSE);
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_29/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lessons/Lesson_29/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lessons/Lesson_29/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/Lessons/Lesson_29/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lessons/Lesson_29/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..32e9c43
--- /dev/null
+++ b/Lessons/Lesson_29/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/Lessons/Lesson_29/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lessons/Lesson_29/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lessons/Lesson_29/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/Lessons/Lesson_29/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lessons/Lesson_29/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lessons/Lesson_29/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/Lessons/Lesson_29/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lessons/Lesson_29/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lessons/Lesson_29/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/Lessons/Lesson_29/UefiLessonsPkg/InteractiveApp/InteractiveApp.c b/Lessons/Lesson_29/UefiLessonsPkg/InteractiveApp/InteractiveApp.c
new file mode 100644
index 0000000..59c89a9
--- /dev/null
+++ b/Lessons/Lesson_29/UefiLessonsPkg/InteractiveApp/InteractiveApp.c
@@ -0,0 +1,34 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ UINTN Index;
+ EFI_INPUT_KEY Key;
+
+ Print(L"Try to guess the secret symbol!\n");
+ Print(L"To quit press 'q'\n");
+
+ while(TRUE) {
+ gBS->WaitForEvent(1, &(gST->ConIn->WaitForKey), &Index);
+ gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
+ Print(L"ScanCode = %04x, UnicodeChar = %04x (%c)\n", Key.ScanCode, Key.UnicodeChar, Key.UnicodeChar);
+
+ if (Key.UnicodeChar == 'k') {
+ Print(L"Correct!\n");
+ break;
+ } else if (Key.UnicodeChar == 'q') {
+ Print(L"Bye!\n");
+ break;
+ } else {
+ Print(L"Wrong!\n");
+ }
+ }
+ gST->ConIn->Reset(gST->ConIn, FALSE);
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_29/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf b/Lessons/Lesson_29/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
new file mode 100644
index 0000000..700b779
--- /dev/null
+++ b/Lessons/Lesson_29/UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
@@ -0,0 +1,18 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = InteractiveApp
+ FILE_GUID = 1539451b-f300-41fa-a565-dde69c1bed66
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ InteractiveApp.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
diff --git a/Lessons/Lesson_29/UefiLessonsPkg/ListVariables/ListVariables.c b/Lessons/Lesson_29/UefiLessonsPkg/ListVariables/ListVariables.c
new file mode 100644
index 0000000..1f3ef4a
--- /dev/null
+++ b/Lessons/Lesson_29/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/Lessons/Lesson_29/UefiLessonsPkg/ListVariables/ListVariables.inf b/Lessons/Lesson_29/UefiLessonsPkg/ListVariables/ListVariables.inf
new file mode 100644
index 0000000..14e9fa2
--- /dev/null
+++ b/Lessons/Lesson_29/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/Lessons/Lesson_29/UefiLessonsPkg/MemoryInfo/MemoryInfo.c b/Lessons/Lesson_29/UefiLessonsPkg/MemoryInfo/MemoryInfo.c
new file mode 100644
index 0000000..8c3bcf2
--- /dev/null
+++ b/Lessons/Lesson_29/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/Lessons/Lesson_29/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf b/Lessons/Lesson_29/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
new file mode 100644
index 0000000..777010d
--- /dev/null
+++ b/Lessons/Lesson_29/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/Lessons/Lesson_29/UefiLessonsPkg/PCDLesson/PCDLesson.c b/Lessons/Lesson_29/UefiLessonsPkg/PCDLesson/PCDLesson.c
new file mode 100644
index 0000000..9e0aae0
--- /dev/null
+++ b/Lessons/Lesson_29/UefiLessonsPkg/PCDLesson/PCDLesson.c
@@ -0,0 +1,43 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/PcdLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ Print(L"PcdMyVar32=%d\n", FixedPcdGet32(PcdMyVar32));
+ Print(L"PcdMyVar32_1=%d\n", FixedPcdGet32(PcdMyVar32_1));
+ Print(L"PcdMyVar32_2=%d\n", FixedPcdGet32(PcdMyVar32_2));
+
+ Print(L"PcdMyVar32=%d\n", PcdGet32(PcdMyVar32));
+
+ Print(L"PcdMyPatchableVar32=0x%x\n", PcdGet32(PcdMyPatchableVar32));
+ RETURN_STATUS PcdStatus = PcdSet32S(PcdMyPatchableVar32, 44);
+ Print(L"PcdStatus=%r\n", PcdStatus);
+ Print(L"PcdMyPatchableVar32=%d\n", PcdGet32(PcdMyPatchableVar32));
+ PatchPcdSet32(PcdMyPatchableVar32, 45);
+ Print(L"PcdMyPatchableVar32=%d\n", PatchPcdGet32(PcdMyPatchableVar32));
+
+
+ Print(L"PcdMyFeatureFlagVar=%d\n", FeaturePcdGet(PcdMyFeatureFlagVar));
+ Print(L"PcdMyFeatureFlagVar=%d\n", PcdGetBool(PcdMyFeatureFlagVar));
+ Print(L"PcdMyVarBool=%d\n", FixedPcdGetBool(PcdMyVarBool));
+ Print(L"PcdMyVarBool=%d\n", PcdGetBool(PcdMyVarBool));
+
+
+
+
+ Print(L"PcdMyDynamicExVar32=%x\n", PcdGet32(PcdMyDynamicExVar32));
+ PcdSet32S(PcdMyDynamicExVar32, 52);
+ Print(L"PcdMyDynamicExVar32=%x\n", PcdGet32(PcdMyDynamicExVar32));
+
+ Print(L"PcdMyDynamicVar32=%x\n", PcdGet32(PcdMyDynamicVar32));
+ PcdSet32S(PcdMyDynamicVar32, 52);
+ Print(L"PcdMyDynamicVar32=%x\n", PcdGet32(PcdMyDynamicVar32));
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_29/UefiLessonsPkg/PCDLesson/PCDLesson.inf b/Lessons/Lesson_29/UefiLessonsPkg/PCDLesson/PCDLesson.inf
new file mode 100644
index 0000000..cfd39d2
--- /dev/null
+++ b/Lessons/Lesson_29/UefiLessonsPkg/PCDLesson/PCDLesson.inf
@@ -0,0 +1,39 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = PCDLesson
+ FILE_GUID = 8c1a6b71-0c4b-4497-aaad-07404edf142c
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ PCDLesson.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiLessonsPkg/UefiLessonsPkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
+[FixedPcd]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_1|43
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|43
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVarBool
+
+[PatchPcd]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyPatchableVar32
+
+[FeaturePcd]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyFeatureFlagVar
+
+[Pcd]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyDynamicVar32
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyDynamicVar32_1
+
+[PcdEx]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyDynamicExVar32
+
+
diff --git a/Lessons/Lesson_29/UefiLessonsPkg/SaveBGRT/SaveBGRT.c b/Lessons/Lesson_29/UefiLessonsPkg/SaveBGRT/SaveBGRT.c
new file mode 100644
index 0000000..2fda8d8
--- /dev/null
+++ b/Lessons/Lesson_29/UefiLessonsPkg/SaveBGRT/SaveBGRT.c
@@ -0,0 +1,104 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/AcpiSystemDescriptionTable.h>
+#include <Library/ShellLib.h>
+#include <IndustryStandard/Bmp.h>
+
+EFI_STATUS WriteFile(CHAR16* FileName, VOID* Data, UINTN* Size)
+{
+ SHELL_FILE_HANDLE FileHandle;
+ EFI_STATUS Status = ShellOpenFileByName(
+ FileName,
+ &FileHandle,
+ EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ,
+ 0
+ );
+ if (!EFI_ERROR(Status)) {
+ Print(L"Save it to %s\n", FileName);
+ UINTN ToWrite = *Size;
+ Status = ShellWriteFile(
+ FileHandle,
+ Size,
+ Data
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"Can't write file: %r\n", Status);
+ }
+ if (*Size != ToWrite) {
+ Print(L"Error! Not all data was written\n");
+ }
+ Status = ShellCloseFile(
+ &FileHandle
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"Can't close file: %r\n", Status);
+ }
+ } else {
+ Print(L"Can't open file: %r\n", Status);
+ }
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_ACPI_SDT_PROTOCOL* AcpiSdtProtocol;
+ EFI_STATUS Status = gBS->LocateProtocol (
+ &gEfiAcpiSdtProtocolGuid,
+ NULL,
+ (VOID**)&AcpiSdtProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BOOLEAN BGRT_found = FALSE;
+ UINTN Index = 0;
+ EFI_ACPI_SDT_HEADER* Table;
+ EFI_ACPI_TABLE_VERSION Version;
+ UINTN TableKey;
+ while (TRUE) {
+ Status = AcpiSdtProtocol->GetAcpiTable(Index,
+ &Table,
+ &Version,
+ &TableKey
+ );
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+ if (((CHAR8)((Table->Signature >> 0) & 0xFF) == 'B') &&
+ ((CHAR8)((Table->Signature >> 8) & 0xFF) == 'G') &&
+ ((CHAR8)((Table->Signature >> 16) & 0xFF) == 'R') &&
+ ((CHAR8)((Table->Signature >> 24) & 0xFF) == 'T')) {
+ BGRT_found = TRUE;
+ break;
+ }
+ Index++;
+ }
+ if (!BGRT_found) {
+ Print(L"BGRT table is not present in the system\n");
+ return EFI_UNSUPPORTED;
+ }
+
+ EFI_ACPI_6_3_BOOT_GRAPHICS_RESOURCE_TABLE* BGRT = (EFI_ACPI_6_3_BOOT_GRAPHICS_RESOURCE_TABLE*)Table;
+ if (BGRT->ImageType == 0) {
+ BMP_IMAGE_HEADER* BMP = (BMP_IMAGE_HEADER*)(BGRT->ImageAddress);
+
+ if ((BMP->CharB != 'B') || (BMP->CharM != 'M')) {
+ Print(L"BMP image has wrong signature!\n");
+ return EFI_UNSUPPORTED;
+ }
+ Print(L"BGRT conatins BMP image with %dx%d resolution\n", BMP->PixelWidth, BMP->PixelHeight);
+ UINTN Size = BMP->Size;
+ Status = WriteFile(L"BGRT.bmp", BMP, &Size);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error! Can't write BGRT.bmp file\n");
+ }
+ }
+ return Status;
+}
diff --git a/Lessons/Lesson_29/UefiLessonsPkg/SaveBGRT/SaveBGRT.inf b/Lessons/Lesson_29/UefiLessonsPkg/SaveBGRT/SaveBGRT.inf
new file mode 100644
index 0000000..93ab1b9
--- /dev/null
+++ b/Lessons/Lesson_29/UefiLessonsPkg/SaveBGRT/SaveBGRT.inf
@@ -0,0 +1,23 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = SaveBGRT
+ FILE_GUID = efe33e23-b17c-42b2-9551-87546f215935
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ SaveBGRT.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ ShellLib
+
+[Protocols]
+ gEfiAcpiSdtProtocolGuid
+
diff --git a/Lessons/Lesson_29/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c b/Lessons/Lesson_29/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
new file mode 100644
index 0000000..7f6b58c
--- /dev/null
+++ b/Lessons/Lesson_29/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.c
@@ -0,0 +1,93 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+
+
+EFI_STATUS
+GetNvramVariable( CHAR16 *VariableName,
+ EFI_GUID *VariableOwnerGuid,
+ VOID **Buffer,
+ UINTN *BufferSize)
+{
+ UINTN Size = 0;
+ *BufferSize = 0;
+
+ EFI_STATUS Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Print(L"Error! 'gRT->GetVariable' call returned %r\n", Status);
+ return Status;
+ }
+
+ *Buffer = AllocateZeroPool(Size);
+ if (!Buffer) {
+ Print(L"Error! 'AllocateZeroPool' call returned %r\n", Status);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable(VariableName, VariableOwnerGuid, NULL, &Size, *Buffer);
+ if (Status == EFI_SUCCESS) {
+ *BufferSize = Size;
+ } else {
+ FreePool( *Buffer );
+ *Buffer = NULL;
+ }
+
+ return Status;
+}
+
+
+VOID PrintBootOption(CHAR16* BootOptionName)
+{
+ UINTN OptionSize;
+ UINT8* Buffer;
+
+ EFI_STATUS Status = GetNvramVariable(BootOptionName, &gEfiGlobalVariableGuid, (VOID**)&Buffer, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ EFI_LOAD_OPTION* LoadOption = (EFI_LOAD_OPTION*) Buffer;
+ CHAR16* Description = (CHAR16*)(Buffer + sizeof (EFI_LOAD_OPTION));
+ UINTN DescriptionSize = StrSize(Description);
+
+ Print(L"%s\n", Description);
+ if (LoadOption->FilePathListLength != 0) {
+ VOID* FilePathList = (UINT8 *)Description + DescriptionSize;
+ CHAR16* DevPathString = ConvertDevicePathToText(FilePathList, TRUE, FALSE);
+ Print(L"%s\n", DevPathString);
+ }
+ } else {
+ Print(L"Can't get %s variable\n", BootOptionName);
+ }
+}
+
+
+INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
+{
+ UINTN OptionSize;
+ EFI_STATUS Status;
+
+ UINT16* BootCurrent;
+ Status = GetNvramVariable(L"BootCurrent", &gEfiGlobalVariableGuid, (VOID**)&BootCurrent, &OptionSize);
+ if (Status != EFI_SUCCESS) {
+ Print(L"Can't get BootCurrent variable\n");
+ }
+
+ UINT16* BootOrderArray;
+ Status = GetNvramVariable(L"BootOrder", &gEfiGlobalVariableGuid, (VOID**)&BootOrderArray, &OptionSize);
+ if (Status == EFI_SUCCESS) {
+ for (UINTN i=0; i<(OptionSize/sizeof(UINT16)); i++) {
+ CHAR16 BootOptionStr[sizeof("Boot####")+1];
+ UnicodeSPrint(BootOptionStr, (sizeof("Boot####")+1)*sizeof(CHAR16), L"Boot%04x", BootOrderArray[i]);
+ Print(L"%s%s\n", BootOptionStr, (BootOrderArray[i] == *BootCurrent)? L"*" : L"" );
+ PrintBootOption(BootOptionStr);
+ Print(L"\n");
+ }
+ } else {
+ Print(L"Can't get BootOrder variable\n");
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_29/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf b/Lessons/Lesson_29/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
new file mode 100644
index 0000000..d2cfba9
--- /dev/null
+++ b/Lessons/Lesson_29/UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
@@ -0,0 +1,19 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = ShowBootVariables
+ FILE_GUID = 31266d12-9c60-478e-905e-05d117a3a9df
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+[Sources]
+ ShowBootVariables.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ ShellCEntryLib
+
diff --git a/Lessons/Lesson_29/UefiLessonsPkg/ShowTables/ShowTables.c b/Lessons/Lesson_29/UefiLessonsPkg/ShowTables/ShowTables.c
new file mode 100644
index 0000000..aa32f41
--- /dev/null
+++ b/Lessons/Lesson_29/UefiLessonsPkg/ShowTables/ShowTables.c
@@ -0,0 +1,16 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ for (UINTN i=0; i<SystemTable->NumberOfTableEntries; i++) {
+ Print(L"%g, %p\n", SystemTable->ConfigurationTable[i].VendorGuid,
+ SystemTable->ConfigurationTable[i].VendorTable);
+ }
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_29/UefiLessonsPkg/ShowTables/ShowTables.inf b/Lessons/Lesson_29/UefiLessonsPkg/ShowTables/ShowTables.inf
new file mode 100644
index 0000000..056b823
--- /dev/null
+++ b/Lessons/Lesson_29/UefiLessonsPkg/ShowTables/ShowTables.inf
@@ -0,0 +1,18 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = ShowTables
+ FILE_GUID = e249532c-d41a-4bd9-a4a8-7fc143e703f2
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ ShowTables.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
diff --git a/Lessons/Lesson_29/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c b/Lessons/Lesson_29/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c
new file mode 100644
index 0000000..b13aa6c
--- /dev/null
+++ b/Lessons/Lesson_29/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/Lessons/Lesson_29/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf b/Lessons/Lesson_29/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf
new file mode 100644
index 0000000..013bf4e
--- /dev/null
+++ b/Lessons/Lesson_29/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/Lessons/Lesson_29/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lessons/Lesson_29/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lessons/Lesson_29/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/Lessons/Lesson_29/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lessons/Lesson_29/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lessons/Lesson_29/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/Lessons/Lesson_29/UefiLessonsPkg/UefiLessonsPkg.dec b/Lessons/Lesson_29/UefiLessonsPkg/UefiLessonsPkg.dec
new file mode 100644
index 0000000..38048bc
--- /dev/null
+++ b/Lessons/Lesson_29/UefiLessonsPkg/UefiLessonsPkg.dec
@@ -0,0 +1,35 @@
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = UefiLessonsPkg
+ PACKAGE_GUID = 7e7edbba-ca2c-4177-a3f0-d3371358773a
+ PACKAGE_VERSION = 1.01
+
+[Includes]
+
+[LibraryClasses]
+
+[Guids]
+ # FILE_GUID as defined in UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ gHelloWorldFileGuid = {0x2e55fa38, 0xf148, 0x42d3, {0xaf, 0x90, 0x1b, 0xe2, 0x47, 0x32, 0x3e, 0x30}}
+ gUefiLessonsPkgTokenSpaceGuid = {0x150cab53, 0xad47, 0x4385, {0xb5, 0xdd, 0xbc, 0xfc, 0x76, 0xba, 0xca, 0xf0}}
+
+[Protocols]
+
+[PcdsFixedAtBuild]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32|42|UINT32|0x00000001
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_1|42|UINT32|0x00000002
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|42|UINT32|0x00000003
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVarBool|FALSE|BOOLEAN|0x00000004
+
+[PcdsPatchableInModule]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyPatchableVar32|0x31313131|UINT32|0x10000001
+
+[PcdsFeatureFlag]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyFeatureFlagVar|FALSE|BOOLEAN|0x20000001
+
+[PcdsDynamic]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyDynamicVar32|0x38323232|UINT32|0x30000001
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyDynamicVar32_1|42|UINT32|0x30000002
+
+[PcdsDynamicEx]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyDynamicExVar32|0x38333333|UINT32|0x40000001
diff --git a/Lessons/Lesson_29/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lessons/Lesson_29/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..5939fcc
--- /dev/null
+++ b/Lessons/Lesson_29/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,50 @@
+[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
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.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
+ ShellLib|ShellPkg/Library/UefiShellLib/UefiShellLib.inf
+ FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
+ HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+ SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf
+ UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.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
+ UefiLessonsPkg/ShowBootVariables/ShowBootVariables.inf
+ UefiLessonsPkg/InteractiveApp/InteractiveApp.inf
+ UefiLessonsPkg/PCDLesson/PCDLesson.inf
+ UefiLessonsPkg/ShowTables/ShowTables.inf
+ UefiLessonsPkg/AcpiInfo/AcpiInfo.inf
+ UefiLessonsPkg/SaveBGRT/SaveBGRT.inf
+
+[PcdsFixedAtBuild]
+ gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32_2|44
+
diff --git a/Lessons/Lesson_30/PCI_Configuration_Address.png b/Lessons/Lesson_30/PCI_Configuration_Address.png
new file mode 100644
index 0000000..5094de4
--- /dev/null
+++ b/Lessons/Lesson_30/PCI_Configuration_Address.png
Binary files differ
diff --git a/Lessons/Lesson_30/README.md b/Lessons/Lesson_30/README.md
new file mode 100644
index 0000000..756583f
--- /dev/null
+++ b/Lessons/Lesson_30/README.md
@@ -0,0 +1,458 @@
+
+In this lesson we try to show all PCI devices available in a system.
+
+For this task we'll need to utilize `EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL` from the UEFI specification. This protocol is installed to every PCI Root bridge in the system.
+It provides various functions to access PCI devices under this root bridge. For example with its help it is possible to read PCI device memory, I/O and configuration spaces for every PCI device:
+
+You can look at a protocol structure to get a hint on what it can do:
+```
+typedef struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL {
+ EFI_HANDLE ParentHandle;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM PollMem;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM PollIo;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Mem;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Io;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Pci;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_COPY_MEM CopyMem;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_MAP Map;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_UNMAP Unmap;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FREE_BUFFER FreeBuffer;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FLUSH Flush;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GET_ATTRIBUTES GetAttributes;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_SET_ATTRIBUTES SetAttributes;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION Configuration;
+ UINT32 SegmentNumber;
+} EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL;
+```
+
+As in the system can be many PCI root bridges and therefore many `EFI_PCI_ROOT_BRIDGE_IO_PROTOCOLs`, we need to use `LocateHandleBuffer` to get all handles that have this protocol and then loop through these handles using `OpenProtocol` on every one of them.
+
+```
+EFI_BOOT_SERVICES.LocateHandleBuffer()
+
+Summary:
+Returns an array of handles that support the requested protocol in a buffer allocated from pool.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_LOCATE_HANDLE_BUFFER) (
+ IN EFI_LOCATE_SEARCH_TYPE SearchType,
+ IN EFI_GUID *Protocol OPTIONAL,
+ IN VOID *SearchKey OPTIONAL,
+ OUT UINTN *NoHandles,
+ OUT EFI_HANDLE **Buffer
+ );
+
+Parameters:
+SearchType Specifies which handle(s) are to be returned.
+Protocol Provides the protocol to search by. This parameter is only valid for a SearchType of ByProtocol.
+SearchKey Supplies the search key depending on the SearchType.
+NoHandles The number of handles returned in Buffer.
+Buffer A pointer to the buffer to return the requested array of handles that support Protocol.
+ This buffer is allocated with a call to the Boot Service EFI_BOOT_SERVICES.AllocatePool().
+ It is the caller's responsibility to call the Boot Service EFI_BOOT_SERVICES.FreePool() when the caller no longer
+ requires the contents of Buffer.
+
+Description:
+The LocateHandleBuffer() function returns one or more handles that match the SearchType request. Buffer is allocated from pool, and the number of entries in Buffer is returned in NoHandles. Each
+SearchType is described below:
+
+AllHandles Protocol and SearchKey are ignored and the function returns an array of every handle in the system.
+ByRegisterNotify SearchKey supplies the Registration returned by EFI_BOOT_SERVICES.RegisterProtocolNotify().
+ The function returns the next handle that is new for the Registration.
+ Only one handle is returned at a time, and the caller must loop until
+ no more handles are returned. Protocol is ignored for this search type.
+ByProtocol All handles that support Protocol are returned. SearchKey is ignored for this search type.
+```
+
+```
+EFI_STATUS Status;
+UINTN HandleCount;
+EFI_HANDLE *HandleBuffer;
+Status = gBS->LocateHandleBuffer(
+ ByProtocol,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+if (EFI_ERROR (Status)) {
+ Print(L"Can't locate EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL: %r\n", Status);
+ return Status;
+}
+
+Print(L"Number of PCI root bridges in the system: %d\n", HandleCount);
+EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL* PciRootBridgeIo;
+for (UINTN Index = 0; Index < HandleCount; Index++) {
+ ...
+}
+FreePool(HandleBuffer);
+```
+Don't forget to include `<Protocol/PciRootBridgeIo.h>` for the `EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL` and `<Library/MemoryAllocationLib.h>` for the `FreePool`. And offcourse protocol should be included in the app `*.inf` file:
+```
+[Protocols]
+ gEfiPciRootBridgeIoProtocolGuid
+```
+To get a protocol for particaular handle you can use `OpenProtocol` function:
+```
+EFI_BOOT_SERVICES.OpenProtocol()
+
+Summary:
+Queries a handle to determine if it supports a specified protocol. If the protocol is supported by the
+handle, it opens the protocol on behalf of the calling agent. This is an extended version of the EFI boot
+service EFI_BOOT_SERVICES.HandleProtocol().
+
+Prototype
+typedef
+EFI_STATUS
+(EFIAPI *EFI_OPEN_PROTOCOL) (
+ IN EFI_HANDLE Handle,
+ IN EFI_GUID *Protocol,
+ OUT VOID **Interface OPTIONAL,
+ IN EFI_HANDLE AgentHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINT32 Attributes
+ );
+
+Parameters:
+Handle The handle for the protocol interface that is being opened.
+Protocol The published unique identifier of the protocol.
+Interface Supplies the address where a pointer to the corresponding Protocol Interface is returned. NULL will be returned in *Interface if a
+ structure is not associated with Protocol. This parameter is optional, and will be ignored if Attributes is EFI_OPEN_PROTOCOL_TEST_PROTOCOL.
+AgentHandle The handle of the agent that is opening the protocol interface specified by Protocol and Interface. For agents that follow the UEFI
+ Driver Model, this parameter is the handle that contains the EFI_DRIVER_BINDING_PROTOCOL instance that is produced by
+ the UEFI driver that is opening the protocol interface. For UEFI applications, this is the image handle of the UEFI application that is
+ opening the protocol interface. For applications that use HandleProtocol() to open a protocol interface, this parameter is
+ the image handle of the EFI firmware.
+ControllerHandle If the agent that is opening a protocol is a driver that follows the
+ UEFI Driver Model, then this parameter is the controller handle that
+ requires the protocol interface. If the agent does not follow the UEFI
+ Driver Model, then this parameter is optional and may be NULL.
+Attributes The open mode of the protocol interface specified by Handle and
+ Protocol.
+
+Description:
+This function opens a protocol interface on the handle specified by Handle for the protocol specified by Protocol.
+The first three parameters are the same as EFI_BOOT_SERVICES.HandleProtocol(). The only difference is that the agent that is opening a protocol interface is tracked in an EFI's internal handle
+database
+```
+
+There are various `Attributes` (last parameter):
+```
+#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL 0x00000001
+#define EFI_OPEN_PROTOCOL_GET_PROTOCOL 0x00000002
+#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL 0x00000004
+#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER 0x00000008
+#define EFI_OPEN_PROTOCOL_BY_DRIVER 0x00000010
+#define EFI_OPEN_PROTOCOL_EXCLUSIVE 0x00000020
+```
+
+We will need `EFI_OPEN_PROTOCOL_GET_PROTOCOL`:
+```
+GET_PROTOCOL - Used by a driver to get a protocol interface from a handle
+```
+You can read more about other values in the UEFI specification.
+
+
+Use `OpenProtocol` call in our loop, and call our custom `EFI_STATUS PrintRootBridge(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL* PciRootBridgeIo)` function for every found protocol:
+```
+for (UINTN Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->OpenProtocol (
+ HandleBuffer[Index],
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **)&PciRootBridgeIo,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"Can't open protocol: %r\n", Status);
+ return Status;
+ }
+ Print(L"\nPCI Root Bridge %d\n", Index);
+ Status = PrintRootBridge(PciRootBridgeIo);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error in PCI Root Bridge printing\n");
+ }
+}
+```
+
+Now let's write this `PrintRootBridge` function.
+
+First we need to get all available buses for the PCI Root Bridge. To do this we can use `Configuration()` function from the `EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL`:
+```
+EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.Configuration()
+
+Summary:
+
+Retrieves the current resource settings of this PCI root bridge in the form of a set of ACPI resource descriptors.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION) (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT VOID **Resources
+ );
+
+Parameters:
+This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+Resources A pointer to the resource descriptors that describe the current configuration of this PCI root bridge.
+ The storage for the resource descriptors is allocated by this function. The caller must treat the return
+ buffer as read-only data, and the buffer must not be freed by the caller.
+
+Description:
+The Configuration() function retrieves a set of resource descriptors that contains the current
+configuration of this PCI root bridge.
+```
+
+Also here is important information about `ACPI resource descriptors` - the data that we would get from excuting this function:
+```
+There are only two resource descriptor types from the ACPI Specification that may be used to describe
+the current resources allocated to a PCI root bridge. These are the QWORD Address Space Descriptor,
+and the End Tag. The QWORD Address Space Descriptor can describe memory, I/O, and bus number
+ranges for dynamic or fixed resources. The configuration of a PCI root bridge is described with one or
+more QWORD Address Space Descriptors followed by an End Tag
+```
+
+So we need to check ACPI specification about 2 types of ACPI resource descriptors:
+- QWORD Address Space Descriptor
+- End Tag Descriptor
+
+The QWORD address space descriptor is defined here in ACPI specification https://uefi.org/specs/ACPI/6.4/06_Device_Configuration/Device_Configuration.html?#qword-address-space-descriptor
+
+In edk2 its structure is placed in a file https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Acpi10.h
+```
+///
+/// The common definition of QWORD, DWORD, and WORD
+/// Address Space Descriptors.
+///
+typedef PACKED struct {
+ UINT8 Desc;
+ UINT16 Len;
+ UINT8 ResType;
+ UINT8 GenFlag;
+ UINT8 SpecificFlag;
+ UINT64 AddrSpaceGranularity;
+ UINT64 AddrRangeMin;
+ UINT64 AddrRangeMax;
+ UINT64 AddrTranslationOffset;
+ UINT64 AddrLen;
+} EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR;
+```
+
+The end tag descriptor is defined in ACPI spec under https://uefi.org/specs/ACPI/6.4/06_Device_Configuration/Device_Configuration.html#end-tag
+
+Define for it in edk2 is here https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Acpi10.h:
+```
+#define ACPI_END_TAG_DESCRIPTOR 0x79
+```
+
+So after we get an array of `EFI_ACPI_ADDRESS_SPACE_DESCRIPTORs` from our `PciRootBridgeIo->Configuration` call, we need to loop through it until we would encounter descriptor `ACPI_END_TAG_DESCRIPTOR`.
+
+QWORD address space descriptor can have one of the several resource types:
+```
+//
+// Resource Type
+//
+#define ACPI_ADDRESS_SPACE_TYPE_MEM 0x00
+#define ACPI_ADDRESS_SPACE_TYPE_IO 0x01
+#define ACPI_ADDRESS_SPACE_TYPE_BUS 0x02
+```
+
+Right now we are interested in `ACPI_ADDRESS_SPACE_TYPE_BUS` type. We need to know, how many PCI buses has this PCI root bridge.
+
+So the code for our function would look like this:
+```
+EFI_STATUS PrintRootBridge(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL* PciRootBridgeIo)
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR* AddressDescriptor;
+ EFI_STATUS Status = PciRootBridgeIo->Configuration(
+ PciRootBridgeIo,
+ (VOID**)&AddressDescriptor
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"\tError! Can't get EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR: %r\n", Status);
+ return Status;
+ }
+ while (AddressDescriptor->Desc != ACPI_END_TAG_DESCRIPTOR) {
+ if (AddressDescriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
+ ...
+ }
+ AddressDescriptor++;
+ }
+}
+return Status;
+```
+
+When we know all available buses for the PCI root bridge we can try to read PCI configuration space for its devices with a help of `EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.Pci.Read()` function:
+```
+EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.Pci.Read()
+EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.Pci.Write()
+
+Summary:
+Enables a PCI driver to access PCI controller registers in a PCI root bridge’s configuration space.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_IO_MEM) (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+Parameters:
+This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+Width Signifies the width of the memory operations.
+Address The address within the PCI configuration space for the PCI controller.
+Count The number of PCI configuration operations to perform. Bytes moved is Width size * Count, starting at Address.
+Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer to write data from.
+
+Description:
+The Pci.Read() and Pci.Write() functions enable a driver to access PCI configuration registers for a
+PCI controller.
+All the PCI transactions generated by this function are guaranteed to be completed before this function
+returns.
+
+```
+
+The address in this function is defined as follows:
+
+![PCI_Configuration_Address](PCI_Configuration_Address.png?raw=true "PCI_Configuration_Address")
+
+So we write a simple function to create an Address variable from the Bus/Device/Function/Register value:
+```
+UINT64 PciConfigurationAddress(UINT8 Bus,
+ UINT8 Device,
+ UINT8 Function,
+ UINT32 Register)
+{
+ UINT64 Address = (((UINT64)Bus) << 24) + (((UINT64)Device) << 16) + (((UINT64)Function) << 8);
+ if (Register & 0xFFFFFF00) {
+ Address += (((UINT64)Register) << 32);
+ } else {
+ Address += (((UINT64)Register) << 0);
+ }
+ return Address;
+}
+```
+
+
+Let's try to loop through all possible PCI functions and for every one of them read its header from PCI cofiguration space.
+
+Maximum values for PCI bus, device and function are determined by PCI specification.
+
+In edk2 they are defined in github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Pci22.h:
+```
+#define PCI_MAX_BUS 255
+#define PCI_MAX_DEVICE 31
+#define PCI_MAX_FUNC 7
+```
+As with ACPI newer PCI specifications include the older ones:
+```
+Pci.h > PciExpress50.h > PciExpress40.h > PciExpress31.h > PciExpress30.h > PciExpress21.h > Pci30.h > Pci23.h > Pci22.h
+```
+- https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Pci.h
+- https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/PciExpress50.h
+- https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/PciExpress40.h
+- https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/PciExpress31.h
+- https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/PciExpress30.h
+- https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/PciExpress21.h
+- https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Pci30.h
+- https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Pci23.h
+- https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Pci22.h
+
+
+For every possible PCI function we would try to read its common PCI configuration space header:
+```
+///
+/// Common header region in PCI Configuration Space
+/// Section 6.1, PCI Local Bus Specification, 2.2
+///
+typedef struct {
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT16 Command;
+ UINT16 Status;
+ UINT8 RevisionID;
+ UINT8 ClassCode[3];
+ UINT8 CacheLineSize;
+ UINT8 LatencyTimer;
+ UINT8 HeaderType;
+ UINT8 BIST;
+} PCI_DEVICE_INDEPENDENT_REGION;
+```
+
+After getting the data we would check if a `VendorId` field is valid. If it is not equal to `0xffff` it is an actual PCI function. In this case we would print some information about it.
+
+Here is a code for this Bus/Device/Func loop:
+```
+for (UINT8 Bus = AddressDescriptor->AddrRangeMin; Bus <= AddressDescriptor->AddrRangeMax; Bus++) {
+ for (UINT8 Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+ for (UINT8 Func = 0; Func <= PCI_MAX_FUNC; Func++) {
+ UINT64 Address = PciConfigurationAddress(Bus, Device, Func, 0);
+ PCI_DEVICE_INDEPENDENT_REGION PCIConfHdr;
+ Status = PciRootBridgeIo->Pci.Read(
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ sizeof(PCI_DEVICE_INDEPENDENT_REGION),
+ &PCIConfHdr
+ );
+ if (!EFI_ERROR(Status)) {
+ if (PCIConfHdr.VendorId != 0xffff) {
+ Print(L"\tBus: %02x, Dev: %02x, Func: %02x - Vendor:%04x, Device:%04x\n",
+ Bus,
+ Device,
+ Func,
+ PCIConfHdr.VendorId,
+ PCIConfHdr.DeviceId);
+ }
+ } else {
+ Print(L"\tError in PCI read: %r\n", Status);
+ }
+ }
+ }
+}
+```
+
+If we build and execute our app under OVMF we would get:
+```
+FS0:\> ListPCI.efi
+Number of PCI root bridges in the system: 1
+
+PCI Root Bridge 0
+ Bus: 00, Dev: 00, Func: 00 - Vendor:8086, Device:1237
+ Bus: 00, Dev: 01, Func: 00 - Vendor:8086, Device:7000
+ Bus: 00, Dev: 01, Func: 01 - Vendor:8086, Device:7010
+ Bus: 00, Dev: 01, Func: 03 - Vendor:8086, Device:7113
+ Bus: 00, Dev: 02, Func: 00 - Vendor:1234, Device:1111
+```
+
+
+You can verify that our output is correct if you execute UEFI shell `pci` command:
+
+```
+FS0:\> pci
+ Seg Bus Dev Func
+ --- --- --- ----
+ 00 00 00 00 ==> Bridge Device - Host/PCI bridge
+ Vendor 8086 Device 1237 Prog Interface 0
+ 00 00 01 00 ==> Bridge Device - PCI/ISA bridge
+ Vendor 8086 Device 7000 Prog Interface 0
+ 00 00 01 01 ==> Mass Storage Controller - IDE controller
+ Vendor 8086 Device 7010 Prog Interface 80
+ 00 00 01 03 ==> Bridge Device - Other bridge type
+ Vendor 8086 Device 7113 Prog Interface 0
+ 00 00 02 00 ==> Display Controller - VGA/8514 controller
+ Vendor 1234 Device 1111 Prog Interface 0
+```
+
+One more thing to end this lesson, you can utilize `PciLib` to access PCI Configuration Space registers. Check out its interface at https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PciLib.h
+
diff --git a/Lessons/Lesson_30/UefiLessonsPkg/ListPCI/ListPCI.c b/Lessons/Lesson_30/UefiLessonsPkg/ListPCI/ListPCI.c
new file mode 100644
index 0000000..e8d5842
--- /dev/null
+++ b/Lessons/Lesson_30/UefiLessonsPkg/ListPCI/ListPCI.c
@@ -0,0 +1,116 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/PciRootBridgeIo.h>
+#include <Library/MemoryAllocationLib.h>
+#include <IndustryStandard/Pci.h>
+
+
+UINT64 PciConfigurationAddress(UINT8 Bus,
+ UINT8 Device,
+ UINT8 Function,
+ UINT32 Register)
+{
+ UINT64 Address = (((UINT64)Bus) << 24) + (((UINT64)Device) << 16) + (((UINT64)Function) << 8);
+ if (Register & 0xFFFFFF00) {
+ Address += (((UINT64)Register) << 32);
+ } else {
+ Address += (((UINT64)Register) << 0);
+ }
+ return Address;
+}
+
+
+EFI_STATUS PrintRootBridge(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL* PciRootBridgeIo)
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR* AddressDescriptor;
+ EFI_STATUS Status = PciRootBridgeIo->Configuration(
+ PciRootBridgeIo,
+ (VOID**)&AddressDescriptor
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"\tError! Can't get EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR: %r\n", Status);
+ return Status;
+ }
+ while (AddressDescriptor->Desc != ACPI_END_TAG_DESCRIPTOR) {
+ if (AddressDescriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
+ for (UINT8 Bus = AddressDescriptor->AddrRangeMin; Bus <= AddressDescriptor->AddrRangeMax; Bus++) {
+ for (UINT8 Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+ for (UINT8 Func = 0; Func <= PCI_MAX_FUNC; Func++) {
+ UINT64 Address = PciConfigurationAddress(Bus, Device, Func, 0);
+ PCI_DEVICE_INDEPENDENT_REGION PCIConfHdr;
+ Status = PciRootBridgeIo->Pci.Read(
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ sizeof(PCI_DEVICE_INDEPENDENT_REGION),
+ &PCIConfHdr
+ );
+ if (!EFI_ERROR(Status)) {
+ if (PCIConfHdr.VendorId != 0xffff) {
+ Print(L"\tBus: %02x, Dev: %02x, Func: %02x - Vendor:%04x, Device:%04x\n",
+ Bus,
+ Device,
+ Func,
+ PCIConfHdr.VendorId,
+ PCIConfHdr.DeviceId);
+ }
+ } else {
+ Print(L"\tError in PCI read: %r\n", Status);
+ }
+ }
+ }
+ }
+ }
+ AddressDescriptor++;
+ }
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ Status = gBS->LocateHandleBuffer(
+ ByProtocol,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ Print(L"Can't locate EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL: %r\n", Status);
+ return Status;
+ }
+
+ Print(L"Number of PCI root bridges in the system: %d\n", HandleCount);
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL* PciRootBridgeIo;
+ for (UINTN Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->OpenProtocol (
+ HandleBuffer[Index],
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **)&PciRootBridgeIo,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"Can't open protocol: %r\n", Status);
+ return Status;
+ }
+ Print(L"\nPCI Root Bridge %d\n", Index);
+ Status = PrintRootBridge(PciRootBridgeIo);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error in PCI Root Bridge printing\n");
+ }
+ }
+ FreePool(HandleBuffer);
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_30/UefiLessonsPkg/ListPCI/ListPCI.inf b/Lessons/Lesson_30/UefiLessonsPkg/ListPCI/ListPCI.inf
new file mode 100644
index 0000000..dd32b12
--- /dev/null
+++ b/Lessons/Lesson_30/UefiLessonsPkg/ListPCI/ListPCI.inf
@@ -0,0 +1,20 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = ListPCI
+ FILE_GUID = 07aceb78-97df-4e49-84a8-28997896e42a
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ ListPCI.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
+[Protocols]
+ gEfiPciRootBridgeIoProtocolGuid
diff --git a/Lessons/Lesson_31/README.md b/Lessons/Lesson_31/README.md
new file mode 100644
index 0000000..fdc22de
--- /dev/null
+++ b/Lessons/Lesson_31/README.md
@@ -0,0 +1,507 @@
+In this lesson we would modify our `ListPCI` utility, so it would show us information about PCI Vendor and Device. Even `pci` command in UEFI shell doesn't show this information. It only shows us information about PCI class/subclass code. So our utility can be really usefull. Just in case you can check out sources for the `pci` command here:
+- https://github.com/tianocore/edk2/blob/master/ShellPkg/Library/UefiShellDebug1CommandsLib/Pci.c
+- https://github.com/tianocore/edk2/blob/master/ShellPkg/Library/UefiShellDebug1CommandsLib/Pci.h
+
+This lesson was inspired by `ShowPCIx` application by fpmurphy https://github.com/fpmurphy/UEFI-Utilities-2019/tree/master/MyApps/ShowPCIx
+Although this utility was taking too long time to do the parsing, so I've decided to rewrite it with a performance in mind.
+
+In our app we would create a function `FindPCIDevDescription` that can fill Vendor/Device description strings based on its codes.
+```
+EFI_STATUS FindPCIDevDescription(IN UINT16 VendorId,
+ IN UINT16 DeviceId,
+ OUT CHAR16* VendorDesc,
+ OUT CHAR16* DeviceDesc,
+ IN UINTN DescBufferSize)
+```
+
+We integrate this function in a main PCI loop like this:
+```
+if (PCIConfHdr.VendorId != 0xffff) {
+ Print(L" %02x:%02x.%02x - Vendor:%04x, Device:%04x",
+ Bus,
+ Device,
+ Func,
+ PCIConfHdr.VendorId,
+ PCIConfHdr.DeviceId);
+
+ CHAR16 VendorDesc[DESCRIPTOR_STR_MAX_SIZE];
+ CHAR16 DeviceDesc[DESCRIPTOR_STR_MAX_SIZE];
+ Status = FindPCIDevDescription(PCIConfHdr.VendorId,
+ PCIConfHdr.DeviceId,
+ VendorDesc,
+ DeviceDesc,
+ DESCRIPTOR_STR_MAX_SIZE);
+ if (!EFI_ERROR(Status)) {
+ Print(L": %s, %s\n", VendorDesc, DeviceDesc);
+ } else {
+ Print(L"\n");
+ }
+}
+```
+
+In this code `DESCRIPTOR_STR_MAX_SIZE` is just a max size for the Vendor/Device description string. We declare `VendorDesc`/`DeviceDesc` as static arrays for simplicity and pick array size large enough to contain all descriptions.
+```
+#define DESCRIPTOR_STR_MAX_SIZE 200
+```
+
+Now it is time to write a function `FindPCIDevDescription`.
+
+We can get PCI Vendor/Device information from a public PCI ID Repository https://pci-ids.ucw.cz/. This site hosts a file with publically known PCI Vendor/Device combinations https://pci-ids.ucw.cz/v2.2/pci.ids.
+
+In the header of a file there are some comments about how the information is presented:
+```
+# Syntax:
+# vendor vendor_name
+# device device_name <-- single tab
+# subvendor subdevice subsystem_name <-- two tabs
+```
+
+Download this file to you shared QEMU directory:
+```
+$ cd ~/UEFI_disk
+$ wget https://pci-ids.ucw.cz/v2.2/pci.ids
+```
+
+Now let's write our function.
+
+First we need to check if PCI database file really exists:
+
+For this task we can utilize a function from the `ShellLib` https://github.com/tianocore/edk2/blob/master/ShellPkg/Include/Library/ShellLib.h
+```
+/**
+ Function to determine if a given filename exists.
+ @param[in] Name Path to test.
+ @retval EFI_SUCCESS The Path represents a file.
+ @retval EFI_NOT_FOUND The Path does not represent a file.
+ @retval other The path failed to open.
+**/
+EFI_STATUS
+EFIAPI
+ShellFileExists(
+ IN CONST CHAR16 *Name
+ );
+```
+
+So our check would be as simple as:
+```
+EFI_STATUS Status = ShellFileExists(L"pci.ids");
+if (EFI_ERROR(Status))
+{
+ Print(L"No file pci.ids: %r\n", Status);
+ return Status;
+}
+```
+
+Next we need to open a file for read:
+```
+SHELL_FILE_HANDLE FileHandle;
+Status = ShellOpenFileByName(L"pci.ids",
+ &FileHandle,
+ EFI_FILE_MODE_READ,
+ 0);
+if (EFI_ERROR(Status))
+{
+ Print(L"Can't open file pci.ids: %r\n", Status);
+ return Status;
+}
+```
+
+In our parsing process we would need a file size for a `pci.ids` file. Again we can use a function from the `ShellLib` for this task:
+```
+/**
+ Retrieve the size of a file.
+ This function extracts the file size info from the FileHandle's EFI_FILE_INFO
+ data.
+ @param[in] FileHandle The file handle from which size is retrieved.
+ @param[out] Size The pointer to size.
+ @retval EFI_SUCCESS The operation was completed sucessfully.
+ @retval EFI_DEVICE_ERROR Cannot access the file.
+**/
+EFI_STATUS
+EFIAPI
+ShellGetFileSize (
+ IN SHELL_FILE_HANDLE FileHandle,
+ OUT UINT64 *Size
+ );
+```
+
+There are a lot of things that can go wrong in our parsing process, but no matter what we should close an opened file handle. The easiest way to go from any point of the function to a specific place is a `goto` statement. We were taught that `goto` is always wrong, but actually in can be very handfull in some situations. It is used a lot in a Linux Kernel code for similar cleanup purposes, so don't argue and accept it:
+```
+EFI_STATUS FindPCIDevDescription(IN UINT16 VendorId,
+ IN UINT16 DeviceId,
+ OUT CHAR16* VendorDesc,
+ OUT CHAR16* DeviceDesc,
+ IN UINTN DescBufferSize)
+{
+ BOOLEAN Vendor_found = FALSE;
+ BOOLEAN Device_found = FALSE;
+
+ ...
+
+ UINT64 FileSize;
+ Status = ShellGetFileSize(FileHandle, &FileSize);
+ if (EFI_ERROR(Status))
+ {
+ Print(L"Can't get file size for file pci.ids: %r\n", Status);
+ goto end;
+ }
+
+ ...
+
+end:
+ if (!Vendor_found) {
+ UnicodeSPrint(VendorDesc, DescBufferSize, L"Undefined");
+ }
+ if (!Device_found) {
+ UnicodeSPrint(DeviceDesc, DescBufferSize, L"Undefined");
+ }
+ ShellCloseFile(&FileHandle);
+
+ return Status;
+}
+```
+
+When we would parse a database file we would be comparing char symbols, so we need to convert our `UINT16` value codes for Vendor and Device to hex strings.
+
+For this task we can utilize `AsciiValueToStringS` function from the https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PrintLib.h
+```
+/**
+ Converts a decimal value to a Null-terminated Ascii string.
+ Converts the decimal number specified by Value to a Null-terminated Ascii
+ string specified by Buffer containing at most Width characters. No padding of
+ spaces is ever performed.
+ ...
+ If RADIX_HEX is set in Flags, then the output buffer will be formatted in
+ hexadecimal format.
+ ...
+ If PREFIX_ZERO is set in Flags and PREFIX_ZERO is not being ignored, then
+ Buffer is padded with '0' characters so the combination of the optional '-'
+ sign character, '0' characters, digit characters for Value, and the
+ Null-terminator add up to Width characters.
+ If an error would be returned, then the function will ASSERT().
+ @param Buffer The pointer to the output buffer for the produced
+ Null-terminated Ascii string.
+ @param BufferSize The size of Buffer in bytes, including the
+ Null-terminator.
+ @param Flags The bitmask of flags that specify left justification,
+ zero pad, and commas.
+ @param Value The 64-bit signed value to convert to a string.
+ @param Width The maximum number of Ascii characters to place in
+ Buffer, not including the Null-terminator.
+ @retval RETURN_SUCCESS The decimal value is converted.
+ @retval RETURN_BUFFER_TOO_SMALL If BufferSize cannot hold the converted
+ value.
+ @retval RETURN_INVALID_PARAMETER If Buffer is NULL.
+ If PcdMaximumAsciiStringLength is not
+ zero, and BufferSize is greater than
+ PcdMaximumAsciiStringLength.
+ If unsupported bits are set in Flags.
+ If both COMMA_TYPE and RADIX_HEX are set in
+ Flags.
+ If Width >= MAXIMUM_VALUE_CHARACTERS.
+**/
+RETURN_STATUS
+EFIAPI
+AsciiValueToStringS (
+ IN OUT CHAR8 *Buffer,
+ IN UINTN BufferSize,
+ IN UINTN Flags,
+ IN INT64 Value,
+ IN UINTN Width
+ );
+```
+
+We just need to create arrays large enough and use the correct flags (`RADIX_HEX | PREFIX_ZERO`):
+```
+CHAR8 VendorStr[5];
+CHAR8 DeviceStr[5];
+AsciiValueToStringS(VendorStr,
+ 5,
+ RADIX_HEX | PREFIX_ZERO,
+ VendorId,
+ 4);
+AsciiValueToStringS(DeviceStr,
+ 5,
+ RADIX_HEX | PREFIX_ZERO,
+ DeviceId,
+ 4);
+```
+
+We need to make one more simple thing. `AsciiValueToStringS` would save hex value in upper-case, but in our database file it is written in lower-case. So we need to write a simple function for case conversion:
+```
+VOID ToLowerASCII(CHAR8* Str, UINTN Size)
+{
+ for (UINT8 i=0; i<Size; i++) {
+ if ((Str[i]>='A')&&(Str[i]<='Z')) {
+ Str[i]+=32;
+ }
+ }
+}
+```
+And use it like this:
+```
+ToLowerASCII(VendorStr, 4);
+ToLowerASCII(DeviceStr, 4);
+```
+
+Now the hard part, the main parsing loop:
+```
+CHAR8 Buffer[BLOCK_READ_SIZE];
+UINTN Size;
+UINT64 FilePos = 0;
+while (TRUE)
+{
+ Size = BLOCK_READ_SIZE;
+ Status = ShellReadFile(FileHandle, &Size, Buffer);
+ if (EFI_ERROR(Status))
+ {
+ Print(L"Can't read file pci.ids: %r\n", Status);
+ goto end;
+ }
+ UINTN StrStart = 0;
+ UINTN StrEnd = 0;
+ for (UINTN i=0; i<Size; i++) {
+ if (Buffer[i]=='\n') {
+ StrEnd=i;
+ <...>
+ StrStart=StrEnd;
+ }
+ }
+
+ if (FilePos+Size >= FileSize) {
+ break;
+ }
+ FilePos += StrEnd;
+ Status = ShellSetFilePosition(FileHandle, FilePos);
+ if (EFI_ERROR(Status))
+ {
+ Print(L"Can't set file position pci.ids: %r\n", Status);
+ goto end;
+ }
+}
+```
+Couple of hints of what is happening here in the code:
+- We read file by blocks (`#define BLOCK_READ_SIZE (1024*4)`),
+- In each block we search for `\n` symbols, to fill variables `StrStart` and `StrEnd`, the actual search would be happening for the data between every two `\n` symbols,
+- After the end of each block parsing we try to set a file pointer to the place of a last found `\n` (`=StrEnd`). For this task we utilize another function from the `ShellLib`:
+```
+EFI_STATUS
+EFIAPI
+ShellSetFilePosition (
+ IN SHELL_FILE_HANDLE FileHandle,
+ IN UINT64 Position
+ );
+```
+- If we've reached the end of a file and this was the last possible read, we end our search:
+```
+if (FilePos+Size >= FileSize) {
+ break;
+}
+```
+
+Now the thing that was hided behind `<...>`:
+```
+ if (!Vendor_found){
+ // 0123456 7
+ //\nVVVV |<desc>|\n
+ if ((StrEnd - StrStart) > 7) {
+ if ((Buffer[StrStart+1]==VendorStr[0]) &&
+ (Buffer[StrStart+2]==VendorStr[1]) &&
+ (Buffer[StrStart+3]==VendorStr[2]) &&
+ (Buffer[StrStart+4]==VendorStr[3])) {
+ Buffer[StrEnd] = 0;
+ UnicodeSPrintAsciiFormat(VendorDesc, DescBufferSize, "%a", &Buffer[StrStart+1+4+2]);
+ Vendor_found = TRUE;
+ }
+ }
+ } else {
+ // 0 1234567 8
+ //\n\tDDDD |<desc>|\n
+ if ((StrEnd - StrStart) > 8) {
+ if ((Buffer[StrStart+1]=='\t') &&
+ (Buffer[StrStart+2]==DeviceStr[0]) &&
+ (Buffer[StrStart+3]==DeviceStr[1]) &&
+ (Buffer[StrStart+4]==DeviceStr[2]) &&
+ (Buffer[StrStart+5]==DeviceStr[3])) {
+ Buffer[StrEnd] = 0;
+ UnicodeSPrintAsciiFormat(DeviceDesc, DescBufferSize, "%a", &Buffer[StrStart+1+1+4+2]);
+ Device_found = TRUE;
+ goto end;
+ }
+ }
+ }
+```
+Here is some explanation as well:
+- if the vendor string wasn't found, search for its pattern, if it was, search for the device pattern,
+- both `StrStart` and `StrEnd` point to different `\n` symbols, and we try to understand if information between them is what we need,
+- I put some comments for the minimal format that we are looking for, for example:
+```
+// 0123456 7
+//\nVVVV |<desc>|\n
+```
+This means that if a `StrStart` is pointing to `\n` at (`i+0`), `StrEnd` should be at least poining to `\n` at 7 (`i+7`) as vendor description is take place in symbols (`i+1`-`i+4`), and after it there have to be exactly two spaces. So even if an actual description is empty, there have to be at least 8 symbols in our string,
+- if we found our string we use `UnicodeSPrintAsciiFormat` to transform it to `CHAR16` string. This is another function from the https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PrintLib.h
+```
+/**
+ Produces a Null-terminated Unicode string in an output buffer based on a Null-terminated
+ ASCII format string and variable argument list.
+ This function is similar as snprintf_s defined in C11.
+ Produces a Null-terminated Unicode string in the output buffer specified by StartOfBuffer
+ and BufferSize.
+ The Unicode string is produced by parsing the format string specified by FormatString.
+ Arguments are pulled from the variable argument list based on the contents of the
+ format string.
+ ...
+ @param StartOfBuffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param FormatString A Null-terminated ASCII format string.
+ @param ... Variable argument list whose contents are accessed based on the
+ format string specified by FormatString.
+ @return The number of Unicode characters in the produced output buffer not including the
+ Null-terminator.
+**/
+UINTN
+EFIAPI
+UnicodeSPrintAsciiFormat (
+ OUT CHAR16 *StartOfBuffer,
+ IN UINTN BufferSize,
+ IN CONST CHAR8 *FormatString,
+ ...
+ );
+```
+
+I hope I've explained everything. Don't forget to add necessary includes for the libraries that we've used:
+```
+#include <Library/ShellLib.h>
+#include <Library/PrintLib.h>
+```
+As well as put `ShellLib` to our `*.inf` file:
+```
+[Packages]
+ ...
+ ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+ ...
+ ShellLib
+```
+
+If you build and execute our app under OVMF now, you would get:
+```
+FS0:\> ListPCI.efi
+Number of PCI root bridges in the system: 1
+
+PCI Root Bridge 0
+ 00:00.00 - Vendor:8086, Device:1237: Intel Corporation, 440FX - 82441FX PMC [Natoma]
+ 00:01.00 - Vendor:8086, Device:7000: Intel Corporation, 82371SB PIIX3 ISA [Natoma/Triton II]
+ 00:01.01 - Vendor:8086, Device:7010: Intel Corporation, 82371SB PIIX3 IDE [Natoma/Triton II]
+ 00:01.03 - Vendor:8086, Device:7113: Intel Corporation, 82371AB/EB/MB PIIX4 ACPI
+ 00:02.00 - Vendor:1234, Device:1111: Undefined, Undefined
+```
+
+In case you wonder what is that misterious 1234/1111 device it is a QEMU VGA controller https://github.com/qemu/qemu/blob/master/docs/specs/standard-vga.txt
+
+# Add PCI expander bridges and PCI root bridges to QEMU machine
+
+We've used this command to run QEMU:
+```
+qemu-system-x86_64 \
+ -drive if=pflash,format=raw,readonly,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd \
+ -drive if=pflash,format=raw,file=../OVMF_VARS.fd \
+ -drive format=raw,file=fat:rw:~/UEFI_disk \
+ -nographic \
+ -net none
+```
+But you can actually provide various PCI expander bridges and PCI root bridges in this command:
+```
+qemu-system-x86_64 \
+ -drive if=pflash,format=raw,readonly,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd \
+ -drive if=pflash,format=raw,file=../OVMF_VARS.fd \
+ -drive format=raw,file=fat:rw:~/UEFI_disk \
+ -nographic \
+ -net none \
+ -device pci-bridge,id=bridge0,chassis_nr=1 \
+ -device virtio-scsi-pci,id=scsi0,bus=bridge0,addr=0x3 \
+ -device pci-bridge,id=bridge1,chassis_nr=2 \
+ -device virtio-scsi-pci,id=scsi1,bus=bridge1,addr=0x3 \
+ -device virtio-scsi-pci,id=scsi2,bus=bridge1,addr=0x4 \
+ -device pxb,id=bridge2,bus=pci.0,bus_nr=3 \
+ -device virtio-scsi-pci,bus=bridge2,addr=0x3 \
+ -device pxb,id=bridge3,bus=pci.0,bus_nr=8 \
+ -device virtio-scsi-pci,bus=bridge3,addr=0x3 \
+ -device virtio-scsi-pci,bus=bridge3,addr=0x4
+```
+On this system our command will produce this output:
+```
+FS0:\> ListPCI.efi
+Number of PCI root bridges in the system: 3
+
+PCI Root Bridge 0
+ 00:00.00 - Vendor:8086, Device:1237: Intel Corporation, 440FX - 82441FX PMC [Natoma]
+ 00:01.00 - Vendor:8086, Device:7000: Intel Corporation, 82371SB PIIX3 ISA [Natoma/Triton II]
+ 00:01.01 - Vendor:8086, Device:7010: Intel Corporation, 82371SB PIIX3 IDE [Natoma/Triton II]
+ 00:01.03 - Vendor:8086, Device:7113: Intel Corporation, 82371AB/EB/MB PIIX4 ACPI
+ 00:02.00 - Vendor:1234, Device:1111: Undefined, Undefined
+ 00:03.00 - Vendor:1B36, Device:0001: Red Hat, Inc., QEMU PCI-PCI bridge
+ 00:04.00 - Vendor:1B36, Device:0001: Red Hat, Inc., QEMU PCI-PCI bridge
+ 00:05.00 - Vendor:1B36, Device:0009: Red Hat, Inc., QEMU PCI Expander bridge
+ 00:06.00 - Vendor:1B36, Device:0009: Red Hat, Inc., QEMU PCI Expander bridge
+ 01:03.00 - Vendor:1AF4, Device:1004: Red Hat, Inc., Virtio SCSI
+ 02:03.00 - Vendor:1AF4, Device:1004: Red Hat, Inc., Virtio SCSI
+ 02:04.00 - Vendor:1AF4, Device:1004: Red Hat, Inc., Virtio SCSI
+
+PCI Root Bridge 1
+ 03:00.00 - Vendor:1B36, Device:0001: Red Hat, Inc., QEMU PCI-PCI bridge
+ 04:03.00 - Vendor:1AF4, Device:1004: Red Hat, Inc., Virtio SCSI
+
+PCI Root Bridge 2
+ 08:00.00 - Vendor:1B36, Device:0001: Red Hat, Inc., QEMU PCI-PCI bridge
+ 09:03.00 - Vendor:1AF4, Device:1004: Red Hat, Inc., Virtio SCSI
+ 09:04.00 - Vendor:1AF4, Device:1004: Red Hat, Inc., Virtio SCSI
+```
+
+On a QEMU `q35` machine you can even add PCI-express root complexes:
+```
+qemu-system-x86_64 \
+ -machine q35 \
+ -drive if=pflash,format=raw,readonly,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd \
+ -drive if=pflash,format=raw,file=../OVMF_VARS.fd \
+ -drive format=raw,file=fat:rw:~/UEFI_disk \
+ -nographic \
+ -net none \
+ -device pxb-pcie,id=pcie.1,bus_nr=2,bus=pcie.0 \
+ -device ioh3420,id=pcie_port1,bus=pcie.1,chassis=1 \
+ -device virtio-scsi-pci,bus=pcie_port1 \
+ -device ioh3420,id=pcie_port2,bus=pcie.1,chassis=2 \
+ -device virtio-scsi-pci,bus=pcie_port2 \
+ -device pxb-pcie,id=pcie.2,bus_nr=8,bus=pcie.0 \
+ -device ioh3420,id=pcie_port3,bus=pcie.2,chassis=3 \
+ -device virtio-scsi-pci,bus=pcie_port3
+```
+```
+FS0:\> ListPCI.efi
+Number of PCI root bridges in the system: 3
+
+PCI Root Bridge 0
+ 00:00.00 - Vendor:8086, Device:29C0: Intel Corporation, 82G33/G31/P35/P31 Express DRAM Controller
+ 00:01.00 - Vendor:1234, Device:1111: Undefined, Undefined
+ 00:02.00 - Vendor:1B36, Device:000B: Red Hat, Inc., QEMU PCIe Expander bridge
+ 00:03.00 - Vendor:1B36, Device:000B: Red Hat, Inc., QEMU PCIe Expander bridge
+ 00:1F.00 - Vendor:8086, Device:2918: Intel Corporation, 82801IB (ICH9) LPC Interface Controller
+ 00:1F.02 - Vendor:8086, Device:2922: Intel Corporation, 82801IR/IO/IH (ICH9R/DO/DH) 6 port SATA Controller [AHCI mode]
+ 00:1F.03 - Vendor:8086, Device:2930: Intel Corporation, 82801I (ICH9 Family) SMBus Controller
+
+PCI Root Bridge 1
+ 02:00.00 - Vendor:8086, Device:3420: Intel Corporation, 7500/5520/5500/X58 I/O Hub PCI Express Root Port 0
+ 02:01.00 - Vendor:8086, Device:3420: Intel Corporation, 7500/5520/5500/X58 I/O Hub PCI Express Root Port 0
+ 03:00.00 - Vendor:1AF4, Device:1048: Red Hat, Inc., Virtio SCSI
+ 04:00.00 - Vendor:1AF4, Device:1048: Red Hat, Inc., Virtio SCSI
+
+PCI Root Bridge 2
+ 08:00.00 - Vendor:8086, Device:3420: Intel Corporation, 7500/5520/5500/X58 I/O Hub PCI Express Root Port 0
+ 09:00.00 - Vendor:1AF4, Device:1048: Red Hat, Inc., Virtio SCSI
+```
+
+If you are interested check out this link to know more about all these QEMU parameters https://blogs.oracle.com/linux/post/a-study-of-the-linux-kernel-pci-subsystem-with-qemu
+
diff --git a/Lessons/Lesson_31/UefiLessonsPkg/ListPCI/ListPCI.c b/Lessons/Lesson_31/UefiLessonsPkg/ListPCI/ListPCI.c
new file mode 100644
index 0000000..055906c
--- /dev/null
+++ b/Lessons/Lesson_31/UefiLessonsPkg/ListPCI/ListPCI.c
@@ -0,0 +1,268 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/PciRootBridgeIo.h>
+#include <Library/MemoryAllocationLib.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/ShellLib.h>
+#include <Library/PrintLib.h>
+
+
+#define DESCRIPTOR_STR_MAX_SIZE 200
+#define BLOCK_READ_SIZE (1024*4)
+
+VOID ToLowerASCII(CHAR8* Str, UINTN Size)
+{
+ for (UINT8 i=0; i<Size; i++) {
+ if ((Str[i]>='A')&&(Str[i]<='Z')) {
+ Str[i]+=32;
+ }
+ }
+}
+
+EFI_STATUS FindPCIDevDescription(IN UINT16 VendorId,
+ IN UINT16 DeviceId,
+ OUT CHAR16* VendorDesc,
+ OUT CHAR16* DeviceDesc,
+ IN UINTN DescBufferSize)
+{
+ BOOLEAN Vendor_found = FALSE;
+ BOOLEAN Device_found = FALSE;
+
+ EFI_STATUS Status = ShellFileExists(L"pci.ids");
+ if (EFI_ERROR(Status))
+ {
+ Print(L"No file pci.ids: %r\n", Status);
+ return Status;
+ }
+
+ SHELL_FILE_HANDLE FileHandle;
+ Status = ShellOpenFileByName(L"pci.ids",
+ &FileHandle,
+ EFI_FILE_MODE_READ,
+ 0);
+ if (EFI_ERROR(Status))
+ {
+ Print(L"Can't open file pci.ids: %r\n", Status);
+ return Status;
+ }
+
+ UINT64 FileSize;
+ Status = ShellGetFileSize(FileHandle, &FileSize);
+ if (EFI_ERROR(Status))
+ {
+ Print(L"Can't get file size for file pci.ids: %r\n", Status);
+ goto end;
+ }
+
+ CHAR8 VendorStr[5];
+ CHAR8 DeviceStr[5];
+ AsciiValueToStringS(VendorStr,
+ 5,
+ RADIX_HEX | PREFIX_ZERO,
+ VendorId,
+ 4);
+ AsciiValueToStringS(DeviceStr,
+ 5,
+ RADIX_HEX | PREFIX_ZERO,
+ DeviceId,
+ 4);
+ ToLowerASCII(VendorStr, 4);
+ ToLowerASCII(DeviceStr, 4);
+
+ CHAR8 Buffer[BLOCK_READ_SIZE];
+ UINTN Size;
+ UINT64 FilePos = 0;
+ while (TRUE)
+ {
+ Size = BLOCK_READ_SIZE;
+ Status = ShellReadFile(FileHandle, &Size, Buffer);
+ if (EFI_ERROR(Status))
+ {
+ Print(L"Can't read file pci.ids: %r\n", Status);
+ goto end;
+ }
+ UINTN StrStart = 0;
+ UINTN StrEnd = 0;
+ for (UINTN i=0; i<Size; i++) {
+ if (Buffer[i]=='\n') {
+ StrEnd=i;
+ if (!Vendor_found){
+ // 0123456 7
+ //\nVVVV |<desc>|\n
+ if ((StrEnd - StrStart) > 7) {
+ if ((Buffer[StrStart+1]==VendorStr[0]) &&
+ (Buffer[StrStart+2]==VendorStr[1]) &&
+ (Buffer[StrStart+3]==VendorStr[2]) &&
+ (Buffer[StrStart+4]==VendorStr[3])) {
+ Buffer[StrEnd] = 0;
+ UnicodeSPrintAsciiFormat(VendorDesc, DescBufferSize, "%a", &Buffer[StrStart+1+4+2]);
+ Vendor_found = TRUE;
+ }
+ }
+ } else {
+ // 0 1234567 8
+ //\n\tDDDD |<desc>|\n
+ if ((StrEnd - StrStart) > 8) {
+ if ((Buffer[StrStart+1]=='\t') &&
+ (Buffer[StrStart+2]==DeviceStr[0]) &&
+ (Buffer[StrStart+3]==DeviceStr[1]) &&
+ (Buffer[StrStart+4]==DeviceStr[2]) &&
+ (Buffer[StrStart+5]==DeviceStr[3])) {
+ Buffer[StrEnd] = 0;
+ UnicodeSPrintAsciiFormat(DeviceDesc, DescBufferSize, "%a", &Buffer[StrStart+1+1+4+2]);
+ Device_found = TRUE;
+ goto end;
+ }
+ }
+ }
+ StrStart = StrEnd;
+ }
+ }
+
+ if (FilePos+Size >= FileSize) {
+ break;
+ }
+ FilePos += StrEnd;
+ Status = ShellSetFilePosition(FileHandle, FilePos);
+ if (EFI_ERROR(Status))
+ {
+ Print(L"Can't set file position pci.ids: %r\n", Status);
+ goto end;
+ }
+ }
+
+end:
+ if (!Vendor_found) {
+ UnicodeSPrint(VendorDesc, DescBufferSize, L"Undefined");
+ }
+ if (!Device_found) {
+ UnicodeSPrint(DeviceDesc, DescBufferSize, L"Undefined");
+ }
+ ShellCloseFile(&FileHandle);
+
+ return Status;
+}
+
+
+UINT64 PciConfigurationAddress(UINT8 Bus,
+ UINT8 Device,
+ UINT8 Function,
+ UINT32 Register)
+{
+ UINT64 Address = (((UINT64)Bus) << 24) + (((UINT64)Device) << 16) + (((UINT64)Function) << 8);
+ if (Register & 0xFFFFFF00) {
+ Address += (((UINT64)Register) << 32);
+ } else {
+ Address += (((UINT64)Register) << 0);
+ }
+ return Address;
+}
+
+
+EFI_STATUS PrintRootBridge(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL* PciRootBridgeIo)
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR* AddressDescriptor;
+ EFI_STATUS Status = PciRootBridgeIo->Configuration(
+ PciRootBridgeIo,
+ (VOID**)&AddressDescriptor
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"\tError! Can't get EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR: %r\n", Status);
+ return Status;
+ }
+ while (AddressDescriptor->Desc != ACPI_END_TAG_DESCRIPTOR) {
+ if (AddressDescriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
+ for (UINT8 Bus = AddressDescriptor->AddrRangeMin; Bus <= AddressDescriptor->AddrRangeMax; Bus++) {
+ for (UINT8 Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+ for (UINT8 Func = 0; Func <= PCI_MAX_FUNC; Func++) {
+ UINT64 Address = PciConfigurationAddress(Bus, Device, Func, 0);
+ PCI_DEVICE_INDEPENDENT_REGION PCIConfHdr;
+ Status = PciRootBridgeIo->Pci.Read(
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ sizeof(PCI_DEVICE_INDEPENDENT_REGION),
+ &PCIConfHdr
+ );
+ if (!EFI_ERROR(Status)) {
+ if (PCIConfHdr.VendorId != 0xffff) {
+ Print(L" %02x:%02x.%02x - Vendor:%04x, Device:%04x",
+ Bus,
+ Device,
+ Func,
+ PCIConfHdr.VendorId,
+ PCIConfHdr.DeviceId);
+
+ CHAR16 VendorDesc[DESCRIPTOR_STR_MAX_SIZE];
+ CHAR16 DeviceDesc[DESCRIPTOR_STR_MAX_SIZE];
+ Status = FindPCIDevDescription(PCIConfHdr.VendorId,
+ PCIConfHdr.DeviceId,
+ VendorDesc,
+ DeviceDesc,
+ DESCRIPTOR_STR_MAX_SIZE);
+ if (!EFI_ERROR(Status)) {
+ Print(L": %s, %s\n", VendorDesc, DeviceDesc);
+ } else {
+ Print(L"\n");
+ }
+ }
+ } else {
+ Print(L" Error in PCI read: %r\n", Status);
+ }
+ }
+ }
+ }
+ }
+ AddressDescriptor++;
+ }
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ Status = gBS->LocateHandleBuffer(
+ ByProtocol,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ Print(L"Can't locate EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL: %r\n", Status);
+ return Status;
+ }
+
+ Print(L"Number of PCI root bridges in the system: %d\n", HandleCount);
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL* PciRootBridgeIo;
+ for (UINTN Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->OpenProtocol (
+ HandleBuffer[Index],
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **)&PciRootBridgeIo,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"Can't open protocol: %r\n", Status);
+ return Status;
+ }
+ Print(L"\nPCI Root Bridge %d\n", Index);
+ Status = PrintRootBridge(PciRootBridgeIo);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error in PCI Root Bridge printing\n");
+ }
+ }
+ FreePool(HandleBuffer);
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_31/UefiLessonsPkg/ListPCI/ListPCI.inf b/Lessons/Lesson_31/UefiLessonsPkg/ListPCI/ListPCI.inf
new file mode 100644
index 0000000..0080d75
--- /dev/null
+++ b/Lessons/Lesson_31/UefiLessonsPkg/ListPCI/ListPCI.inf
@@ -0,0 +1,22 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = ListPCI
+ FILE_GUID = 07aceb78-97df-4e49-84a8-28997896e42a
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ ListPCI.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ ShellLib
+
+[Protocols]
+ gEfiPciRootBridgeIoProtocolGuid
diff --git a/Lessons/Lesson_32/README.md b/Lessons/Lesson_32/README.md
new file mode 100644
index 0000000..78c12f6
--- /dev/null
+++ b/Lessons/Lesson_32/README.md
@@ -0,0 +1,545 @@
+In this lesson we would try to list OptionROMs that are present in the PCI devices in our system.
+
+# Theory
+
+Some PCI devices like graphic cards require additional 'drivers' to work at the BIOS stage.
+
+But BIOS is not an OS, it can't have all the drivers for all the possible PCI devices that you can plug into your board. To solve this problem such complex PCI devices store its 'driver' it its own firmware. This is a concept known as a PCI Option ROM https://en.wikipedia.org/wiki/Option_ROM
+
+BIOS queries PCI configuration space in every PCI device and determines if it has an option ROM. If it has BIOS can execute code from the option ROM depending on the BIOS settings.
+
+PCI Option ROM can have several code images in itself. The common case is that option ROM contains two images:
+- driver for the legacy BIOS (Legacy OpROM)
+- driver for the UEFI BIOS (UEFI OpROM)
+
+Keep in mind that older cards can contain only driver for the legacy BIOS, newer/future ones can contain only driver for the UEFI BIOS.
+
+Currently the world is in the transition process from Legacy BIOS interface to UEFI. UEFI firmware doesn't work with Legacy OpROMs. But for now vendors still leave a possibility to work with such legacy interfaces via CSM mode.
+
+But you wouldn't see any output, if you set a BIOS policy to load only UEFI OpROMs, but your graphic card only contains Legacy OpROM.
+
+Also OptionROM can have various code images for different CPU architectures, so this PCI device could work both with ARM CPU host and x86 CPU host.
+
+As you can see it might be very interesting to know which OptionROMs your PCI device contain. So let's write the UEFI Shell utility that can show us that.
+
+# `EFI_PCI_IO_PROTOCOL`
+
+To access PCI devices we would utilize `EFI_PCI_IO_PROTOCOL` https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/PciRootBridgeIo.h
+```
+typedef struct _EFI_PCI_IO_PROTOCOL {
+EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollMem;
+ EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollIo;
+ EFI_PCI_IO_PROTOCOL_ACCESS Mem;
+ EFI_PCI_IO_PROTOCOL_ACCESS Io;
+ EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS Pci;
+ EFI_PCI_IO_PROTOCOL_COPY_MEM CopyMem;
+ EFI_PCI_IO_PROTOCOL_MAP Map;
+ EFI_PCI_IO_PROTOCOL_UNMAP Unmap;
+ EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer;
+ EFI_PCI_IO_PROTOCOL_FREE_BUFFER FreeBuffer;
+ EFI_PCI_IO_PROTOCOL_FLUSH Flush;
+ EFI_PCI_IO_PROTOCOL_GET_LOCATION GetLocation;
+ EFI_PCI_IO_PROTOCOL_ATTRIBUTES Attributes;
+ EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES GetBarAttributes;
+ EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES SetBarAttributes;
+ UINT64 RomSize;
+ VOID *RomImage;
+} EFI_PCI_IO_PROTOCOL;
+```
+
+As you can see it is pretty similar to the `EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL` we've used in the last lesson. Here is a comparision of these two:
+```
+typedef struct _EFI_PCI_IO_PROTOCOL { typedef struct _EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL {
+ EFI_HANDLE ParentHandle;
+ EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollMem; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM PollMem;
+ EFI_PCI_IO_PROTOCOL_POLL_IO_MEM PollIo; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_POLL_IO_MEM PollIo;
+ EFI_PCI_IO_PROTOCOL_ACCESS Mem; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Mem;
+ EFI_PCI_IO_PROTOCOL_ACCESS Io; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Io;
+ EFI_PCI_IO_PROTOCOL_CONFIG_ACCESS Pci; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ACCESS Pci;
+ EFI_PCI_IO_PROTOCOL_COPY_MEM CopyMem; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_COPY_MEM CopyMem;
+ EFI_PCI_IO_PROTOCOL_MAP Map; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_MAP Map;
+ EFI_PCI_IO_PROTOCOL_UNMAP Unmap; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_UNMAP Unmap;
+ EFI_PCI_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer;
+ EFI_PCI_IO_PROTOCOL_FREE_BUFFER FreeBuffer; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FREE_BUFFER FreeBuffer;
+ EFI_PCI_IO_PROTOCOL_FLUSH Flush; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_FLUSH Flush;
+ EFI_PCI_IO_PROTOCOL_GET_LOCATION GetLocation;
+ EFI_PCI_IO_PROTOCOL_ATTRIBUTES Attributes;
+ EFI_PCI_IO_PROTOCOL_GET_BAR_ATTRIBUTES GetBarAttributes; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GET_ATTRIBUTES GetAttributes;
+ EFI_PCI_IO_PROTOCOL_SET_BAR_ATTRIBUTES SetBarAttributes; EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_SET_ATTRIBUTES SetAttributes;
+ UINT64 RomSize;
+ VOID *RomImage;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_CONFIGURATION Configuration;
+ UINT32 SegmentNumber;
+} EFI_PCI_IO_PROTOCOL; } EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL;
+```
+
+The main difference is that `EFI_PCI_IO_PROTOCOL` is attached to every PCI device in the system and the `EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL` is attached only to PCI Root Bridges.
+
+To access PCI OptionROM we would need to utilize these parameters from the `EFI_PCI_IO_PROTOCOL`:
+```
+RomSize The size, in bytes, of the ROM image.
+RomImage A pointer to the in memory copy of the ROM image. The PCI Bus Driver is responsible
+ for allocating memory for the ROM image, and copying the contents of the ROM to memory.
+ The contents of this buffer are either from the PCI option ROM that can be accessed
+ through the ROM BAR of the PCI controller, or it is from a platformspecific location.
+ The Attributes() function can be used to determine from which of these two sources
+ the RomImage buffer was initialized
+```
+
+First let's try to enumerate PCI devices in our system with this `EFI_PCI_IO_PROTOCOL`. The logic is similar to the one, that we've used in the previous lesson. First we find all handles that have `EFI_PCI_IO_PROTOCOL` protocol via `LocateHandleBuffer` API and then we actually get the each protocol with a `OpenProtocol` call. On every protocol we would execute our `PrintPCI` function that we would write next:
+```
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ Status = gBS->LocateHandleBuffer(
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ Print(L"Can't locate EFI_PCI_IO_PROTOCOL: %r\n", Status);
+ return Status;
+ }
+
+ //Print(L"Number of PCI devices in the system: %d\n", HandleCount);
+ EFI_PCI_IO_PROTOCOL* PciIo;
+ for (UINTN Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->OpenProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"Can't open protocol: %r\n", Status);
+ return Status;
+ }
+ Status = PrintPCI(PciIo);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error in PCI printing\n");
+ }
+
+ }
+ FreePool(HandleBuffer);
+
+ return EFI_SUCCESS;
+}
+```
+
+When we have a `EFI_PCI_IO_PROTOCOL` we can execute `GetLocation()` to know the current PCI controller’s address:
+```
+EFI_PCI_IO_PROTOCOL.GetLocation()
+
+Summary:
+Retrieves this PCI controller’s current PCI bus number, device number, and function number.
+
+Prototype:
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PCI_IO_PROTOCOL_GET_LOCATION) (
+ IN EFI_PCI_IO_PROTOCOL *This,
+ OUT UINTN *SegmentNumber,
+ OUT UINTN *BusNumber,
+ OUT UINTN *DeviceNumber,
+ OUT UINTN *FunctionNumber
+ );
+
+Parameters:
+This A pointer to the EFI_PCI_IO_PROTOCOL instance.
+SegmentNumber The PCI controller’s current PCI segment number.
+BusNumber The PCI controller’s current PCI bus number.
+DeviceNumber The PCI controller’s current PCI device number.
+FunctionNumber The PCI controller’s current PCI function number.
+
+Description:
+The GetLocation() function retrieves a PCI controller’s current location on a PCI Host Bridge. This is
+specified by a PCI segment number, PCI bus number, PCI device number, and PCI function number. These
+values can be used with the PCI Root Bridge I/O Protocol to perform PCI configuration cycles on the PCI
+controller, or any of its peer PCI controller’s on the same PCI Host Bridge.
+```
+
+So let's write our `PrintPCI` function:
+```
+EFI_STATUS PrintPCI(EFI_PCI_IO_PROTOCOL* PciIo)
+{
+ UINTN SegmentNumber;
+ UINTN BusNumber;
+ UINTN DeviceNumber;
+ UINTN FunctionNumber;
+ EFI_STATUS Status = PciIo->GetLocation(PciIo,
+ &SegmentNumber,
+ &BusNumber,
+ &DeviceNumber,
+ &FunctionNumber);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error in getting PCI location: %r\n", Status);
+ return Status;
+ }
+
+ PCI_DEVICE_INDEPENDENT_REGION PCIConfHdr;
+ Status = PciIo->Pci.Read(PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ sizeof(PCI_DEVICE_INDEPENDENT_REGION),
+ &PCIConfHdr);
+
+ if (EFI_ERROR(Status)) {
+ Print(L"Error in reading PCI conf space: %r\n", Status);
+ return Status;
+ }
+
+ Print(L"%02x:%02x.%02x - Vendor:%04x, Device:%04x", BusNumber,
+ DeviceNumber,
+ FunctionNumber,
+ PCIConfHdr.VendorId,
+ PCIConfHdr.DeviceId);
+
+ return Status;
+}
+
+```
+After using `GetLocation` API we've used `Pci.Read` call to read PCI configuration space like we did in earlier lesson.
+
+If you'll build and execute our app now you would get the same list of PCI devices, that we've received with a `EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL`.
+```
+FS0:\> PCIRomInfo.efi
+00:00.00 - Vendor:8086, Device:1237
+00:01.00 - Vendor:8086, Device:7000
+00:01.01 - Vendor:8086, Device:7010
+00:01.03 - Vendor:8086, Device:7113
+00:02.00 - Vendor:1234, Device:1111
+```
+
+But right now we are interested only in devices that have PCI Option ROM, so replace the `Print` statement to:
+```
+if (PciIo->RomSize) {
+ Print(L"%02x:%02x.%02x - Vendor:%04x, Device:%04x", BusNumber,
+ DeviceNumber,
+ FunctionNumber,
+ PCIConfHdr.VendorId,
+ PCIConfHdr.DeviceId);
+
+ CHAR16 VendorDesc[DESCRIPTOR_STR_MAX_SIZE];
+ CHAR16 DeviceDesc[DESCRIPTOR_STR_MAX_SIZE];
+ Status = FindPCIDevDescription(PCIConfHdr.VendorId,
+ PCIConfHdr.DeviceId,
+ VendorDesc,
+ DeviceDesc,
+ DESCRIPTOR_STR_MAX_SIZE);
+ if (!EFI_ERROR(Status)) {
+ Print(L": %s, %s\n", VendorDesc, DeviceDesc);
+ } else {
+ Print(L"\n");
+ }
+ PrintOptionROM(PciIo->RomImage, PciIo->RomSize);
+}
+```
+Here I've used a `FindPCIDevDescription` function, you need to copy it from the last lesson. Also the main OptionROM printing would be happening in a `PrintOptionROM` that we'll write next.
+
+But first some theory.
+
+OptionROM image in memory would have a special header. edk2 definition for the header structure is `PCI_EXPANSION_ROM_HEADER`. This header contains signature field that is equal to `0xAA55`. You can check out definitions in a file https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Pci22.h:
+```
+#define PCI_EXPANSION_ROM_HEADER_SIGNATURE 0xaa55
+
+...
+
+///
+/// Standard PCI Expansion ROM Header
+/// Section 13.4.2, Unified Extensible Firmware Interface Specification, Version 2.1
+///
+typedef struct {
+ UINT16 Signature; ///< 0xaa55
+ UINT8 Reserved[0x16];
+ UINT16 PcirOffset;
+} PCI_EXPANSION_ROM_HEADER;
+```
+This header has offset (`PcirOffset`) to another header `PCI_DATA_STRUCTURE`. It also has a `signature` field which is equal to `PCIR` in this case:
+```
+///
+/// PCI Data Structure Format
+/// Section 6.3.1.2, PCI Local Bus Specification, 2.2
+///
+typedef struct {
+ UINT32 Signature; ///< "PCIR"
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT16 Reserved0;
+ UINT16 Length;
+ UINT8 Revision;
+ UINT8 ClassCode[3];
+ UINT16 ImageLength;
+ UINT16 CodeRevision;
+ UINT8 CodeType;
+ UINT8 Indicator;
+ UINT16 Reserved1;
+} PCI_DATA_STRUCTURE;
+```
+These two headers prepends every code image in an Option ROM. As you remember there can be several code images in the Option ROM. To find all of them we need to loop through the header structures.
+Two fields will help us to do it:
+- `PCI_DATA_STRUCTURE.ImageLength` - describes the total code image size in 512 byte increments,
+- `PCI_DATA_STRUCTURE.Indicator` - the most significant bit of this byte tells if this is the last code image in the option ROM
+
+With this in mind let's write the main loop for the Option ROM parsing:
+```
+VOID PrintOptionROM(VOID *RomImage, UINT64 RomSize)
+{
+ Print(L"Has OptionROM at memory %p-%p\n", RomImage, (UINT8*)RomImage + RomSize);
+ PCI_EXPANSION_ROM_HEADER* RomHeader = (PCI_EXPANSION_ROM_HEADER*) RomImage;
+ UINTN RomImageIndex = 1;
+ while (TRUE)
+ {
+ if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ Print(L"Error! OptionROM has a wrong signature\n");
+ return;
+ }
+ PCI_DATA_STRUCTURE* RomImage = (PCI_DATA_STRUCTURE*)((UINT8*)RomHeader + RomHeader->PcirOffset);
+ if ((((CHAR8)((RomImage->Signature >> 0) & 0xFF)) != 'P') &&
+ (((CHAR8)((RomImage->Signature >> 8) & 0xFF)) != 'C') &&
+ (((CHAR8)((RomImage->Signature >> 16) & 0xFF)) != 'I') &&
+ (((CHAR8)((RomImage->Signature >> 24) & 0xFF)) != 'R')) {
+ Print(L"Error! OptionROM image has wrong signature\n");
+ return;
+ }
+
+ <...>
+
+ if ((RomImage->Indicator) & 0x80) {
+ break;
+ }
+ RomHeader = (PCI_EXPANSION_ROM_HEADER*)((UINT8*) RomHeader + (RomImage->ImageLength)*512);
+ RomImageIndex++;
+ }
+ Print(L"------------------\n");
+}
+```
+
+In the `<...>` we should write an actual parsing of the code image.
+
+UEFI specification was trying to adapt to the current Option ROM design that was already present when UEFI is originated. It appears that original Option ROM design wasn't thought with extendability in mind. Therefore UEFI extended it as it could, and now the parsing process may look a little bit strange.
+
+First we need to look at the field `PCI_DATA_STRUCTURE.CodeType` in the second header. And by this field interpret the first `PCI_EXPANSION_ROM_HEADER`.
+
+That is why there is a strange `union` in the https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/Pci22.h:
+```
+typedef union {
+ UINT8 *Raw;
+ PCI_EXPANSION_ROM_HEADER *Generic;
+ EFI_PCI_EXPANSION_ROM_HEADER *Efi;
+ EFI_LEGACY_EXPANSION_ROM_HEADER *PcAt;
+} EFI_PCI_ROM_HEADER;
+```
+It means that:
+- if an image is Legacy (`PCI_DATA_STRUCTURE.CodeType = 0x00`) then you should treat `EFI_PCI_ROM_HEADER` as a `EFI_LEGACY_EXPANSION_ROM_HEADER`
+- if an image is UEFI (`PCI_DATA_STRUCTURE.CodeType = 0x03`) then you should treat `EFI_PCI_ROM_HEADER` as a `EFI_PCI_EXPANSION_ROM_HEADER`
+- if you don't know image type yet, you can only treat `EFI_PCI_ROM_HEADER` as a `PCI_EXPANSION_ROM_HEADER`
+
+
+There is nothing useful for us in the `EFI_LEGACY_EXPANSION_ROM_HEADER`, so we would only print additional information if the image is EFI:
+```
+Print(L"---Code Image %d---\n", RomImageIndex);
+Print(L"Address: %p-%p\n", RomHeader, (UINT8*)RomHeader + (RomImage->ImageLength)*512);
+Print(L"VendorId: %04x, DeviceId: %04x\n", RomImage->VendorId, RomImage->DeviceId);
+Print(L"Type: ");
+switch (RomImage->CodeType) {
+ case 0x00:
+ Print(L"IA-32, PC-AT compatible\n");
+ break;
+ case 0x01:
+ Print(L"Open Firmware standard for PCI\n");
+ break;
+ case 0x02:
+ Print(L"Hewlett-Packard PA RISC\n");
+ break;
+ case 0x03:
+ Print(L"EFI Image\n");
+ break;
+ default:
+ Print(L"Unknown\n");
+ break;
+}
+if (RomImage->CodeType == 0x03) {
+ EFI_PCI_EXPANSION_ROM_HEADER* EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER*) RomHeader;
+ if (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) {
+ <print additional EFI image info>
+ } else {
+ Print(L"EFI signature is incorrect!\n");
+ }
+}
+```
+
+If the image is EFI we can print its type, target CPU architecture and compression:
+```
+Print(L"Subsystem: ");
+switch (EfiRomHeader->EfiSubsystem) {
+ case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
+ Print(L"EFI Application\n");
+ break;
+ case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
+ Print(L"EFI Boot Service Driver\n");
+ break;
+ case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
+ Print(L"EFI Runtime Driver\n");
+ break;
+ case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
+ Print(L"EFI SAL Runtime Driver\n");
+ break;
+ default:
+ Print(L"Unknown\n");
+ break;
+}
+Print(L"Machine type: ");
+switch (EfiRomHeader->EfiMachineType) {
+ case IMAGE_FILE_MACHINE_I386:
+ Print(L"IA-32\n");
+ break;
+ case IMAGE_FILE_MACHINE_IA64:
+ Print(L"Itanium\n");
+ break;
+ case IMAGE_FILE_MACHINE_EBC:
+ Print(L"EFI Byte Code (EBC)\n");
+ break;
+ case IMAGE_FILE_MACHINE_X64:
+ Print(L"X64\n");
+ break;
+ case IMAGE_FILE_MACHINE_ARMTHUMB_MIXED:
+ Print(L"ARM\n");
+ break;
+ case IMAGE_FILE_MACHINE_ARM64:
+ Print(L"ARM 64-bit\n");
+ break;
+ case IMAGE_FILE_MACHINE_RISCV32:
+ Print(L"RISCV32\n");
+ break;
+ case IMAGE_FILE_MACHINE_RISCV64:
+ Print(L"RISCV64\n");
+ break;
+ case IMAGE_FILE_MACHINE_RISCV128:
+ Print(L"RISCV128\n");
+ break;
+ default:
+ Print(L"Unknown\n");
+ break;
+}
+switch (EfiRomHeader->CompressionType) {
+ case EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED:
+ Print(L"Compressed following the UEFI Compression Algorithm\n");
+ break;
+ case 0:
+ Print(L"Uncompressed\n");
+ break;
+ default:
+ Print(L"Unknown compression type\n");
+ break;
+}
+```
+Check out "PCI Option ROMs" part in the UEFI spec for the explanation of the parsing process.
+Also some of these case statements use constants from the PE specification, therefore we have to include PE Image header https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/PeImage.h:
+```
+#include <IndustryStandard/PeImage.h>
+```
+
+Build our program. After that copy its `*.efi` executable to our QEMU shared folder and run OVMF with a command:
+```
+$ qemu-system-x86_64 -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
+ -nographic \
+ -net none
+```
+
+If you execute our program now you would get:
+```
+FS0:\> PCIRomInfo.efi
+00:02.00 - Vendor:1234, Device:1111: Undefined, Undefined
+Has OptionROM at memory 6EA5018-6EAEA18
+---Code Image 1---
+Address: 6EA5018-6EAEA18
+PCIR address: 6EAE854
+VendorId: 1234, DeviceId: 1111
+Type: IA-32, PC-AT compatible
+------------------
+```
+
+You can use `dmem` to peak in the Option ROM regions. At the `6EA5018` you can see the first header with its `AA55` signature:
+```
+FS0:\> dmem 6EA5018 30
+Memory Address 0000000006EA5018 30 Bytes
+ 06EA5018: 55 AA 4D E9 AE 55 B4 00-00 00 00 00 00 00 00 00 *U.M..U..........*
+ 06EA5028: 00 00 00 00 00 00 00 00-3C 98 00 00 00 00 49 42 *........<.....IB*
+ 06EA5038: 4D 00 2E 8B 16 C6 98 85-D2 74 01 EE C2 02 00 66 *M........t.....f*
+```
+And at the `6EAE854` you can observe the second header with its `PCIR` signature. After it immediately follows PCI vendor/device pair (`1234:1111`):
+```
+FS0:\> dmem 6EAE854 30
+Memory Address 0000000006EAE854 30 Bytes
+ 06EAE854: 50 43 49 52 34 12 11 11-00 00 18 00 00 00 00 03 *PCIR4...........*
+ 06EAE864: 4D 00 01 00 00 80 00 00-66 90 66 90 66 90 66 90 *M.......f.f.f.f.*
+ 06EAE874: 66 90 66 90 67 63 63 3A-20 28 55 62 75 6E 74 75 *f.f.gcc: (Ubuntu*
+```
+
+
+Now let's rerun our QEMU without `-net none` option:
+```
+$ qemu-system-x86_64 -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
+ -nographic
+```
+And execute our program again:
+```
+FS0:\> PCIRomInfo.efi
+00:02.00 - Vendor:1234, Device:1111: Undefined, Undefined
+Has OptionROM at memory 6EA5018-6EAEA18
+---Code Image 1---
+Address: 6EA5018-6EAEA18
+PCIR address: 6EAE854
+VendorId: 1234, DeviceId: 1111
+Type: IA-32, PC-AT compatible
+------------------
+00:03.00 - Vendor:8086, Device:100E: Intel Corporation, 82540EM Gigabit Ethernet Controller
+Has OptionROM at memory 6E59018-6EA4218
+---Code Image 1---
+Address: 6E59018-6E6F418
+PCIR address: 6E59034
+VendorId: 8086, DeviceId: 100E
+Type: IA-32, PC-AT compatible
+---Code Image 2---
+Address: 6E6F418-6EA4218
+PCIR address: 6E6F434
+VendorId: 8086, DeviceId: 100E
+Type: EFI Image
+Subsystem: EFI Boot Service Driver
+Machine type: X64
+Uncompressed
+------------------
+```
+Now besides the Legacy Option ROM for the `1234:1111` VGA QEMU device there is another Option ROM.
+
+This second Option ROM is for the PCI network card and it has two code images in itself: for legacy BIOS and for UEFI.
+
+If you peak in the second image you'll see some strings that will give you a clue that this is an iPXE image (https://ipxe.org/start):
+```
+FS0:\> dmem 6E59018 c0
+Memory Address 0000000006E59018 C0 Bytes
+ 06E59018: 55 AA B2 E9 A2 00 22 00-00 00 00 00 00 00 00 00 *U.....".........*
+ 06E59028: 9C 00 00 00 00 00 84 00-1C 00 40 00 50 43 49 52 *..........@.PCIR*
+ 06E59038: 86 80 0E 10 BF 04 1C 00-03 02 00 00 B2 00 01 00 *................*
+ 06E59048: 00 00 07 00 00 00 00 00-8D B4 00 00 8D B4 00 00 *................*
+ 06E59058: 24 50 6E 50 01 02 00 00-00 7D 00 00 00 00 60 00 *$PnP.....}....`.*
+ 06E59068: 70 00 02 00 00 F4 00 00-00 00 85 03 00 00 00 00 *p...............*
+ 06E59078: 68 74 74 70 3A 2F 2F 69-70 78 65 2E 6F 72 67 00 *http://ipxe.org.*
+ 06E59088: 69 50 58 45 00 28 50 43-49 20 78 78 3A 78 78 2E *iPXE.(PCI xx:xx.*
+ 06E59098: 78 29 00 90 55 4E 44 49-16 1D 00 00 01 02 A4 04 *x)..UNDI........*
+ 06E590A8: 10 2D 10 2D 42 08 50 43-49 52 66 90 69 50 58 45 *.-.-B.PCIRf.iPXE*
+ 06E590B8: 0C 4E 07 00 FE DB B2 BE-60 1E 06 0F A0 0F A8 FC *.N......`.......*
+ 06E590C8: 0E 1F BE 27 03 31 FF E8-4C 04 8E EB 31 FF E8 3D *...'.1..L...1..=*
+```
+
diff --git a/Lessons/Lesson_32/UefiLessonsPkg/PCIRomInfo/PCIRomInfo.c b/Lessons/Lesson_32/UefiLessonsPkg/PCIRomInfo/PCIRomInfo.c
new file mode 100644
index 0000000..7531192
--- /dev/null
+++ b/Lessons/Lesson_32/UefiLessonsPkg/PCIRomInfo/PCIRomInfo.c
@@ -0,0 +1,380 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/PciIo.h>
+#include <Library/MemoryAllocationLib.h>
+#include <IndustryStandard/Pci.h>
+#include <Library/ShellLib.h>
+#include <Library/PrintLib.h>
+
+#include <IndustryStandard/PeImage.h>
+
+
+#define DESCRIPTOR_STR_MAX_SIZE 200
+#define BLOCK_READ_SIZE (1024*4)
+
+VOID ToLowerASCII(CHAR8* Str, UINTN Size)
+{
+ for (UINT8 i=0; i<Size; i++) {
+ if ((Str[i]>='A')&&(Str[i]<='Z')) {
+ Str[i]+=32;
+ }
+ }
+}
+
+EFI_STATUS FindPCIDevDescription(UINT16 VendorId,
+ UINT16 DeviceId,
+ CHAR16* VendorDesc,
+ CHAR16* DeviceDesc,
+ UINTN DescBufferSize)
+{
+ EFI_STATUS Status = ShellFileExists(L"pci.ids");
+ if (EFI_ERROR(Status))
+ {
+ Print(L"No file pci.ids: %r\n", Status);
+ return Status;
+ }
+
+ SHELL_FILE_HANDLE FileHandle;
+ Status = ShellOpenFileByName(L"pci.ids",
+ &FileHandle,
+ EFI_FILE_MODE_READ,
+ 0);
+ if (EFI_ERROR(Status))
+ {
+ Print(L"Can't open file pci.ids: %r\n", Status);
+ return Status;
+ }
+
+ UINT64 FileSize;
+ Status = ShellGetFileSize(FileHandle, &FileSize);
+ if (EFI_ERROR(Status))
+ {
+ Print(L"Can't get file size for file pci.ids: %r\n", Status);
+ goto end;
+ }
+
+ CHAR8 VendorStr[5];
+ CHAR8 DeviceStr[5];
+ AsciiValueToStringS(VendorStr,
+ 5,
+ RADIX_HEX | PREFIX_ZERO,
+ VendorId,
+ 4);
+ AsciiValueToStringS(DeviceStr,
+ 5,
+ RADIX_HEX | PREFIX_ZERO,
+ DeviceId,
+ 4);
+ ToLowerASCII(VendorStr, 4);
+ ToLowerASCII(DeviceStr, 4);
+
+ CHAR8 Buffer[BLOCK_READ_SIZE];
+ UINTN Size;
+ UINT64 FilePos = 0;
+ BOOLEAN Vendor_found = FALSE;
+ BOOLEAN Device_found = FALSE;
+ while (TRUE)
+ {
+ Size = BLOCK_READ_SIZE;
+ Status = ShellReadFile(FileHandle, &Size, Buffer);
+ if (EFI_ERROR(Status))
+ {
+ Print(L"Can't read file pci.ids: %r\n", Status);
+ goto end;
+ }
+ UINTN StrStart = 0;
+ UINTN StrEnd = 0;
+ for (UINTN i=0; i<Size; i++) {
+ if (Buffer[i]=='\n') {
+ StrEnd=i;
+ if (!Vendor_found){
+ // 0123456 7
+ //\nXXXX |<desc>|\n
+ if ((StrEnd - StrStart) > 7) {
+ if ((Buffer[StrStart+1]==VendorStr[0]) &&
+ (Buffer[StrStart+2]==VendorStr[1]) &&
+ (Buffer[StrStart+3]==VendorStr[2]) &&
+ (Buffer[StrStart+4]==VendorStr[3])) {
+ Buffer[StrEnd] = 0;
+ UnicodeSPrintAsciiFormat(VendorDesc, DescBufferSize, "%a", &Buffer[StrStart+1+4+2]);
+ Vendor_found = TRUE;
+ }
+ }
+ } else {
+ // 0 1234567 8
+ //\n\tXXXX |<desc>|\n
+ if ((StrEnd - StrStart) > 8) {
+ if ((Buffer[StrStart+1]=='\t') &&
+ (Buffer[StrStart+2]==DeviceStr[0]) &&
+ (Buffer[StrStart+3]==DeviceStr[1]) &&
+ (Buffer[StrStart+4]==DeviceStr[2]) &&
+ (Buffer[StrStart+5]==DeviceStr[3])) {
+ Buffer[StrEnd] = 0;
+ UnicodeSPrintAsciiFormat(DeviceDesc, DescBufferSize, "%a", &Buffer[StrStart+1+1+4+2]);
+ Device_found = TRUE;
+ break;
+ }
+ }
+ }
+ StrStart = StrEnd;
+ }
+ }
+
+ if (FilePos+Size >= FileSize) {
+ break;
+ }
+ FilePos += StrEnd;
+ Status = ShellSetFilePosition(FileHandle, FilePos);
+ if (EFI_ERROR(Status))
+ {
+ Print(L"Can't set file position pci.ids: %r\n", Status);
+ goto end;
+ }
+ }
+
+end:
+ if (!Vendor_found) {
+ UnicodeSPrint(VendorDesc, DescBufferSize, L"Undefined");
+ }
+ if (!Device_found) {
+ UnicodeSPrint(DeviceDesc, DescBufferSize, L"Undefined");
+ }
+ ShellCloseFile(&FileHandle);
+
+ return Status;
+}
+
+
+UINT64 PciConfigurationAddress(UINT8 Bus,
+ UINT8 Device,
+ UINT8 Function,
+ UINT32 Register)
+{
+ UINT64 Address = (((UINT64)Bus) << 24) + (((UINT64)Device) << 16) + (((UINT64)Function) << 8);
+ if (Register & 0xFFFFFF00) {
+ Address += (((UINT64)Register) << 32);
+ } else {
+ Address += (((UINT64)Register) << 0);
+ }
+ return Address;
+}
+
+VOID PrintOptionROM(VOID *RomImage, UINT64 RomSize)
+{
+ Print(L"Has OptionROM at memory %p-%p\n", RomImage, (UINT8*)RomImage + RomSize);
+ PCI_EXPANSION_ROM_HEADER* RomHeader = (PCI_EXPANSION_ROM_HEADER*) RomImage;
+ UINTN RomImageIndex = 1;
+ while (TRUE)
+ {
+ if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ Print(L"Error! OptionROM has a wrong signature\n");
+ return;
+ }
+ PCI_DATA_STRUCTURE* RomImage = (PCI_DATA_STRUCTURE*)((UINT8*)RomHeader + RomHeader->PcirOffset);
+ if ((((CHAR8)((RomImage->Signature >> 0) & 0xFF)) != 'P') &&
+ (((CHAR8)((RomImage->Signature >> 8) & 0xFF)) != 'C') &&
+ (((CHAR8)((RomImage->Signature >> 16) & 0xFF)) != 'I') &&
+ (((CHAR8)((RomImage->Signature >> 24) & 0xFF)) != 'R')) {
+ Print(L"Error! OptionROM image has wrong signature\n");
+ return;
+ }
+ Print(L"---Code Image %d---\n", RomImageIndex);
+ Print(L"Address: %p-%p\n", RomHeader, (UINT8*)RomHeader + (RomImage->ImageLength)*512);
+ Print(L"PCIR address: %p\n", RomImage);
+ Print(L"VendorId: %04x, DeviceId: %04x\n", RomImage->VendorId, RomImage->DeviceId);
+ Print(L"Type: ");
+ switch (RomImage->CodeType) {
+ case 0x00:
+ Print(L"IA-32, PC-AT compatible\n");
+ break;
+ case 0x01:
+ Print(L"Open Firmware standard for PCI\n");
+ break;
+ case 0x02:
+ Print(L"Hewlett-Packard PA RISC\n");
+ break;
+ case 0x03:
+ Print(L"EFI Image\n");
+ break;
+ default:
+ Print(L"Unknown\n");
+ break;
+ }
+ if (RomImage->CodeType == 0x03) {
+ EFI_PCI_EXPANSION_ROM_HEADER* EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER*) RomHeader;
+ if (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) {
+ Print(L"Subsystem: ");
+ switch (EfiRomHeader->EfiSubsystem) {
+ case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
+ Print(L"EFI Application\n");
+ break;
+ case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
+ Print(L"EFI Boot Service Driver\n");
+ break;
+ case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
+ Print(L"EFI Runtime Driver\n");
+ break;
+ case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
+ Print(L"EFI SAL Runtime Driver\n");
+ break;
+ default:
+ Print(L"Unknown\n");
+ break;
+ }
+ Print(L"Machine type: ");
+ switch (EfiRomHeader->EfiMachineType) {
+ case IMAGE_FILE_MACHINE_I386:
+ Print(L"IA-32\n");
+ break;
+ case IMAGE_FILE_MACHINE_IA64:
+ Print(L"Itanium\n");
+ break;
+ case IMAGE_FILE_MACHINE_EBC:
+ Print(L"EFI Byte Code (EBC)\n");
+ break;
+ case IMAGE_FILE_MACHINE_X64:
+ Print(L"X64\n");
+ break;
+ case IMAGE_FILE_MACHINE_ARMTHUMB_MIXED:
+ Print(L"ARM\n");
+ break;
+ case IMAGE_FILE_MACHINE_ARM64:
+ Print(L"ARM 64-bit\n");
+ break;
+ case IMAGE_FILE_MACHINE_RISCV32:
+ Print(L"RISCV32\n");
+ break;
+ case IMAGE_FILE_MACHINE_RISCV64:
+ Print(L"RISCV64\n");
+ break;
+ case IMAGE_FILE_MACHINE_RISCV128:
+ Print(L"RISCV128\n");
+ break;
+ default:
+ Print(L"Unknown\n");
+ break;
+ }
+ switch (EfiRomHeader->CompressionType) {
+ case EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED:
+ Print(L"Compressed following the UEFI Compression Algorithm\n");
+ break;
+ case 0:
+ Print(L"Uncompressed\n");
+ break;
+ default:
+ Print(L"Unknown compression type\n");
+ break;
+ }
+ } else {
+ Print(L"EFI signature is incorrect!\n");
+ }
+ }
+ if ((RomImage->Indicator) & 0x80) {
+ break;
+ }
+ RomHeader = (PCI_EXPANSION_ROM_HEADER*)((UINT8*) RomHeader + (RomImage->ImageLength)*512);
+ RomImageIndex++;
+ }
+ Print(L"------------------\n");
+}
+
+EFI_STATUS PrintPCI(EFI_PCI_IO_PROTOCOL* PciIo)
+{
+ UINTN SegmentNumber;
+ UINTN BusNumber;
+ UINTN DeviceNumber;
+ UINTN FunctionNumber;
+ EFI_STATUS Status = PciIo->GetLocation(PciIo,
+ &SegmentNumber,
+ &BusNumber,
+ &DeviceNumber,
+ &FunctionNumber);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error in getting PCI location: %r\n", Status);
+ return Status;
+ }
+
+ PCI_DEVICE_INDEPENDENT_REGION PCIConfHdr;
+ Status = PciIo->Pci.Read(PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ sizeof(PCI_DEVICE_INDEPENDENT_REGION),
+ &PCIConfHdr);
+
+ if (EFI_ERROR(Status)) {
+ Print(L"Error in reading PCI conf space: %r\n", Status);
+ return Status;
+ }
+
+ if (PciIo->RomSize) {
+ Print(L"%02x:%02x.%02x - Vendor:%04x, Device:%04x", BusNumber,
+ DeviceNumber,
+ FunctionNumber,
+ PCIConfHdr.VendorId,
+ PCIConfHdr.DeviceId);
+
+ CHAR16 VendorDesc[DESCRIPTOR_STR_MAX_SIZE];
+ CHAR16 DeviceDesc[DESCRIPTOR_STR_MAX_SIZE];
+ Status = FindPCIDevDescription(PCIConfHdr.VendorId,
+ PCIConfHdr.DeviceId,
+ VendorDesc,
+ DeviceDesc,
+ DESCRIPTOR_STR_MAX_SIZE);
+ if (!EFI_ERROR(Status)) {
+ Print(L": %s, %s\n", VendorDesc, DeviceDesc);
+ } else {
+ Print(L"\n");
+ }
+ PrintOptionROM(PciIo->RomImage, PciIo->RomSize);
+ }
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ Status = gBS->LocateHandleBuffer(
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ Print(L"Can't locate EFI_PCI_IO_PROTOCOL: %r\n", Status);
+ return Status;
+ }
+
+ //Print(L"Number of PCI devices in the system: %d\n", HandleCount);
+ EFI_PCI_IO_PROTOCOL* PciIo;
+ for (UINTN Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->OpenProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR(Status)) {
+ Print(L"Can't open protocol: %r\n", Status);
+ return Status;
+ }
+ Status = PrintPCI(PciIo);
+ if (EFI_ERROR(Status)) {
+ Print(L"Error in PCI printing\n");
+ }
+
+ }
+ FreePool(HandleBuffer);
+
+ return EFI_SUCCESS;
+}
diff --git a/Lessons/Lesson_32/UefiLessonsPkg/PCIRomInfo/PCIRomInfo.inf b/Lessons/Lesson_32/UefiLessonsPkg/PCIRomInfo/PCIRomInfo.inf
new file mode 100644
index 0000000..b098b26
--- /dev/null
+++ b/Lessons/Lesson_32/UefiLessonsPkg/PCIRomInfo/PCIRomInfo.inf
@@ -0,0 +1,22 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = PCIRomInfo
+ FILE_GUID = 76f1798f-533f-49a2-b94c-96ab3dfebea0
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ PCIRomInfo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ ShellLib
+
+[Protocols]
+ gEfiPciIoProtocolGuid
diff --git a/Lessons/Lesson_33/README.md b/Lessons/Lesson_33/README.md
new file mode 100644
index 0000000..b5b85c5
--- /dev/null
+++ b/Lessons/Lesson_33/README.md
@@ -0,0 +1,335 @@
+In this lesson we will be investigating OptionROM images with the help of BaseTools utility `EfiRom`. It is available in your path once you'll execute `. edksetup.sh` in edk2 folder.
+
+First take a look at `EfiRom` help:
+```
+$ EfiRom -h
+Usage: EfiRom -f VendorId -i DeviceId [options] [file name<s>]
+
+Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+
+Options:
+ -o FileName, --output FileName
+ File will be created to store the output content.
+ -e EfiFileName
+ EFI PE32 image files.
+ -ec EfiFileName
+ EFI PE32 image files and will be compressed.
+ -b BinFileName
+ Legacy binary files.
+ -l ClassCode
+ Hex ClassCode in the PCI data structure header.
+ -r Rev Hex Revision in the PCI data structure header.
+ -n Not to automatically set the LAST bit in the last file.
+ -f VendorId
+ Hex PCI Vendor ID for the device OpROM, must be specified
+ -i DeviceId
+ One or more hex PCI Device IDs for the device OpROM, must be specified
+ -p, --pci23
+ Default layout meets PCI 3.0 specifications
+ specifying this flag will for a PCI 2.3 layout.
+ -d, --dump
+ Dump the headers of an existing option ROM image.
+ -v, --verbose
+ Turn on verbose output with informational messages.
+ --version Show program's version number and exit.
+ -h, --help
+ Show this help message and exit.
+ -q, --quiet
+ Disable all messages except FATAL ERRORS.
+ --debug [#,0-9]
+ Enable debug messages at level #.
+```
+Complete version of the manual for `EfiRom` is placed at https://github.com/tianocore/edk2/blob/master/BaseTools/UserManuals/EfiRom_Utility_Man_Page.rtf
+
+If you are interested in the source code: https://github.com/tianocore/edk2/tree/master/BaseTools/Source/C/EfiRom
+
+With this tool it is possible to:
+- dump Option ROM images
+- create Option ROM images from EFI drivers and/or Legacy binary images
+
+Also take a look at tianocore docs:
+- https://edk2-docs.gitbook.io/edk-ii-basetools-user-guides/efirom
+- https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/18_pci_driver_design_guidelines/readme.7/1871_efirom_utility
+
+# ipxe rom
+
+Preboot eXecution Environment (PXE) is a standard for booting to an image received via network (https://en.wikipedia.org/wiki/Preboot_Execution_Environment).
+
+To know how to use particular PCI network card for PXE boot, BIOS needs to know some network card internals. But BIOS is not an OS, it is not possible to have drivers for every PCI network card in it. Therefore this problem is solved via OptionROM firmware. PCI network card contains all the necessary code for PXE boot in itself. But not every card have such firmware in itself. In this case you can utilize iPXE project.
+
+iPXE is the open source network boot firmware (https://ipxe.org/). It provides a full PXE implementation enhanced with some additional features. It support various PCI network cards https://ipxe.org/appnote/hardware_drivers.
+
+iPXE can be compiled as EFI application or as EFI/Legacy OptionROM. You can read more about build targets at https://ipxe.org/appnote/buildtargets.
+
+Let's download iPXE:
+```
+git clone git://git.ipxe.org/ipxe.git
+cd ipxe/src
+```
+
+Now build some images:
+```
+$ sudo apt-get install liblzma-dev
+$ make bin-x86_64-efi/ipxe.efi # EFI app with all devices
+$ make bin-x86_64-efi/8086100e.efirom # EFI ROM vendev: 8086:100e
+$ make bin/8086100e.rom # Legacy ROM vendev: 8086:100e
+```
+
+You can execute `ipxe.efi` directly from the UEFI shell. It is a simple UEFI application similar to the ones that we create in this series.
+
+Look at the https://github.com/ipxe/ipxe/blob/master/src/image/efi_image.c for source code investigation.
+
+`8086100e.rom` is a Legacy code image PCI Option ROM for `8086:100e` network card
+
+`8086100e.efirom` is an UEFI code image PCI Option ROM for `8086:100e` network card
+
+If you inspect the OptionROM images with `hexdump`, you'll see standard `AA55` and `PCIR` signatures in them.
+
+```
+$ hexdump bin/8086100e.rom -C -n 64
+00000000 55 aa 86 e9 a2 00 30 00 00 00 00 00 00 00 00 00 |U.....0.........|
+00000010 9c 00 00 00 00 00 84 00 1c 00 40 00 50 43 49 52 |..........@.PCIR|
+00000020 86 80 0e 10 bf 04 1c 00 03 00 00 02 86 00 01 00 |................|
+00000030 00 80 07 00 00 00 00 00 8d b4 00 00 8d b4 00 00 |................|
+00000040
+$ hexdump bin-x86_64-efi/8086100e.efirom -C -n 64
+00000000 55 aa d0 00 f1 0e 00 00 0b 00 64 86 01 00 00 00 |U.........d.....|
+00000010 00 00 00 00 00 00 38 00 1c 00 00 00 50 43 49 52 |......8.....PCIR|
+00000020 86 80 0e 10 00 00 18 00 00 00 00 02 d0 00 00 00 |................|
+00000030 03 80 00 00 87 00 00 00 0d 9e 01 00 00 d2 02 00 |................|
+00000040
+```
+
+We can even use `EfiRom` on them:
+```
+$ EfiRom -d bin/8086100e.rom
+Image 1 -- Offset 0x0
+ ROM header contents
+ Signature 0xAA55
+ PCIR offset 0x001C
+ Signature PCIR
+ Vendor ID 0x8086
+ Device ID 0x100E
+ Length 0x001C
+ Revision 0x0003
+ DeviceListOffset 0x4BF
+ Device list contents
+ 0x100E
+ Class Code 0x020000
+ Image size 0x10C00
+ Code revision: 0x0001
+ MaxRuntimeImageLength 0x07
+ ConfigUtilityCodeHeaderOffset 0x00
+ DMTFCLPEntryPointOffset 0x00
+ Indicator 0x80 (last image)
+ Code type 0x00
+```
+If we execute `EfiRom` on a `bin-x86_64-efi/8086100e.efirom`, we would get an error:
+```
+$ EfiRom -d bin-x86_64-efi/8086100e.efirom
+EfiRom: ERROR 1002: No PciRom input file
+ No *.rom input file
+```
+The problem is that we `EfiRom` understands only files with `.rom` extension, so change it and use `EfiRom` again:
+```
+$ cp bin-x86_64-efi/8086100e.efirom bin-x86_64-efi/8086100e.rom
+$ EfiRom -d bin-x86_64-efi/8086100e.rom
+Image 1 -- Offset 0x0
+ ROM header contents
+ Signature 0xAA55
+ PCIR offset 0x001C
+ Signature PCIR
+ Vendor ID 0x8086
+ Device ID 0x100E
+ Length 0x0018
+ Revision 0x0000
+ DeviceListOffset 0x00
+ Class Code 0x020000
+ Image size 0x1A000
+ Code revision: 0x0000
+ MaxRuntimeImageLength 0x00
+ ConfigUtilityCodeHeaderOffset 0x87
+ DMTFCLPEntryPointOffset 0x00
+ Indicator 0x80 (last image)
+ Code type 0x03 (EFI image)
+ EFI ROM header contents
+ EFI Signature 0x0EF1
+ Compression Type 0x0001 (compressed)
+ Machine type 0x8664 (X64)
+ Subsystem 0x000B (EFI boot service driver)
+ EFI image offset 0x0038 (@0x38)
+```
+
+EfiRom can't currently combine Option ROM from the EFI ROM images. But it can use EFI PE32 image files as a source for EFI ROM images in the resulting Option ROM. So we have to compile another target:
+```
+$ make bin-x86_64-efi/8086100e.efidrv
+```
+Now we can create combined OptionROM image with both Legacy and EFI ROMs.
+```
+$ EfiRom -f 0x8086 -i 0x100e -b bin/8086100e.rom -ec bin-x86_64-efi/8086100e.efidrv -o bin/8086100e_optionrom.rom
+$ EfiRom -d bin/8086100e_optionrom.rom
+Image 1 -- Offset 0x0
+ ROM header contents
+ Signature 0xAA55
+ PCIR offset 0x001C
+ Signature PCIR
+ Vendor ID 0x8086
+ Device ID 0x100E
+ Length 0x001C
+ Revision 0x0003
+ DeviceListOffset 0x4BF
+ Device list contents
+ 0x100E
+ Class Code 0x020000
+ Image size 0x10C00
+ Code revision: 0x0001
+ MaxRuntimeImageLength 0x07
+ ConfigUtilityCodeHeaderOffset 0x00
+ DMTFCLPEntryPointOffset 0x00
+ Indicator 0x00
+ Code type 0x00
+Image 2 -- Offset 0x10C00
+ ROM header contents
+ Signature 0xAA55
+ PCIR offset 0x001C
+ Signature PCIR
+ Vendor ID 0x8086
+ Device ID 0x100E
+ Length 0x001C
+ Revision 0x0003
+ DeviceListOffset 0x00
+ Class Code 0x000000
+ Image size 0x1A000
+ Code revision: 0x0000
+ MaxRuntimeImageLength 0x00
+ ConfigUtilityCodeHeaderOffset 0x00
+ DMTFCLPEntryPointOffset 0x00
+ Indicator 0x80 (last image)
+ Code type 0x03 (EFI image)
+ EFI ROM header contents
+ EFI Signature 0x0EF1
+ Compression Type 0x0001 (compressed)
+ Machine type 0x8664 (X64)
+ Subsystem 0x000B (EFI boot service driver)
+ EFI image offset 0x0038 (@0x10C38)
+```
+
+# VGA rom
+
+SeaBIOS is an open-source legacy BIOS implementation that implements the standard BIOS calling interfaces that a typical x86 proprietary BIOS implements (https://github.com/coreboot/seabios).
+SeaVGABIOS is a sub-project of the SeaBIOS project - it is an open source implementation of a 16bit X86 VGA BIOS
+(https://github.com/coreboot/seabios/blob/master/docs/SeaVGABIOS.md). In other words it builds a Legacy Option ROM for a PCI graphic device.
+
+SeaBIOS uses Kconfig system for the build configuration. Main options for the VGA BIOS are placed under https://github.com/coreboot/seabios/blob/master/vgasrc/Kconfig In this file you can see that one of the options is a OptionROM with a Vendor/Device pair as `1234:1111`. Exactly the one that we saw at QEMU:
+```
+ config VGA_VID
+ depends on VGA_PCI
+ hex
+ prompt "PCI Vendor ID" if OVERRIDE_PCI_ID
+ default 0x1013 if VGA_CIRRUS
+ default 0x1002 if VGA_ATI
+ default 0x1234 if VGA_BOCHS_STDVGA
+ default 0x15ad if VGA_BOCHS_VMWARE
+ default 0x1b36 if VGA_BOCHS_QXL
+ default 0x1af4 if VGA_BOCHS_VIRTIO
+ default 0x100b if VGA_GEODEGX2
+ default 0x1022 if VGA_GEODELX
+ default 0x1234 if DISPLAY_BOCHS <--------------
+ default 0x0000
+ help
+ Vendor ID for the PCI ROM
+
+ config VGA_DID
+ depends on VGA_PCI
+ hex
+ prompt "PCI Vendor ID" if OVERRIDE_PCI_ID
+ default 0x00b8 if VGA_CIRRUS
+ default 0x5159 if VGA_ATI
+ default 0x1111 if VGA_BOCHS_STDVGA
+ default 0x0405 if VGA_BOCHS_VMWARE
+ default 0x0100 if VGA_BOCHS_QXL
+ default 0x1050 if VGA_BOCHS_VIRTIO
+ default 0x0030 if VGA_GEODEGX2
+ default 0x2081 if VGA_GEODELX
+ default 0x1111 if DISPLAY_BOCHS <---------------
+ default 0x0000
+ help
+ Device ID for the PCI ROM
+```
+If you wonder what is `DISPLAY_BOCHS`, here is a help for this option:
+```
+ config DISPLAY_BOCHS
+ depends on QEMU
+ bool "qemu bochs-display support"
+ select VGA_EMULATE_TEXT
+ help
+ Build support for the qemu bochs-display device, which
+ is basically qemu stdvga without the legacy vga
+ emulation, supporting only 16+32 bpp VESA video modes
+ in a linear framebuffer. So this uses cbvga text mode
+ emulation.
+
+ The bochs-display device is available in qemu
+ v3.0+. The vgabios works with the qemu stdvga too (use
+ "qemu -device VGA,romfile=/path/to/vgabios.bin")".
+```
+
+Let's build this SeaBIOS VGA image. Install necessary packages, download SeaBIOS source and perfrorm build configuration:
+```
+$ sudo apt-get install python
+$ git clone https://github.com/coreboot/seabios.git
+$ cd seabios
+$ make menuconfig
+```
+In a menuconfig select:
+```
+VGA ROM ---> VGA Hardware Type (qemu bochs-display support)
+```
+After that execute:
+```
+$ make
+```
+
+After the build resulting VGA Option ROM would be at path `out/vgabios.bin`. As `EfiRom` expects ROM files to have a `*.rom` extension, create a copy of a file with such extension. After that execute `dump` command on this file:
+```
+$ cp out/vgabios.bin out/vgabios.rom
+$ EfiRom -d out/vgabios.rom
+Image 1 -- Offset 0x0
+ ROM header contents
+ Signature 0xAA55
+ PCIR offset 0x6E00
+ Signature PCIR
+ Vendor ID 0x1234
+ Device ID 0x1111
+ Length 0x0018
+ Revision 0x0000
+ DeviceListOffset 0x00
+ Class Code 0x030000
+ Image size 0x7000
+ Code revision: 0x0001
+ MaxRuntimeImageLength 0x00
+ ConfigUtilityCodeHeaderOffset 0x9066
+ DMTFCLPEntryPointOffset 0x9066
+ Indicator 0x80 (last image)
+ Code type 0x00
+```
+This is the info similar to the one that we saw with our utility on a working QEMU system. You can see that PCI vendor/device pair is set to `1234:1111`.
+
+
+# How QEMU gets these OptionROMs
+
+The main Makefile in QEMU responsible for OptionROM image creation is https://github.com/qemu/qemu/blob/master/roms/Makefile
+
+In this Makefile you can see how:
+- `seavgabios-%` target is used for the creation of a Legacy SeaVGABIOS OptionROM
+- `efi-rom-%` target is used for the creation of an OptionROM with both Legacy and UEFI iPXE code images (it even uses `EfiRom` utility from edk2 for this purpose)
+
+# Code images for different CPU architectures in OptionROM image
+
+In the previous lesson I've mentioned that PCI device can have various code images for different CPU architectures.
+
+Check out this guide as an example https://www.workofard.com/2020/12/aarch64-option-roms-for-amd-gpus/
+
+It explains how to add the AMD AARCH64 Gop Driver as another Code Image to the PCI graphic card OptionROM to make the graphic card work at boot time in AArch64 systems.
+
+It uses `flashrom` utility to download initial PCI card Option ROM firmware and with a help of `EfiRom` adds AMD EFI graphic driver for AArch64 to the list of images in this OptionROM.
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
+
diff --git a/Lessons/Lesson_35/README.md b/Lessons/Lesson_35/README.md
new file mode 100644
index 0000000..def1314
--- /dev/null
+++ b/Lessons/Lesson_35/README.md
@@ -0,0 +1,383 @@
+If you'll search through ShellPkg library (https://github.com/tianocore/edk2/tree/master/ShellPkg/Library) you can notice that there is a folder `UefiShellAcpiViewCommandLib` (https://github.com/tianocore/edk2/tree/master/ShellPkg/Library/UefiShellAcpiViewCommandLib).
+This folder provides a library for the support of in-shell `acpiview` command. If you check the INF file, you'll see
+https://github.com/tianocore/edk2/blob/master/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf:
+```
+# Provides Shell 'acpiview' command functions
+```
+But if you try to execute `acpiview` in our current OVMF build, you'll notice that this command is not recognized:
+```
+FS0:\> acpiview
+'acpiview' is not recognized as an internal or external command, operable program, or script file.
+```
+We have 3 ways to use this 'acpiview' command functionality:
+- compile `acpiview` as a separate app and run it as an ordinary UEFI shell application
+- compile shell with 'acpiview' command in itself and run it under OVMF
+- update OVMF image with a shell that actually includes 'acpiview' command in itself
+
+# Compile `acpiview` as a separate app
+
+I guess it is the most easy way.
+
+It is possible to perform such thing with a help of https://github.com/tianocore/edk2/tree/master/ShellPkg/Application/AcpiViewApp
+
+If you look at the source file, you'll see that it is pretty simple, the main function just makes a library call to `ShellCommandRunAcpiView` function:
+```
+EFI_STATUS
+EFIAPI
+AcpiViewAppMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return ShellCommandRunAcpiView (gImageHandle, SystemTable);
+}
+```
+
+To build this application issue:
+```
+build --platform=ShellPkg/ShellPkg.dsc --module=ShellPkg/Application/AcpiViewApp/AcpiViewApp.inf --arch=X64 --buildtarget=RELEASE --tagname=GCC5
+```
+
+Copy image to the QEMU shared folder:
+```
+cp Build/Shell/RELEASE_GCC5/X64/AcpiViewApp.efi ~/UEFI_disk/
+```
+
+You can see application help with a:
+```
+FS0:\> AcpiViewApp.efi -?
+Display ACPI Table information.
+
+ACPIVIEWAPP.EFI [[-?] | [[[[-l] | [-s AcpiTable [-d]]] [-q] [-h]] [-r Spec]]]
+
+
+ -l - Display list of installed ACPI Tables.
+ -s - Display only the specified AcpiTable type and only support single
+ invocation option.
+ AcpiTable : The required ACPI Table type.
+ -d - Generate a binary file dump of the specified AcpiTable.
+ -q - Quiet. Suppress errors and warnings. Disables consistency checks.
+ -h - Enable colour highlighting.
+ -r - Validate that all required ACPI tables are installed
+ Spec : Specification to validate against.
+ For Arm, the possible values are:
+ 0 - Server Base Boot Requirements v1.0
+ 1 - Server Base Boot Requirements v1.1
+ 2 - Server Base Boot Requirements v1.2
+ -? - Show help.
+
+
+ This program is provided to allow examination of ACPI table values from the
+ UEFI Shell. This can help with investigations, especially at that stage
+ where the tables are not enabling an OS to boot.
+ The program is not exhaustive, and only encapsulates detailed knowledge of a
+ limited number of table types.
+
+ Default behaviour is to display the content of all tables installed.
+ 'Known' table types (listed in NOTES below) will be parsed and displayed
+ with descriptions and field values. Where appropriate a degree of
+ consistency checking is done and errors may be reported in the output.
+ Other table types will be displayed as an array of Hexadecimal bytes.
+
+ To facilitate debugging, the -s and -d options can be used to generate a
+ binary file image of a table that can be copied elsewhere for investigation
+ using tools such as those provided by acpica.org. This is especially
+ relevant for AML type tables like DSDT and SSDT.
+
+NOTES:
+ 1. The AcpiTable parameter can match any installed table type.
+ Tables without specific handling will be displayed as a raw hex dump (or
+ dumped to a file if -d is used).
+ 2. -s option supports to display the specified AcpiTable type that is present
+ in the system. For normal type AcpiTable, it would display the data of the
+ AcpiTable and AcpiTable header. The following type may contain header type
+ other than AcpiTable header. The actual header can refer to the ACPI spec
+ 6.3
+ Extra A. Particular types:
+ APIC - Multiple APIC Description Table (MADT)
+ BGRT - Boot Graphics Resource Table
+ DBG2 - Debug Port Table 2
+ DSDT - Differentiated System Description Table
+ FACP - Fixed ACPI Description Table (FADT)
+ GTDT - Generic Timer Description Table
+ IORT - IO Remapping Table
+ MCFG - Memory Mapped Config Space Base Address Description Table
+ PPTT - Processor Properties Topology Table
+ RSDP - Root System Description Pointer
+ SLIT - System Locality Information Table
+ SPCR - Serial Port Console Redirection Table
+ SRAT - System Resource Affinity Table
+ SSDT - Secondary SystemDescription Table
+ XSDT - Extended System Description Table
+
+
+
+EXAMPLES:
+ * To display a list of the installed table types:
+ fs0:\> acpiviewapp.efi -l
+
+ * To parse and display a specific table type:
+ fs0:\> acpiviewapp.efi -s GTDT
+
+ * To save a binary dump of the contents of a table to a file
+ in the current working directory:
+ fs0:\> acpiviewapp.efi -s DSDT -d
+
+ * To display contents of all ACPI tables:
+ fs0:\> acpiviewapp.efi
+
+ * To check if all Server Base Boot Requirements (SBBR) v1.2 mandatory
+ ACPI tables are installed (Arm only):
+ fs0:\> acpiviewapp.efi -r 2
+```
+
+With this program you can list ACPI tables in system:
+```
+FS0:\> AcpiViewApp.efi -l
+
+Installed Table(s):
+ 1. RSDP
+ 2. XSDT
+ 3. FACP
+ 4. FACS
+ 5. DSDT
+ 6. APIC
+ 7. HPET
+ 8. BGRT
+```
+
+Show the content of any table:
+```
+FS0:\> AcpiViewApp.efi -s BGRT
+
+
+ --------------- BGRT Table ---------------
+
+Address : 0x7B77000
+Length : 56
+
+00000000 : 42 47 52 54 38 00 00 00 - 01 C5 49 4E 54 45 4C 20 BGRT8.....INTEL
+00000010 : 45 44 4B 32 20 20 20 20 - 02 00 00 00 20 20 20 20 EDK2 ....
+00000020 : 13 00 00 01 01 00 01 00 - 18 30 8B 06 00 00 00 00 .........0......
+00000030 : 2F 01 00 00 0F 01 00 00 /.......
+
+Table Checksum : OK
+
+BGRT :
+ Signature : BGRT
+ Length : 56
+ Revision : 1
+ Checksum : 0xC5
+ Oem ID : INTEL
+ Oem Table ID : EDK2
+ Oem Revision : 0x2
+ Creator ID :
+ Creator Revision : 0x1000013
+ Version : 0x1
+ Status : 0x1
+ Image Type : 0x0
+ Image Address : 0x68B3018
+ Image Offset X : 303
+ Image Offset Y : 271
+
+Table Statistics:
+ 0 Error(s)
+ 0 Warning(s)
+```
+
+Or dump any ACPI table:
+```
+FS0:\> acpiview -s APIC -d
+Dumping ACPI table to : .\APIC0000.bin ... DONE.
+```
+You can disassemble this image with `iasl -d <file>` like we did earlier.
+
+
+# Compile shell with 'acpiview' command in itself and run it under OVMF
+
+This case is a little bit crazy, we would be running a shell applicaion inside the shell application.
+
+I guess this is not the usual case, but it will help you to know how to compile the shell image that you can actually use in your projects.
+
+If you'll look at the https://github.com/tianocore/edk2/blob/master/ShellPkg/ShellPkg.dsc you'll see that if you build `ShellPkg`, you'll actually build two versions of the `Shell.inf`:
+- one would have general commands
+- another one would have all the commands
+```
+ShellPkg/Application/Shell/Shell.inf {
+ <PcdsFixedAtBuild>
+ gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
+ <LibraryClasses>
+ NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf
+fndef $(NO_SHELL_PROFILES)
+ NULL|ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf
+ndif #$(NO_SHELL_PROFILES)
+}
+
+#
+# Build a second version of the shell with all commands integrated
+#
+ShellPkg/Application/Shell/Shell.inf {
+ <Defines>
+ FILE_GUID = EA4BB293-2D7F-4456-A681-1F22F42CD0BC
+ <PcdsFixedAtBuild>
+ gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
+ <LibraryClasses>
+ NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf <------- acpiview is present in this Shell version
+}
+```
+
+In case you wonder how `UefiShellAcpiViewCommandLib.inf` registers new command take a look at its sources:
+
+https://github.com/tianocore/edk2/blob/master/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf
+```
+[Defines]
+ INF_VERSION = 0x00010019
+ BASE_NAME = UefiShellAcpiViewCommandLib
+ FILE_GUID = FB5B305E-84F5-461F-940D-82D345757AFA
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = AcpiViewCommandLib|UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = UefiShellAcpiViewCommandLibConstructor
+ DESTRUCTOR = UefiShellAcpiViewCommandLibDestructor
+
+ ...
+```
+https://github.com/tianocore/edk2/blob/master/ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.c
+```
+EFI_STATUS
+EFIAPI
+UefiShellAcpiViewCommandLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ ...
+ // Install our Shell command handler
+ ShellCommandRegisterCommandName (
+ L"acpiview",
+ ShellCommandRunAcpiView,
+ ShellCommandGetManFileNameAcpiView,
+ 0,
+ L"acpiview",
+ TRUE,
+ gShellAcpiViewHiiHandle,
+ STRING_TOKEN (STR_GET_HELP_ACPIVIEW)
+ );
+
+ return EFI_SUCCESS;
+}
+```
+It doesn't look too scary, so you can even try to add your command to the shell. Maybe will try that in later lessons.
+
+Now execute this command to build the Shell application:
+```
+build --platform=ShellPkg/ShellPkg.dsc --module=ShellPkg/Application/Shell/Shell.inf --arch=X64 --buildtarget=RELEASE --tagname=GCC5
+```
+
+After the build there would be two files in the build folder:
+```
+$ ls Build/Shell/RELEASE_GCC5/X64/Shell*.efi
+Build/Shell/RELEASE_GCC5/X64/Shell_7C04A583-9E3E-4f1c-AD65-E05268D0B4D1.efi
+Build/Shell/RELEASE_GCC5/X64/Shell_EA4BB293-2D7F-4456-A681-1F22F42CD0BC.efi
+```
+
+If you look closely to the code from the `ShellPkg/ShellPkg.dsc` that I've pasted earlier, you can notice that the image that we need is an image with a `EA4BB293-2D7F-4456-A681-1F22F42CD0BC` guid.
+
+Copy it to the QEMU shared folder:
+```
+$ cp Build/Shell/RELEASE_GCC5/X64/Shell_EA4BB293-2D7F-4456-A681-1F22F42CD0BC.efi ~/UEFI_disk/
+```
+In your default shell there wouldn't be any `acpiview` command, but when as you'll move to the `Shell_EA4BB293-2D7F-4456-A681-1F22F42CD0BC.efi` this `acpiview` command would became present in the shell.
+```
+FS0:\> acpiview -l
+'acpiview' is not recognized as an internal or external command, operable program, or script file.
+FS0:\> Shell_EA4BB293-2D7F-4456-A681-1F22F42CD0BC.efi
+UEFI Interactive Shell v2.2
+EDK II
+UEFI v2.70 (EDK II, 0x00010000)
+Mapping table
+ FS0: Alias(s):HD0a1:;BLK1:
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
+ BLK0: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ BLK2: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+Press ESC in 4 seconds to skip startup.nsh or any other key to continue.
+FS0:\> acpiview -l
+
+Installed Table(s):
+ 1. RSDP
+ 2. XSDT
+ 3. FACP
+ 4. FACS
+ 5. DSDT
+ 6. APIC
+ 7. HPET
+ 8. BGRT
+```
+
+# Update OVMF image with a shell that actually includes 'acpiview' command in itself
+
+Correct `OvmfPkg/OvmfPkgX64.dsc`. You'll need to add `UefiShellAcpiViewCommandLib.inf` to the `Shell.inf` library classes:
+```
+[Components]
+ ...
+ ShellPkg/Application/Shell/Shell.inf {
+ <LibraryClasses>
+ ShellCommandLib|ShellPkg/Library/UefiShellCommandLib/UefiShellCommandLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel2CommandsLib/UefiShellLevel2CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel1CommandsLib/UefiShellLevel1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellLevel3CommandsLib/UefiShellLevel3CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellDriver1CommandsLib/UefiShellDriver1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellDebug1CommandsLib/UefiShellDebug1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellInstall1CommandsLib/UefiShellInstall1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellNetwork1CommandsLib/UefiShellNetwork1CommandsLib.inf
+ NULL|ShellPkg/Library/UefiShellAcpiViewCommandLib/UefiShellAcpiViewCommandLib.inf <-----------
+!if $(NETWORK_IP6_ENABLE) == TRUE
+ NULL|ShellPkg/Library/UefiShellNetwork2CommandsLib/UefiShellNetwork2CommandsLib.inf
+!endif
+ HandleParsingLib|ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
+
+ <PcdsFixedAtBuild>
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
+ gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
+ gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000
+ }
+```
+
+Rebuild OVMF:
+```
+build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5
+```
+
+You can test that this OVMF image has a shell that includes `acpiview` command in itself:
+```
+FS0:\> acpiview -l
+
+Installed Table(s):
+ 1. RSDP
+ 2. XSDT
+ 3. FACP
+ 4. FACS
+ 5. DSDT
+ 6. APIC
+ 7. HPET
+ 8. BGRT
+```
+