{"id":532,"date":"2022-11-21T02:14:11","date_gmt":"2022-11-21T01:14:11","guid":{"rendered":"https:\/\/klondike.es\/klog\/?p=532"},"modified":"2022-11-21T02:14:11","modified_gmt":"2022-11-21T01:14:11","slug":"patching-the-acpi-dmar-table-to-allow-tpm2-0","status":"publish","type":"post","link":"https:\/\/klondike.es\/klog\/2022\/11\/21\/patching-the-acpi-dmar-table-to-allow-tpm2-0\/","title":{"rendered":"Patching the ACPI DMAR table to allow TPM2.0"},"content":{"rendered":"<p>The Intel Corporation 8 Series HECI has support for a TPM2.0 device which can be enabled by the BIOS. Unfortunately, this firmware TPM device uses DMA accesses (instead of MMIO as used by newer HECIs) to interact with the operating system and most BIOS do not include an appropriate entry in the DMAR table to allow the IOMMU to work along the firmware TPM.<\/p>\n<p>This blogpost aims to help you understand the procedure needed to patch the DMAR ACPI table provided by your system&#8217;s firmware to allow the TPM2.0 device through. Unfortunately, given the way the Linux kernel handles RMRR entries, you will also need a kernel patch to alias the HECIs function 7 (used by the firmware TPM application) to the function 0 (the only one that is exposed).<\/p>\n<p><!--more--> To patch the DMAR table you will need the following tools: iasl (which you will probably need to install), lspci, cat, grep, a text editor and a way to modify your initramfs (I usually create my own although you may be able to create a cpio image with the table in a way similar to how microcodes are loaded).<\/p>\n<p>The first step is extracting your system&#8217;s DMAR table in binary format. You can do so by running the following command: <tt>cat \/sys\/firmware\/acpi\/tables\/DMAR &gt; dmar.bin<\/tt><\/p>\n<p>To be able to modify the table you need to convert it into text format. You do this using iasl as follows: <tt>iasl dmar.bin<\/tt><\/p>\n<p>You also need to find out at which address the TPM2.0 device is. You can do by looking <tt>\/proc\/iomem<\/tt> for a device with a name similar to <tt>MSFT0101:00<\/tt>. In my system this could be done by running the following command: <tt>grep MSFT \/proc\/iomem | tail -1<\/tt> You should get an entry similar to this: <tt>xxxxxxxx-yyyyyyyy : MSFT0101:00<\/tt>. Here xxxxxxxx is the lower end of the memory range and yyyyyyyy the higher end.<\/p>\n<p>You need to find also the &#8220;physical&#8221; path to your HECI. Use the following command to do so: <tt>lspci -nn | grep HECI<\/tt>. The entry will look something as follows: <tt>ii:jj.k Communication controller [0780]: Intel Corporation 8 Series HECI #0 [llll:mmmm] (rev 04)<\/tt>. Notice that ii:jj.k are placeholders used to patch the DMAR table. Similary, llll:mmmm is a placeholder you might need if you need to patch the kernel to add another quirk. Note that k should be 0 for my patch to work.<\/p>\n<p>Now open the <tt>dmar.dsl<\/tt> file in your favorite editor and perform the appropriate changes. You just have to add the code, found below this paragraph, above the line at the end of the file where it says <tt>Raw Table Data:<\/tt> (if you put it below that line, your entry will instead be ignored). Remember that you need to replace xxxxxxxx and yyyyyyyy with the entries you obtained before using grep. You will also need to replace ii, jj and kk with the values you obtained using lspci. All three values are extacly two digits so you need to add zeros to the left to ensure they are two digits. For example, if your value for k on lspci is 0 you should replace kk with 00.<\/p>\n<p><tt>Subtable Type : 0001<br \/>\nLength : 0020<br \/>\nReserved : 0000<br \/>\nPCI Segment Number : 0000<br \/>\nBase Address : xxxxxxxx<br \/>\nEnd Address (limit) : yyyyyyyy<br \/>\nDevice Scope Type : 01<br \/>\nEntry Length : 08<br \/>\nReserved : 0000<br \/>\nEnumeration ID : 00<br \/>\nPCI Bus Number : ii<br \/>\nPCI Path : jj,kk<\/tt><\/p>\n<p>You will also need to increase the value of the entry in the original file labeled <tt>Oem Revision<\/tt>. Adding one to whichever number in the field works. Although all that is needed is that it is larger than the original value (so the table is marked as newer and therefore used when overriding the original table provided by your system&#8217;s manufacturer).<\/p>\n<p>Now we need to compile the new table. We do so using iasl: <tt>iasl dmar.dsl<\/tt> If the command worked correctly, you should see something as follows on your terminal: <tt>Compilation successful. 0 Errors, 0 Warnings, 0 Remarks<\/tt>. The new table file will be called <tt>dmar.aml<\/tt><\/p>\n<p>Finally you need to modify your initramfs so that the generated file is on <tt>kernel\/firmware\/acpi\/dmar.aml<\/tt> the way to do this will depend on your distribution. If you want to create a new initrd that can be concatenated with your existing one, you can do as follows: <tt>mkdir -p  kernel\/firmware\/acpi &amp;&amp; cp dmar.aml kernel\/firmware\/acpi &amp;&amp; find kernel -print0 | cpio -ov -0 --format=newc &gt; my-initramfs.cpio<\/tt> Then you need to move my-initramfs.cpio to your \/boot folder and make sure you configure your bootloader to include it when loading your kernel.<\/p>\n<p>If all went correctly after you reboot you should see something like the following on dmesg:<\/p>\n<p><tt>ACPI: DMAR ACPI table found in initrd [kernel\/firmware\/acpi\/dmar.aml]<br \/>\nACPI: Table Upgrade: override [DMAR<\/tt><\/p>\n<p>For the TPM to work you will also need to patch the kernel to add a PCI quirk for the HECI. You can check <a href=\"https:\/\/bugzilla.kernel.org\/show_bug.cgi?id=108251\" rel=\"noopener\" target=\"_blank\">Linux bug 108251<\/a> for the patch. Usually all you will need to do (if the TPM shows as function 7 on your dmesg log and the HECI shows on lspci with function 0) is just add an entry similar to the one below in <tt>drivers\/pci\/quirks.c<\/tt> Preferably after the definition of <tt>quirk_dma_func7_alias<\/tt> If your HECI uses a function other than 7 you may need to create your own function. Similarly, if your HECI is at a function other than 0 you will also need your own function too. If the value from lspci labeled as llll is 8086 then you can leave <tt>PCI_VENDOR_ID_INTEL<\/tt> as is, otherwise you will need to replace with llll or (if you plan to upstream the patch) the appropriate macro. Similarly you will need to replace mmmm with the device ID of your HECI.<\/p>\n<p><tt>DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0xmmmm,<br \/>\nquirk_dma_func7_alias);<\/tt><\/p>\n<p>I hope you found this entry useful and can now enjoy both your TPM 2.0 device and the protection provided by the IOMMU.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Intel Corporation 8 Series HECI has support for a TPM2.0 device which can be enabled by the BIOS. Unfortunately, this firmware TPM device uses DMA accesses (instead of MMIO as used by newer HECIs) to interact with the operating system and most BIOS do not include an appropriate entry in the DMAR table to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[103],"tags":[105,104,108,38,107],"class_list":["post-532","post","type-post","status-publish","format-standard","hentry","category-linux-software-libre","tag-acpi","tag-kernel","tag-lenovo-x240","tag-linux","tag-patching-2"],"_links":{"self":[{"href":"https:\/\/klondike.es\/klog\/wp-json\/wp\/v2\/posts\/532","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/klondike.es\/klog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/klondike.es\/klog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/klondike.es\/klog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/klondike.es\/klog\/wp-json\/wp\/v2\/comments?post=532"}],"version-history":[{"count":3,"href":"https:\/\/klondike.es\/klog\/wp-json\/wp\/v2\/posts\/532\/revisions"}],"predecessor-version":[{"id":535,"href":"https:\/\/klondike.es\/klog\/wp-json\/wp\/v2\/posts\/532\/revisions\/535"}],"wp:attachment":[{"href":"https:\/\/klondike.es\/klog\/wp-json\/wp\/v2\/media?parent=532"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/klondike.es\/klog\/wp-json\/wp\/v2\/categories?post=532"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/klondike.es\/klog\/wp-json\/wp\/v2\/tags?post=532"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}