{"id":246,"date":"2023-04-07T16:11:07","date_gmt":"2023-04-07T16:11:07","guid":{"rendered":"https:\/\/lucaceresoli.net\/?p=246"},"modified":"2023-04-07T16:11:08","modified_gmt":"2023-04-07T16:11:08","slug":"fixing-reboot-in-zynqmp-pmu-firmware","status":"publish","type":"post","link":"https:\/\/lucaceresoli.net\/it\/fixing-reboot-in-zynqmp-pmu-firmware\/","title":{"rendered":"Fixing reboot in ZynqMP PMU Firmware"},"content":{"rendered":"\n<p>See <a href=\"https:\/\/bootlin.com\/blog\/fixing-reboot-in-zynqmp-pmu-firmware\/\" target=\"_blank\" rel=\"noreferrer noopener\">the original post<\/a> on the Bootlin website.<\/p>\n\n\n\n<p>Thanks to community contributions, our engineer <a href=\"https:\/\/bootlin.com\/company\/staff\/luca-ceresoli\/\">Luca Ceresoli<\/a> has recently published a fix to the <a href=\"https:\/\/github.com\/lucaceresoli\/zynqmp-pmufw-builder\">zynqmp-pmufw-builder<\/a> repository that allows building a fully working PMU Firmware binary. Rebooting had previously been broken for a long time.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h1 class=\"wp-block-heading\">Building the PMU Firmware<\/h1>\n\n\n\n<p>For the uninitiated, the PMU (Platform Management Unit) is an auxiliary <a href=\"https:\/\/www.xilinx.com\/products\/design-tools\/microblaze.html\">Microblaze<\/a> processor present on the <a href=\"https:\/\/www.xilinx.com\/products\/silicon-devices\/soc\/zynq-ultrascale-mpsoc.html\">Xilinx\/AMD ZynqMP<\/a> System-on-Chips, whose role includes handling power states and power domains, as well as rebooting the chip. The PMU Firmware (often called PMUFW) is the small program running on it, and it is loaded during the early boot process. The PMUFW source code is available in the Xilinx <a href=\"https:\/\/github.com\/Xilinx\/embeddedsw\">embeddedsw<\/a> git repository.<\/p>\n\n\n\n<p>A few years ago Luca has <a href=\"https:\/\/lucaceresoli.net\/zynqmp-pmufw-builder\/\">published zynqmp-pmufw-builder<\/a>, a simple script to allow building the PMU Firmware. One goal of that simple project is to make the build process easy and quick, without needing a complex Yocto setup. Another goal it to document the build process itself by being as simple and readable as possible.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">The reboot bug<\/h1>\n\n\n\n<p>Unfortunately, about one year ago it has been reported that the PMUFW binaries built by this script are hanging forever during the reboot process, making it unusable in most cases.<\/p>\n\n\n\n<p>Since the embeddedsw code being built was the same, the toolchain used was the first suspect: zynqmp-pmufw-builder leverages crosstool-NG to build a basic Microblaze toolchain, while Xilinx\/AMD supports either using their Vitis IDE or the <a href=\"https:\/\/github.com\/Xilinx\/meta-xilinx\">meta-xilinx<\/a> Yocto layers which build their own Microblaze toolchain. There must be a difference in the toolchain that creates this bug, maybe due to one of <a href=\"https:\/\/github.com\/Xilinx\/meta-xilinx\/tree\/4f55e171396816ee995e47060fba59463f5ddccd\/meta-microblaze\/recipes-devtools\/gcc\/gcc-12\">the 50+ patches<\/a> that the <code>meta-microblaze<\/code> layer by Xilinx applies on top of <code>gcc<\/code>.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">A workaround\u2026<\/h1>\n\n\n\n<p>Recently AMD engineer Ibai Erkiaga Elorza gave a big contribution by investigating the problem in deep detail. He found the issue in the initialization of the TCM memories during the RPU cluster reset process: the PMUFW code is initializing the TCM memories <a href=\"https:\/\/github.com\/Xilinx\/embeddedsw\/blob\/xilinx_v2022.2\/lib\/sw_apps\/zynqmp_pmufw\/src\/pm_sram.c#L170\">using <code>memset()<\/code><\/a>, which does not guarantee that memory will be written using 32-bit accesses as required. The toolchain that zynqmp-pmufw-builder used to build via crosstool-NG does not work because it implements <code>memset()<\/code> using 8-bit accesses. Other toolchains work for one reason or another.<\/p>\n\n\n\n<p>Ibai also found that disabling <code>CT_LIBC_NEWLIB_ENABLE_TARGET_OPTSPACE<\/code> in the crosstool-NG configuration would avoid this problem. This is only a workaround because the code should work with every reasonable toolchain, and it also requires to rebuild the toolchain, but it did the trick!<\/p>\n\n\n\n<p>Luca <a href=\"https:\/\/github.com\/lucaceresoli\/zynqmp-pmufw-builder\/commit\/5db56c3b3f5f383bd3e2d39c4a7bf82402412762\">added this workaround<\/a>, which finally allowed zynqmp-pmufw-builder to build PMUFW binaries which are able to reboot correctly! He also published <a href=\"https:\/\/github.com\/lucaceresoli\/zynqmp-pmufw-binaries\/tree\/master\/k26\">new binary images for the ZynqMP-based Kria SoMs<\/a> that have reboot working properly. Building binaries for non-Kria ZynqMP boards should work as well now.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">\u2026and a proper fix!<\/h1>\n\n\n\n<p>Shortly later, AMD engineer Neal Frager went even further and prepared a patch to fix the bug at its root: the PMUFW code. His patch is simply replacing the <code>memset()<\/code> calls with a for loop using 32-bit pointers. With this simple change the toolchain workaround is not required anymore.<\/p>\n\n\n\n<p>Luca added <a href=\"https:\/\/github.com\/lucaceresoli\/zynqmp-pmufw-builder\/commit\/6c9d51215f58539e426f0b720deeba881af5487b\">Neal\u2019s patch<\/a> to the zynqmp-pmufw-builder script along with code to apply it&nbsp; before building the PMUFW. He then removed the workaround from the crosstool-NG configuration and verified that everything is working, including reboot. The result is on the zynqmp-pmufw-builder master branch.<\/p>\n\n\n\n<p>We would like to thank Ibai and Neal for their effort in getting this very annoying issue solved!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>See the original post on the Bootlin website. Thanks to community contributions, our engineer Luca Ceresoli has recently published a fix to the zynqmp-pmufw-builder repository that allows building a fully working PMU Firmware binary. Rebooting had previously been broken for a long time.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[6,5,4],"translation":{"provider":"WPGlobus","version":"2.12.2","language":"it","enabled_languages":["en","it"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"it":{"title":false,"content":false,"excerpt":false}}},"_links":{"self":[{"href":"https:\/\/lucaceresoli.net\/it\/wp-json\/wp\/v2\/posts\/246"}],"collection":[{"href":"https:\/\/lucaceresoli.net\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lucaceresoli.net\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lucaceresoli.net\/it\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/lucaceresoli.net\/it\/wp-json\/wp\/v2\/comments?post=246"}],"version-history":[{"count":1,"href":"https:\/\/lucaceresoli.net\/it\/wp-json\/wp\/v2\/posts\/246\/revisions"}],"predecessor-version":[{"id":247,"href":"https:\/\/lucaceresoli.net\/it\/wp-json\/wp\/v2\/posts\/246\/revisions\/247"}],"wp:attachment":[{"href":"https:\/\/lucaceresoli.net\/it\/wp-json\/wp\/v2\/media?parent=246"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lucaceresoli.net\/it\/wp-json\/wp\/v2\/categories?post=246"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lucaceresoli.net\/it\/wp-json\/wp\/v2\/tags?post=246"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}