<div class="xblock xblock-public_view xblock-public_view-vertical" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-init="VerticalStudentView" data-runtime-class="LmsRuntime" data-runtime-version="1" data-block-type="vertical" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@vertical+block@df435f15924b4cf1a52c31fd12314125" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="vert-mod">
<div class="vert vert-0" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@5b11aaaa531649f3abd0f4471fa06ffd">
<div class="xblock xblock-public_view xblock-public_view-markdown" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="markdown" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@5b11aaaa531649f3abd0f4471fa06ffd" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="markdown_xblock"><p>In Practice #1 we learned how to compile and run UEFI firmware for QEMU (OVMF). In this section we will learn couple debugging methods:</p>
<ul>
<li>Debugging using EDKII logging features</li>
<li>Debugging using EDKII debug code statement</li>
<li>Debugging using GDB remote target connecting to EDK II Debug Agent</li>
<li>Debugging using GDB remote target connecting to QEMU</li>
</ul>
<h1>Enabling debugging at build time</h1>
<p>To created debug build target use <code>-b DEBUG</code> parameter:</p>
<div class="codehilite">
<pre><span></span><code>build -p OvmfPkg/OvmfPkgX64.dsc -b DEBUG -t GCC5 -n <span class="k">$(</span>nproc<span class="k">)</span> -a X64 all
</code></pre>
</div>
<h1>Add DebugLib to DSC file</h1>
<p>If you were creating a completely new platform, you would need to add DebugLib to the platform's DSC file in order for it to support debugging. However, since we are using the existing <code>OvmfPkg/OvmfPkgX64.dsc</code> let's check how DebugLib was added:</p>
<div class="codehilite">
<pre><span></span><code>grep DebugLib OvmfPkg/OvmfPkgX64.dsc -C1
</code></pre>
</div>
<p>Output should look as follows:</p>
<div class="codehilite">
<pre><span></span><code>!ifdef <span class="k">$(</span>DEBUG_ON_SERIAL_PORT<span class="k">)</span>
DebugLib<span class="p">|</span>MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
!else
DebugLib<span class="p">|</span>OvmfPkg/Library/PlatformDebugLibIoPort/PlatformRomDebugLibIoPort.inf
!endif
--
!ifdef <span class="k">$(</span>DEBUG_ON_SERIAL_PORT<span class="k">)</span>
DebugLib<span class="p">|</span>MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
!else
DebugLib<span class="p">|</span>OvmfPkg/Library/PlatformDebugLibIoPort/PlatformDebugLibIoPort.inf
!endif
--
...
</code></pre>
</div>
<p>As we can see there are multiple libraries available in our platform description file. If we look inside the DSC file we will find that <code>BaseDebugLibSerialPort</code> is used when <code>DEBUG_ON_SERIAL_PORT</code> is defined. We can define it at build time using <code>-D DEBUG_ON_SERIAL_PORT</code>, but before we do that let's see what happens if <code>DEBUG_ON_SERIAL_PORT</code> is not defined. In the DSC we see that <code>PlatformRomDebugLibIoPort</code> or <code>PlatformDebugLibIoPort</code> are used. First just in SEC libraries and second with other UEFI phases libraries.</p>
<h2>Exercise #1: How to see output PlatformRomDebugLibIoPort functions?</h2>
<ol>
<li>We can look for PlatformRomDebugLibIoPort.inf</li>
<li>In section Sources we can find DebugLib.c</li>
<li>Inside we can find the following functions calls <code>DebugPrint->DebugVPrint->DebugPrintMarker</code></li>
<li>The last thing <code>DebugPrintMarker</code> performs is <code>IoWriteFifo8</code> to some PCD (Platform Configuration Databse) - PCD in this case is decoded using <code>PcdGet16()</code> function. Please note the parameter of that function as we will refer to it in next exercise as "I/O Debug Port".</li>
<li>Please find "I/O Debug Port" in OvmfPkg.dec declaration file - the default file for PCD definitions.</li>
<li>Knowing that hex value, let's run QEMU. Do not forget to replace <code><I/O Debug Port></code> with the correct value, and see if we can get any debug prints from SEC phase in our debug.log:</li>
</ol>
<div class="codehilite">
<pre><span></span><code>qemu-system-x86_64 -nographic -bios Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd -chardev file,path<span class="o">=</span>debug.log,id<span class="o">=</span>edk2-debug -device isa-debugcon,iobase<span class="o">=</span><I/O Debug Port>,chardev<span class="o">=</span>edk2-debug -net none
</code></pre>
</div>
<p>At a basic level, you can think of PCDs like global variables that are set in configuration files, and which can be looked up by code at runtime via GetPcd(). This allows code to be more generic and perform correctly, regardless of which architecture it is compiled for. To learn more about PCDs you can read the <a href="https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/edkii-platform-config-database-entries-paper.pdf">Intel white paper</a>.</p>
</div>
</div>
</div>
<div class="vert vert-1" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@ddfbe01acff749c49a61132d7860e9a7">
<div class="xblock xblock-public_view xblock-public_view-done" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="done" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@ddfbe01acff749c49a61132d7860e9a7" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="True">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Completion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
<div class="vert vert-2" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@809f05f5dfe14b99ab47ff8dedeb5851">
<div class="xblock xblock-public_view xblock-public_view-discussion" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="discussion" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@809f05f5dfe14b99ab47ff8dedeb5851" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Discussion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
</div>
<script type="text/javascript">
(function (require) {
require(['/static/js/dateutil_factory.be68acdff619.js?raw'], function () {
require(['js/dateutil_factory'], function (DateUtilFactory) {
DateUtilFactory.transform('.localized-datetime');
});
});
}).call(this, require || RequireJS.require);
</script>
<script>
function emit_event(message) {
parent.postMessage(message, '*');
}
</script>
</div>
<div class="xblock xblock-public_view xblock-public_view-vertical" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-init="VerticalStudentView" data-runtime-class="LmsRuntime" data-runtime-version="1" data-block-type="vertical" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@vertical+block@3f7de0b5c78c4e0ebbe336219bbd7daa" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="vert-mod">
<div class="vert vert-0" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@60158b87c73d4debb3db71fda729c03c">
<div class="xblock xblock-public_view xblock-public_view-markdown" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="markdown" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@60158b87c73d4debb3db71fda729c03c" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="markdown_xblock"><h1>Debugging by printing</h1>
<p>This is one of the most easiest, popular and efficient way of debugging firmware.</p>
<h2>Exercise #2: Let's add debug log to SEC module</h2>
<ol>
<li>One of the first lines that we saw in debug log from Exercise #1 should be <code>SecCoreStartupWithStack</code> - please find the C file where this string occurs</li>
<li>Add another debug message right after the above message</li>
<li>Recompile</li>
<li>Dump the logs as in Exercise #1 and make sure your modification is present in the log</li>
</ol>
</div>
</div>
</div>
<div class="vert vert-1" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@0e7f76cc3be84e7facf63ede9fb85436">
<div class="xblock xblock-public_view xblock-public_view-done" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="done" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@0e7f76cc3be84e7facf63ede9fb85436" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="True">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Completion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
<div class="vert vert-2" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@a1d66407d65747ae94e2aa533836d166">
<div class="xblock xblock-public_view xblock-public_view-discussion" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="discussion" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@a1d66407d65747ae94e2aa533836d166" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Discussion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
</div>
<script type="text/javascript">
(function (require) {
require(['/static/js/dateutil_factory.be68acdff619.js?raw'], function () {
require(['js/dateutil_factory'], function (DateUtilFactory) {
DateUtilFactory.transform('.localized-datetime');
});
});
}).call(this, require || RequireJS.require);
</script>
<script>
function emit_event(message) {
parent.postMessage(message, '*');
}
</script>
</div>
<div class="xblock xblock-public_view xblock-public_view-vertical" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-init="VerticalStudentView" data-runtime-class="LmsRuntime" data-runtime-version="1" data-block-type="vertical" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@vertical+block@5cde3f53f21c4b838c823391f70ecd77" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="vert-mod">
<div class="vert vert-0" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@c885e4bf503e4cc7a2cd375f6232084e">
<div class="xblock xblock-public_view xblock-public_view-markdown" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="markdown" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@c885e4bf503e4cc7a2cd375f6232084e" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="markdown_xblock"><p>Let's use QEMU feature to connect GDB and debug EDKII code.</p>
<p>First let's run QEMU with GDB server listnening and waiting for connection:</p>
<pre><code>qemu-system-x86_64 -nographic -bios Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd -chardev file,path=debug.log,id=edk2-debug -device isa-debugcon,iobase=0x402,chardev=edk2-debug -net none -s -S
</code></pre>
<h2>Exercise #3: Debugging EFI files</h2>
<ul>
<li>Run gdb</li>
</ul>
<div class="codehilite">
<pre><span></span><code>user@user-OST-VM:~/edk2$ gdb --quiet <span class="o">(</span>gdb<span class="o">)</span>
</code></pre>
</div>
<ul>
<li>Load <code>SecMain.debug</code> file to obtain addresses of <code>.text</code> and <code>.data</code> sections</li>
</ul>
<div class="codehilite">
<pre><span></span><code><span class="o">(</span>gdb<span class="o">)</span> file Build/OvmfX64/DEBUG_GCC5/X64/SecMain.debug
Reading symbols from Build/OvmfX64/DEBUG_GCC5/X64/SecMain.debug...
<span class="o">(</span>gdb<span class="o">)</span> info file
Symbols from <span class="s2">"/home/user/edk2/Build/OvmfX64/DEBUG_GCC5/X64/SecMain.debug"</span>.
Local <span class="nb">exec</span> file:
<span class="sb">`</span>/home/user/edk2/Build/OvmfX64/DEBUG_GCC5/X64/SecMain.debug<span class="err">'</span>, file <span class="nb">type</span> elf64-x86-64.
Entry point: 0x64f0
0x0000000000000240 - 0x00000000000088fe is .text
0x0000000000008900 - 0x0000000000009a60 is .data
0x0000000000009a80 - 0x0000000000009a80 is .eh_frame
</code></pre>
</div>
<ul>
<li><p>This gives us the offset for the .text section of the debug ELF file (0x240), which we will call <code><SECMAIN_TEXT_OFFSET></code>, and the offset for the .data section (0x8900), which we will call <code><SECMAIN_DATA_OFFSET></code> and use in a command below. These values will change as you change debug and build options throughout the class. </p></li>
<li><p>You may now discard the symbol file, because we will need to reload it with correct offsets</p></li>
</ul>
<div class="codehilite">
<pre><span></span><code><span class="o">(</span>gdb<span class="o">)</span> symbol-file
Discard symbol table from <span class="sb">`</span>/home/user/edk2/Build/OvmfX64/DEBUG_GCC5/X64/SecMain.debug<span class="err">'</span>? <span class="o">(</span>y or n<span class="o">)</span> y
</code></pre>
</div>
<ul>
<li>In other terminal look in <code>Build/OvmfX64/DEBUG_GCC5/Ovmf.map</code> for base address of <code>SecMain</code></li>
</ul>
<div class="codehilite">
<pre><span></span><code>user@user-OST-VM:~/edk2$ grep SecMain Build/OvmfX64/DEBUG_GCC5/Ovmf.map
SecMain <span class="o">(</span>Fixed Flash Address, <span class="nv">BaseAddress</span><span class="o">=</span><SECMAIN_BASEADDRESS>, <span class="nv">EntryPoint</span><span class="o">=</span>0x00fffd2584, <span class="nv">Type</span><span class="o">=</span>PE<span class="o">)</span>
<span class="o">(</span><span class="nv">IMAGE</span><span class="o">=</span>/home/user/edk2/Build/OvmfX64/DEBUG_GCC5/X64/OvmfPkg/Sec/SecMain/DEBUG/SecMain.efi<span class="o">)</span>
</code></pre>
</div>
<p>e.g. </p>
<div class="codehilite">
<pre><span></span><code>user@user-OST-VM:~/edk2$ grep SecMain Build/OvmfX64/DEBUG_GCC5/Ovmf.map
SecMain <span class="o">(</span>Fixed Flash Address, <span class="nv">BaseAddress</span><span class="o">=</span>0x00fffcc094, <span class="nv">EntryPoint</span><span class="o">=</span>0x00fffd2584, <span class="nv">Type</span><span class="o">=</span>PE<span class="o">)</span>
<span class="o">(</span><span class="nv">IMAGE</span><span class="o">=</span>/home/user/edk2/Build/OvmfX64/DEBUG_GCC5/X64/OvmfPkg/Sec/SecMain/DEBUG/SecMain.efi<span class="o">)</span>
</code></pre>
</div>
<ul>
<li>Reload symbols using correct <code><SECMAIN_BASEADDRESS></code>, <code><SECMAIN_TEXT_OFFSET></code>, and <code><SECMAIN_DATA_OFFSET></code> found above. :</li>
</ul>
<pre><code>add-symbol-file Build/OvmfX64/DEBUG_GCC5/X64/SecMain.debug (<SECMAIN_BASEADDRESS>+<SECMAIN_TEXT_OFFSET>) -s .data (<SECMAIN_BASEADDRESS>+<SECMAIN_DATA_OFFSET>)
</code></pre>
<p>Which for the above example values would translate to the following (but make sure to use your values, incase you compiled with different options and have different offsets.):</p>
<div class="codehilite">
<pre><span></span><code><span class="o">(</span>gdb<span class="o">)</span> add-symbol-file Build/OvmfX64/DEBUG_GCC5/X64/SecMain.debug <span class="o">(</span>0x00fffcc094+0x240<span class="o">)</span> -s .data <span class="o">(</span>0x00fffcc094+0x8900<span class="o">)</span>
add symbol table from file <span class="s2">"Build/OvmfX64/DEBUG_GCC5/X64/SecMain.debug"</span> at
.text_addr <span class="o">=</span> 0xfffcc2d4
.data_addr <span class="o">=</span> 0xfffd4994
<span class="o">(</span>y or n<span class="o">)</span> y
Reading symbols from Build/OvmfX64/DEBUG_GCC5/X64/SecMain.debug...
</code></pre>
</div>
<ul>
<li>You can now use symbolic breakpoints. Add a breakpoint at function <code>SecCoreStartupWithStack</code></li>
</ul>
<div class="codehilite">
<pre><span></span><code><span class="o">(</span>gdb<span class="o">)</span> <span class="nb">break</span> SecCoreStartupWithStack
Breakpoint <span class="m">1</span> at 0xfffd1b02: file /home/user/edk2/OvmfPkg/Sec/SecMain.c, line <span class="m">734</span>.
</code></pre>
</div>
<ul>
<li>Connect to target:</li>
</ul>
<pre><code>(gdb) target remote :1234
</code></pre>
<ul>
<li>Continue execution by <code>(gdb) c</code></li>
<li>Step to the debug print you added in Exercise #2</li>
<li>(You can use <code>list</code> to show source code in gdb, and <code>break SecMain.c:<Line_Number>"</code> to break on the appropriate line.)</li>
</ul>
</div>
</div>
</div>
<div class="vert vert-1" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@8ef5c8efef154efe8cdacf4e22cf1f6c">
<div class="xblock xblock-public_view xblock-public_view-done" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="done" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@8ef5c8efef154efe8cdacf4e22cf1f6c" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="True">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Completion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
<div class="vert vert-2" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@e198097258c3491fb645e0e148fab3de">
<div class="xblock xblock-public_view xblock-public_view-discussion" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="discussion" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@e198097258c3491fb645e0e148fab3de" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Discussion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
</div>
<script type="text/javascript">
(function (require) {
require(['/static/js/dateutil_factory.be68acdff619.js?raw'], function () {
require(['js/dateutil_factory'], function (DateUtilFactory) {
DateUtilFactory.transform('.localized-datetime');
});
});
}).call(this, require || RequireJS.require);
</script>
<script>
function emit_event(message) {
parent.postMessage(message, '*');
}
</script>
</div>
<div class="xblock xblock-public_view xblock-public_view-vertical" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-init="VerticalStudentView" data-runtime-class="LmsRuntime" data-runtime-version="1" data-block-type="vertical" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@vertical+block@d49560dc1ca34527ae4987ea12354ddb" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="vert-mod">
<div class="vert vert-0" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@91b04905a27f49edbdb25cf9d75956e9">
<div class="xblock xblock-public_view xblock-public_view-markdown" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="markdown" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@91b04905a27f49edbdb25cf9d75956e9" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="markdown_xblock"><p>ASSERT is another macro delivered by DebugLib to simplify debugging process by providing additional information about location of problem.</p>
<p>EDKII uses many debug macros which you can read about <a href="https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/31_testing_and_debugging_uefi_drivers/readme.4">here</a>.</p>
<h2>Exercise #4: Let's try ASSERT</h2>
<ul>
<li>Please add following modification:</li>
</ul>
<div class="codehilite">
<pre><span></span><code><span class="gh">diff --git a/OvmfPkg/Sec/SecMain.c b/OvmfPkg/Sec/SecMain.c</span>
<span class="gh">index 2c5561661e..fec863836a 100644</span>
<span class="gd">--- a/OvmfPkg/Sec/SecMain.c</span>
<span class="gi">+++ b/OvmfPkg/Sec/SecMain.c</span>
<span class="gu">@@ -815,6 +815,7 @@ SecCoreStartupWithStack (</span>
(UINT32)(UINTN)TopOfCurrentStack
));
<span class="gi">+ ASSERT (FALSE);</span>
//
// Initialize floating point operating environment
// to be compliant with UEFI spec.
</code></pre>
</div>
<ul>
<li>Recompile the code</li>
<li>Run in QEMU</li>
</ul>
<pre><code>qemu-system-x86_64 -nographic -bios Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd -chardev file,path=debug.log,id=edk2-debug -device isa-debugcon,iobase=0x402,chardev=edk2-debug -net none
</code></pre>
<ul>
<li>In debug.log file you should find following:</li>
</ul>
<pre><code>ASSERT /home/user/edk2/OvmfPkg/Sec/SecMain.c(823): ((BOOLEAN)(0==1))
</code></pre>
<p>As you can see <code>ASSERT</code> macro provide source code file and line, as well as information about the value of the condition which triggered ASSERT. Macro is triggered when its parameter value is FALSE.</p>
<h2>Exercise #5: Release-build ASSERT behavior</h2>
<p>ASSERTs can trick developers into making security mistakes. Specifically if a developer inserts an ASSERT that is meant to check for some security-relevant condition such as an invalid value. A developer might thing that the ASSERT will still do the check in a release-build code, when in may not. In practice, whether an ASSERT macro continues to function in release-build code, or whether it's simply compiled-out, depends on the macro definition, and the compile options. So developers used to one behavior in one codebase may expect that behavior in another codebase, but it may not actually behave the way they expect.</p>
<p>Test whether the ASSERT you inserted will trigger and prevent system boot in a RELEASE build of the source code.</p>
<p><strong><em>Now remove the assert</em></strong> to avoid problems with further exercises.</p>
</div>
</div>
</div>
<div class="vert vert-1" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@problem+block@70d9e0da76e5419a9da6f0c865d16b52">
<div class="xblock xblock-public_view xblock-public_view-problem xmodule_display xmodule_ProblemBlock" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="problem" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@problem+block@70d9e0da76e5419a9da6f0c865d16b52" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="True">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Mini-quiz #3 is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
<div class="vert vert-2" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@c015d93c01694110af867448abb3ff8c">
<div class="xblock xblock-public_view xblock-public_view-done" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="done" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@c015d93c01694110af867448abb3ff8c" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="True">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Completion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
<div class="vert vert-3" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@c1b1c5e54ac543fda3a58b286f6f6107">
<div class="xblock xblock-public_view xblock-public_view-discussion" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="discussion" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@c1b1c5e54ac543fda3a58b286f6f6107" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Discussion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
</div>
<script type="text/javascript">
(function (require) {
require(['/static/js/dateutil_factory.be68acdff619.js?raw'], function () {
require(['js/dateutil_factory'], function (DateUtilFactory) {
DateUtilFactory.transform('.localized-datetime');
});
});
}).call(this, require || RequireJS.require);
</script>
<script>
function emit_event(message) {
parent.postMessage(message, '*');
}
</script>
</div>
<div class="xblock xblock-public_view xblock-public_view-vertical" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-init="VerticalStudentView" data-runtime-class="LmsRuntime" data-runtime-version="1" data-block-type="vertical" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@vertical+block@99a4d78e73c342b3852d1beca0c997a5" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="vert-mod">
<div class="vert vert-0" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@ed2cb3fd452b4545b617f0ab3abc6609">
<div class="xblock xblock-public_view xblock-public_view-markdown" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="markdown" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@ed2cb3fd452b4545b617f0ab3abc6609" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="markdown_xblock"><p>Debugging of some code parts may be challenging because of compiler optimizations, which are enabled by default. Compiler optimization can be disabled in two ways:</p>
<ul>
<li>In DSC for whole package </li>
<li>In INF file just for one module </li>
</ul>
<h2>Exercise #6: disable compiler optimization in INF</h2>
<ul>
<li>Let's build RELEASE and check the size of SecMain module</li>
</ul>
<div class="codehilite">
<pre><span></span><code>build -p OvmfPkg/OvmfPkgX64.dsc -b RELEASE -t GCC5 -n <span class="k">$(</span>nproc<span class="k">)</span> -a X64 all
</code></pre>
</div>
<div class="codehilite">
<pre><span></span><code>user@user-OST-VM:~/edk2$ ls -al Build/OvmfX64/RELEASE_GCC5/X64/SecMain.efi
-rw-rw-r-- <span class="m">1</span> user user <span class="m">32128</span> Oct <span class="m">19</span> <span class="m">07</span>:53 Build/OvmfX64/RELEASE_GCC5/X64/SecMain.efi
</code></pre>
</div>
<ul>
<li>Let's build DEBUG and check the size of SecMain module</li>
</ul>
<div class="codehilite">
<pre><span></span><code>build -p OvmfPkg/OvmfPkgX64.dsc -b DEBUG -t GCC5 -n <span class="k">$(</span>nproc<span class="k">)</span> -a X64 all
</code></pre>
</div>
<div class="codehilite">
<pre><span></span><code>user@user-OST-VM:~/edk2$ ls -al Build/OvmfX64/DEBUG_GCC5/X64/SecMain.efi
-rw-rw-r-- <span class="m">1</span> user user <span class="m">39872</span> Oct <span class="m">19</span> <span class="m">07</span>:52 Build/OvmfX64/DEBUG_GCC5/X64/SecMain.efi
</code></pre>
</div>
<ul>
<li>Let's disable optimization in DEBUG build</li>
</ul>
<div class="codehilite">
<pre><span></span><code><span class="gh">diff --git a/OvmfPkg/Sec/SecMain.inf b/OvmfPkg/Sec/SecMain.inf</span>
<span class="gh">index 95cf0025e1..3c0af1d1ed 100644</span>
<span class="gd">--- a/OvmfPkg/Sec/SecMain.inf</span>
<span class="gi">+++ b/OvmfPkg/Sec/SecMain.inf</span>
<span class="gu">@@ -80,3 +80,6 @@</span>
[FeaturePcd]
gUefiOvmfPkgTokenSpaceGuid.PcdSmmSmramRequire
<span class="gi">+</span>
<span class="gi">+[BuildOptions]</span>
<span class="gi">+ GCC:*_*_*_CC_FLAGS = -O0</span>
</code></pre>
</div>
<p>Now rebuild the debug build.</p>
<div class="codehilite">
<pre><span></span><code>build -p OvmfPkg/OvmfPkgX64.dsc -b DEBUG -t GCC5 -n <span class="k">$(</span>nproc<span class="k">)</span> -a X64 all
</code></pre>
</div>
<p>And view the new file size.</p>
<pre><code>user@user-OST-VM:~/edk2$ ls -al Build/OvmfX64/DEBUG_GCC5/X64/SecMain.efi
-rw-rw-r-- 1 user user 45440 Oct 19 07:56 Build/OvmfX64/DEBUG_GCC5/X64/SecMain.efi
</code></pre>
<p>Given below is the output of debug log after compiler optimization is disabled.</p>
<pre><code>FV Space Information
SECFV [22%Full] 212992 (0x34000) total, 47872 (0xbb00) used, 165120 (0x28500) free
PEIFV [22%Full] 917504 (0xe0000) total, 209448 (0x33228) used, 708056 (0xacdd8) free
DXEFV [33%Full] 12582912 (0xc00000) total, 4212496 (0x404710) used, 8370416 (0x7fb8f0) free
FVMAIN_COMPACT [35%Full] 3440640 (0x348000) total, 1236936 (0x12dfc8) used, 2203704 (0x21a038) free
</code></pre>
<p>What we can see is that DEBUG is bigger from RELEASE ~25%, but unoptimized debug binary is 40% bigger. The compiler definitely uses shortcuts, that may cause problems when debugging EDKII code. So if you face unexpected behavior during debugging it is worth to consider disabling compiler optimization.</p>
<h2>Exercise #7: disable compiler optimization in DSC</h2>
<p>In the case of modifying a DSC file, we disable optimization in the same way, under the same section <code>[BuildOptions]</code>. But in <code>OvmfPkgX64.dsc</code> we already have some flags for GCC RELEASE build.</p>
<div class="codehilite">
<pre><span></span><code><span class="gh">diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc</span>
<span class="gh">index 718399299f..fddbc1cf00 100644</span>
<span class="gd">--- a/OvmfPkg/OvmfPkgX64.dsc</span>
<span class="gi">+++ b/OvmfPkg/OvmfPkgX64.dsc</span>
<span class="gu">@@ -74,6 +74,7 @@</span>
[BuildOptions]
GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG
<span class="gi">+ GCC:DEBUG_*_*_CC_FLAGS = -O0</span>
INTEL:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG
MSFT:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG
!if $(TOOL_CHAIN_TAG) != "XCODE5" && $(TOOL_CHAIN_TAG) != "CLANGPDB"
!if $(TOOL_CHAIN_TAG) != "XCODE5" && $(TOOL_CHAIN_TAG) != "CLANGPDB"
</code></pre>
</div>
<p>Please note the change in the wildcard (<code>*</code>) placement compared to the previous INF example, and the fact that instead of having <code>*_*_*_CC_FLAGS</code> as in module build options (which would apply to both RELEASE and DEBUG), we distinguish RELEASE and DEBUG build flags.</p>
<p>Rebuild your debug-build firmware.</p>
<div class="codehilite">
<pre><span></span><code>build -p OvmfPkg/OvmfPkgX64.dsc -b DEBUG -t GCC5 -n <span class="k">$(</span>nproc<span class="k">)</span> -a X64 all
</code></pre>
</div>
<p>Note the new file size.</p>
<pre><code>user@user-OST-VM:~/edk2$ ls -al Build/OvmfX64/DEBUG_GCC5/X64/SecMain.efi
-rw-rw-r-- 1 user user 74496 Oct 19 08:01 Build/OvmfX64/DEBUG_GCC5/X64/SecMain.efi
</code></pre>
<p>The effect is that all code used in this package is built without optimization, which means that binaries are even bigger since not only the module itself but everything this module uses is built without optimization. The increase in size in comparison to RELEASE is more then 2x.</p>
<p>Of course the above method can be used to add arbitrary defines or compiler parameters either package-wide or module-wide.</p>
</div>
</div>
</div>
<div class="vert vert-1" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@495943ad5c89465296e961fbf542f052">
<div class="xblock xblock-public_view xblock-public_view-done" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="done" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@495943ad5c89465296e961fbf542f052" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="True">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Completion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
<div class="vert vert-2" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@3b7d9cd2e7f04cba9156384c079282bc">
<div class="xblock xblock-public_view xblock-public_view-discussion" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="discussion" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@3b7d9cd2e7f04cba9156384c079282bc" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Discussion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
</div>
<script type="text/javascript">
(function (require) {
require(['/static/js/dateutil_factory.be68acdff619.js?raw'], function () {
require(['js/dateutil_factory'], function (DateUtilFactory) {
DateUtilFactory.transform('.localized-datetime');
});
});
}).call(this, require || RequireJS.require);
</script>
<script>
function emit_event(message) {
parent.postMessage(message, '*');
}
</script>
</div>
<div class="xblock xblock-public_view xblock-public_view-vertical" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-init="VerticalStudentView" data-runtime-class="LmsRuntime" data-runtime-version="1" data-block-type="vertical" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@vertical+block@dad6b46e71534fdc963f3beaae07b3cb" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="vert-mod">
<div class="vert vert-0" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@b6ae274709ea488c84e6fa010f8c2a92">
<div class="xblock xblock-public_view xblock-public_view-markdown" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="markdown" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@b6ae274709ea488c84e6fa010f8c2a92" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="markdown_xblock"><p>EDKII provides the SourceLevelDebug family of packages, which support an alternative way of debugging EDKII source code.
The <a href="https://www.intel.com/content/dam/develop/external/us/en/documents/udk-debugger-tool-user-manual-v1-11-820238.pdf">documentation</a> is outdated,
but worth reading if you plan to use this features with real hardware. There is also a presentation from UEFI forum <a href="https://uefi.org/sites/default/files/resources/EDK_II_SW_debugger_v0.1_lj-Plugfest.pdf">here</a>. Source level debugging features supported on Linux are:</p>
<ul>
<li>GDB support</li>
<li>SEC debugging after temporary RAM initialization</li>
<li>SMM debugging</li>
<li>Debugging for a multiprocessor environment - i.e. an ability to debug code running not only the bootstrap processor (BSP) (i.e. the first processor code that comes up), but also on application processors (APs) (the subsequent cores that are initialized by the BSP.)</li>
</ul>
<h2>Exercise #8: Install Intel UDK Debugger Tool</h2>
<ul>
<li>Download, unpack and install:</li>
</ul>
<pre><code>wget https://downloadmirror.intel.com/674526/udk-debugger-tool-v1-5-1-linux.zip
unzip udk-debugger-tool-v1-5-1-linux.zip
chmod +x ./UDK_Debugger_Tool_v1_5_1.bin
sudo ./UDK_Debugger_Tool_v1_5_1.bin -i console
</code></pre>
<p>(<a href="https://gitlab.com/opensecuritytraining/arch4021-intro-uefi-additional-files/-/blob/master/udk-debugger-tool-v1-5-1-linux.zip">Mirror copy of udk-debugger-tool-v1-5-1-linux.zip</a> incase the above link breaks)</p>
<ul>
<li><p>Follow instructions with default options until <code>Debug Port Channel</code> selection, for which you should choose <code>4</code> (TCP), and then provide server:<code>localhost</code> and port <code>1234</code>.</p></li>
<li><p>After exiting the installer, if you examine <code>/etc/udkdebugger.conf</code>, the debug port section should contain the following:</p></li>
</ul>
<pre><code>[Debug Port]
Channel = TCP
Port = 1234
Server = localhost
</code></pre>
<h2>Exercise #9: Enable Source Level Debugging</h2>
<ul>
<li>Modify the DSC file:</li>
</ul>
<div class="codehilite">
<pre><span></span><code><span class="gh">diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc</span>
<span class="gh">index 718399299f..2b1fb75c05 100644</span>
<span class="gd">--- a/OvmfPkg/OvmfPkgX64.dsc</span>
<span class="gi">+++ b/OvmfPkg/OvmfPkgX64.dsc</span>
<span class="gu">@@ -31,7 +31,7 @@</span>
#
DEFINE SECURE_BOOT_ENABLE = FALSE
DEFINE SMM_REQUIRE = FALSE
<span class="gd">- DEFINE SOURCE_DEBUG_ENABLE = FALSE</span>
<span class="gi">+ DEFINE SOURCE_DEBUG_ENABLE = TRUE</span>
!include OvmfPkg/OvmfTpmDefines.dsc.inc
</code></pre>
</div>
<ul>
<li>Build</li>
</ul>
<pre><code>build -p OvmfPkg/OvmfPkgX64.dsc -b DEBUG -t GCC5 -n $(nproc) -a X64 all
</code></pre>
<ul>
<li>Run QEMU, please note serial parameter, which sets up a server to which Intel UDK Debugger can connect</li>
</ul>
<pre><code>qemu-system-x86_64 -nographic -bios Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd -serial tcp:127.0.0.1:1234,server -net none
</code></pre>
<ul>
<li>Run UDK Debugger</li>
</ul>
<pre><code>user@user-OST-VM:~$ /opt/intel/udkdebugger/bin/udk-gdb-server
Intel(R) UEFI Development Kit Debugger Tool Version 1.5.1
Debugging through TCP (localhost:1234)
Redirect Target output to TCP port (20715)
Debug agent revision: 0.4
GdbServer on user-OST-VM is waiting for connection on port 1235
Connect with 'target remote user-OST-VM:1235'
</code></pre>
<ul>
<li>Connect with GDB to port 1235</li>
</ul>
<pre><code>user@user-OST-VM:~$ gdb --quiet
(gdb) target remote :1235
Remote debugging using :1235
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
(gdb) source /opt/intel/udkdebugger/script/udk_gdb_script
##############################################################
# This GDB configuration file contains settings and scripts
# for debugging UDK firmware.
# WARNING: Setting pending breakpoints is NOT supported by the GDB!
##############################################################
Loading symbol for address: 0xfffd412b
add symbol table from file "/home/user/edk2/Build/OvmfX64/DEBUG_GCC5/X64/OvmfPkg/Sec/SecMain/DEBUG/SecMain.dll" at
.text_addr = 0xfffcc2d4
.data_addr = 0xfffe5154
(udb) bt
#0 CpuBreakpoint () at /home/ost2/Desktop/edk2/MdePkg/Library/BaseLib/X64/GccInline.c:60
#1 PeCoffLoaderExtraActionCommon (Signature=1145130828, ImageContext=ImageContext@entry=0x81fb80)
at /home/ost2/Desktop/edk2/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c:144
#2 PeCoffLoaderRelocateImageExtraAction (ImageContext=ImageContext@entry=0x81fb80)
at /home/ost2/Desktop/edk2/SourceLevelDebugPkg/Library/PeCoffExtraActionLibDebug/PeCoffExtraActionLib.c:213
#3 0x00000000fffd18c8 in FindAndReportEntryPoints (PeiCoreEntryPoint=0x81fb78,
BootFirmwareVolumePtr=<synthetic pointer>) at /home/ost2/Desktop/edk2/OvmfPkg/Sec/SecMain.c:708
#4 SecStartupPhase2 (Context=0x81fd20) at /home/ost2/Desktop/edk2/OvmfPkg/Sec/SecMain.c:916
#5 0x00000000fffd49d2 in DebugPortInitialize (Function=0xfffd1e88 <InitializeDebugAgentPhase2>,
Context=0x81fce0)
at /home/ost2/Desktop/edk2/SourceLevelDebugPkg/Library/DebugCommunicationLibSerialPort/DebugCommunicationLibSerialPort.c:66
#6 InitializeDebugAgent (Function=0xfffd123a <SecStartupPhase2>, Context=0x81fd20, InitFlag=1)
at /home/ost2/Desktop/edk2/SourceLevelDebugPkg/Library/DebugAgent/SecPeiDebugAgent/SecPeiDebugAgentLib.c:413
#7 SecCoreStartupWithStack (BootFv=<optimized out>, TopOfCurrentStack=<optimized out>)
at /home/ost2/Desktop/edk2/OvmfPkg/Sec/SecMain.c:886
#8 0x00000000fffd5741 in _ModuleEntryPoint ()
#9 0x5aa55aa55aa55aa5 in jQuery22403545760663904043_1670848571110 ()
#10 0x5aa55aa55aa55aa5 in jQuery22405755335005961207_1670848610422 ()
#11 0x5aa55aa55aa55aa5 in ?? ()
#12 0x5aa55aa55aa55aa5 in ?? ()
#13 0x0000000000000000 in ?? ()
</code></pre>
<p>As you can see the UDK script recognizes paths, locations, and correctly loaded the text and data section. It can also recognize the backtrace to some extent.</p>
</div>
</div>
</div>
<div class="vert vert-1" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@2b527a91398b462882adeaad172914dd">
<div class="xblock xblock-public_view xblock-public_view-done" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="done" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@2b527a91398b462882adeaad172914dd" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="True">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Completion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
<div class="vert vert-2" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@74963ed3310c4888b94bffcd162cc3d6">
<div class="xblock xblock-public_view xblock-public_view-discussion" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="discussion" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@74963ed3310c4888b94bffcd162cc3d6" data-request-token="cc0d017aff1511eeaa280242ac12000b" data-graded="True" data-has-score="False">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Discussion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
</div>
<script type="text/javascript">
(function (require) {
require(['/static/js/dateutil_factory.be68acdff619.js?raw'], function () {
require(['js/dateutil_factory'], function (DateUtilFactory) {
DateUtilFactory.transform('.localized-datetime');
});
});
}).call(this, require || RequireJS.require);
</script>
<script>
function emit_event(message) {
parent.postMessage(message, '*');
}
</script>
</div>