<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>jic23</title>
    <link>https://people.kernel.org/jic23/</link>
    <description></description>
    <pubDate>Wed, 13 May 2026 22:19:27 +0000</pubDate>
    <item>
      <title>Howto test CXL enablement on Arm64 using QEMU</title>
      <link>https://people.kernel.org/jic23/howto-test-cxl-enablement-on-arm64-using-qemu</link>
      <description>&lt;![CDATA[Note: Parts of this blog are outdated / wrong.  I might fix it at somepoint soon!&#xA;&#xA;Note this blog post is a an evolving work in progress. All comments welcome by email to Jonathan.Cameron@huawei.com&#xA;&#xA;The CXL 2.0 specification is a fairly complex beast and as such, software enablement relies on having a suitable platform well in advance of actual hardware.  This helps with several aspects:&#xA;Specification prove out. &#xA;Early enablement to make sure the Linux distributions have support in place when hardware does arrive.&#xA;&#xA;The approach taken to this, spear-headed by the team at Intel is to emulate CXL 2.0 in QEMU and develop the Linux kernel, firmware and tooling support against that.&#xA;&#xA;Enabling similar for arm64 built directly on their work and the required code additions were fairly minimal.  However, bringing up a suitable test environment is less trivial and requires collating information from many sources.  The purpose of this blog is to bring all that information together in one location.&#xA;&#xA;The key parts needed are:&#xA;QEMU&#xA;EDK2&#xA;Kernel&#xA;Suitable OS Image&#xA;&#xA;Lets assume we have a ~/src/images directory for where we are going to put all the things needed to boot our emulated machine.&#xA;&#xA;Cross compiler&#xA;&#xA;Often available as part of a Linux distribution.  I&#39;m going to assume that anyone interested in this blog has one of these on hand already.&#xA;&#xA;EDK2 &#xA;&#xA;Tianocore or EDK2 is an open source BIOS.  A recent version is needed to enable the pxb-pcie / pxb-cxl PCI expansion bridges used for CXL emulation.  Linaro provides a useful set of scripts to aid building suitable firmware images.&#xA;For this document I used commit f297b7f200107&#xA;&#xA;  mkdir tianocore&#xA;  cd tianocore&#xA;  git clone https://git.linaro.org/uefi/uefi-tools.git&#xA;  git clone https://github.com/tianocore/edk2.git&#xA;  git submodule init \ &#xA;  MdeModulePkg/Library/BrotliCustomDecompressLib/brotli&#xA;  git submodule init \&#xA;  BaseTools/Source/C/BortiCompress/brotli&#xA;  git submodule init \&#xA;  CryptoPkg/Library/OpensslLib/openssl&#xA;  git submodule update&#xA;  uefi-tools/edk2-build.sh armvirtqemu64&#xA;  cp Build/ArmVirtQemu-AARCH64/RELEASEGCC5/FV/QEMUEFI.fd \&#xA;  ~/src/images&#xA;&#xA;Filesystem / OS Image&#xA;&#xA;So normally I&#39;d advocate taking the time to install your favorite Linux distribution on they system you are going to emulate, but for this blog post, let&#39;s take a different approach.  Abusing cloud images.&#xA;&#xA;There are nice sophisticated things that can be done with cloud-init and CDROM images etc, but it turns out Debian also ships images that skip the cloud-init part and have a root user with no password.  Just what we need to trying something like this.&#xA;&#xA;http://cdimage.debian.org/cdimage/cloud/sid/daily/20210504-627/debian-sid-nocloud-arm64-daily-20210504-627.qcow2 which works equally well with less complexity.&#xA;(I might do a follow up blog on the CDROM method as it was a fun detour and may be applicable to more distributions)&#xA;&#xA;Kernel&#xA;&#xA;For first run, we&#39;ll use the mainline kernel.&#xA;&#xA;  git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git&#xA;  cd linux&#xA;  make ARCH=arm64 CROSSCOMPILE=aarch64-linux-gnu- defconfig&#xA;&#xA;To avoid the need for messing around with initrd images which is a big waste of time when developing, we&#39;ll tweak the config in order to ensure everything we &#39;need&#39; is built in.&#xA;&#xA;Not all of these are technically necessary but they will probably be helpful if you are developing CXL stuff.&#xA;&#xA;  CONFIGACPIHMAT=y&#xA;  CONFIGACPIAPEIPCIEAER=y&#xA;  CONFIGACPIHOTPLUGMEMORY=y&#xA;  CONFIGMEMORYHOTPLUG=y&#xA;  CONFIGMEMORYHOTPLUGDEFAULTONLINE=y&#xA;  CONFIGMEMORYHOTREMOVE=y&#xA;  CONFIGCXLBUS=y&#xA;  CONFIGCXLMEM=y&#xA;&#xA;Build the kernel and copy it to our images directory&#xA;&#xA;  make ARCH=arm64 CROSSCOMPILE=aarch64-linux-gnu- &#xA;  cp arch/arm64/boot/Image ~/images&#xA;&#xA;QEMU&#xA;&#xA;The CXL emulation in QEMU is not yet upstream.  So get it from Ben Widawsky&#39;s gitlab.  He&#39;s been kind enough to include almost all the patches we need to support CXL on arm64.&#xA;&#xA;  git clone https://gitlab.com/bwidawsk/qemu&#xA;  cd qemu&#xA;&#xA;Now make a small change that I haven&#39;t shared upstream yet.&#xA;Note there has been some discussion on the right way to fix this but no firm conclusions yet.&#xA;https://lore.kernel.org/qemu-devel/20210513124737.00002b2d@Huawei.com/&#xA;&#xA;  Fix unaligned undersized access&#xA;&#xA;  Signed-off-by: Jonathan Cameron Jonathan.Cameron@huawei.com                                                                                               ---&#xA;  softmmu/memory.c | 10 ++++++++--&#xA;  1 file changed, 8 insertions(+), 2 deletions(-)&#xA;    diff --git a/softmmu/memory.c b/softmmu/memory.c&#xA;  index d4493ef9e4..11c1d54077 100644&#xA;  --- a/softmmu/memory.c&#xA;  +++ b/softmmu/memory.c&#xA;  @@ -531,6 +531,7 @@ static MemTxResult accesswithadjustedsize(hwaddr addr,&#xA;  unsigned accesssize;&#xA;  unsigned i;&#xA;  MemTxResult r = MEMTXOK;&#xA;  +    int offset = 0;&#xA;  if (!accesssizemin) {&#xA;  accesssizemin = 1;&#xA;  @@ -541,7 +542,12 @@ static MemTxResult accesswithadjustedsize(hwaddr addr,&#xA;  / FIXME: support unaligned access? /&#xA;  accesssize = MAX(MIN(size, accesssizemax), accesssizemin);&#xA;  -    accessmask = MAKE64BITMASK(0, accesssize  8);                                                                                                       &#xA;  +    if (accesssize   size) {&#xA;  +        offset = (addr % accesssize)  8;&#xA;  +        accessmask = MAKE64BITMASK(offset, size  8);&#xA;  +    } else { &#xA;  +        accessmask = MAKE64BITMASK(0, accesssize  8);&#xA;  +    }                                                                                                                                                            &#xA;  if (memoryregionbigendian(mr)) {&#xA;  for (i = 0; i &lt; size; i += accesssize) {&#xA;  r |= accessfn(mr, addr + i, value, accesssize,&#xA;  @@ -549,7 +555,7 @@ static MemTxResult accesswithadjustedsize(hwaddr addr,                                                                                          &#xA;  } else {&#xA;  for (i = 0; i &lt; size; i += accesssize) {&#xA;  -            r |= accessfn(mr, addr + i, value, accesssize, i  8, &#xA;  +            r |= accessfn(mr, addr - (addr % accesssize) + i, value,&#xA;  +                           accesssize, -offset + i  8,&#xA;  accessmask, attrs);&#xA;  }&#xA;  }&#xA;&#xA;Build QEMU&#xA;&#xA;  mkdir -p bin/native&#xA;  cd bin/native&#xA;  ../../configure --target-list=aarch64-softmmu --disable-docs&#xA;  make&#xA;&#xA;Booting the result&#xA;&#xA;  cd ~/src/images/&#xA;  ./qemu-system-aarch64 -M virt -m 4g,maxmem=8G,slots=8 -cpu max \&#xA;  -smp 4 -kernel Image -nographic -no-reboot \&#xA;  -bios QEMUEFI.fd \&#xA;  -drive if=none,file=cxl.qcow2,format=qcow2,id=hd \&#xA;  -device virtio-blk-pci,drive=hd \&#xA;  -append &#39;root=/dev/vda1&#39; \&#xA;  -object memory-backend-ram,size=4G,id=mem0 \&#xA;  -numa node,nodeid=0,cpus=0-3,memdev=mem0 \&#xA;  -object memory-backend-file,id=cxl-mem1,share,mem-path=/tmp/cxltest.raw,size=2G,align=2G \&#xA;  -device pxb-cxl,busnr=128,id=cxlbus1,uid=1,len-window-base=1,window-base[0]=0x4c0000000,memdev[0]=cxl-mem1 \&#xA;  -device cxl-rp,bus=cxlbus1,id=cxlrp,chassis=0,slot=1 \&#xA;  -device cxl-type3,bus=cxlrp,memdev=cxl-mem1,lsa=cxl-mem1,id=cxl-mem0,size=2G&#xA;&#xA;Login is [username: root, password:]&#xA;&#xA;You will probably want to be able to scp to the board later, so take this opportunity to generate host keys&#xA;&#xA;  dpkg-reconfigure openssh-server&#xA;Also, make your image nice an insecure by editing&#xA;  /etc/ssh/sshdconfig&#xA;&#xA;To set&#xA;&#xA;  PasswordAuthentication yes&#xA;  PermitEmptyPassword  yes&#xA;&#xA;Data Object Exchange support&#xA;&#xA;QEMU&#xA;&#xA;Need the patches from Avery Design. &#xA;https://lore.kernel.org/qemu-devel/1619454964-10190-1-git-send-email-cbrowy@avery-design.com/&#xA;&#xA;If using the b4 tool then&#xA;&#xA;  b4 am -t  1619454964-10190-1-git-send-email-cbrowy@avery-design.com&#xA;&#xA;Will fetch the patches.  Note the final test data appears to be corrupt, so given we don&#39;t need it use&#xA;&#xA;  git am --skip&#xA;&#xA;Kernel&#xA;&#xA;Need the Data Object Exchange patches from&#xA;https://lore.kernel.org/linux-pci/20210524133938.2815206-1-Jonathan.Cameron@huawei.com/T/#t&#xA;&#xA;  b4 am -t 20210524133938.2815206-1-Jonathan.Cameron@huawei.com&#xA;&#xA;which apply to&#xA;https://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl.git/commit/?h=next&amp;id=35c32e3095d396c750f5cdfdaa94cba83d9b23c6&#xA;&#xA;These both enable CDAT access via /sys/bus/cxl/devices/mem0/CDAT and a IOCTL interface (which will probably never be merged) for which there is a doetest program in tools/pci/&#xA;&#xA;Cross compile the doetest program and test the DOE with:&#xA;&#xA;  $ ./doetest -f /dev/pcidoe/doe\[0000\:81\:00.0\]190 -l&#xA;  VID: 0x1, Protocol 0&#xA;  VID: 0x1e98, Protocol 0x2&#xA;&#xA;]]&gt;</description>
      <content:encoded><![CDATA[<p>Note: Parts of this blog are outdated / wrong.  I might fix it at somepoint soon!</p>

<p>Note this blog post is a an evolving work in progress. All comments welcome by email to Jonathan.Cameron@huawei.com</p>

<p>The CXL 2.0 specification is a fairly complex beast and as such, software enablement relies on having a suitable platform well in advance of actual hardware.  This helps with several aspects:
* Specification prove out.
* Early enablement to make sure the Linux distributions have support in place when hardware does arrive.</p>

<p>The approach taken to this, spear-headed by the team at Intel is to emulate CXL 2.0 in QEMU and develop the Linux kernel, firmware and tooling support against that.</p>

<p>Enabling similar for arm64 built directly on their work and the required code additions were fairly minimal.  However, bringing up a suitable test environment is less trivial and requires collating information from many sources.  The purpose of this blog is to bring all that information together in one location.</p>

<p>The key parts needed are:
* QEMU
* EDK2
* Kernel
* Suitable OS Image</p>

<p>Lets assume we have a ~/src/images directory for where we are going to put all the things needed to boot our emulated machine.</p>

<h2 id="cross-compiler">Cross compiler</h2>

<p>Often available as part of a Linux distribution.  I&#39;m going to assume that anyone interested in this blog has one of these on hand already.</p>

<h2 id="edk2">EDK2</h2>

<p>Tianocore or EDK2 is an open source BIOS.  A recent version is needed to enable the pxb-pcie / pxb-cxl PCI expansion bridges used for CXL emulation.  Linaro provides a useful set of scripts to aid building suitable firmware images.
For this document I used commit f297b7f200107</p>

<blockquote><p>mkdir tianocore
cd tianocore
git clone <a href="https://git.linaro.org/uefi/uefi-tools.git" rel="nofollow">https://git.linaro.org/uefi/uefi-tools.git</a>
git clone <a href="https://github.com/tianocore/edk2.git" rel="nofollow">https://github.com/tianocore/edk2.git</a>
git submodule init \
     MdeModulePkg/Library/BrotliCustomDecompressLib/brotli
git submodule init \
     BaseTools/Source/C/BortiCompress/brotli
git submodule init \
     CryptoPkg/Library/OpensslLib/openssl
git submodule update
uefi-tools/edk2-build.sh armvirtqemu64
cp Build/ArmVirtQemu-AARCH64/RELEASE<em>GCC5/FV/QEMU</em>EFI.fd \
    ~/src/images</p></blockquote>

<h2 id="filesystem-os-image">Filesystem / OS Image</h2>

<p>So normally I&#39;d advocate taking the time to install your favorite Linux distribution on they system you are going to emulate, but for this blog post, let&#39;s take a different approach.  Abusing cloud images.</p>

<p>There are nice sophisticated things that can be done with cloud-init and CDROM images etc, but it turns out Debian also ships images that skip the cloud-init part and have a root user with no password.  Just what we need to trying something like this.</p>

<p><a href="http://cdimage.debian.org/cdimage/cloud/sid/daily/20210504-627/debian-sid-nocloud-arm64-daily-20210504-627.qcow2" rel="nofollow">http://cdimage.debian.org/cdimage/cloud/sid/daily/20210504-627/debian-sid-nocloud-arm64-daily-20210504-627.qcow2</a> which works equally well with less complexity.
(I might do a follow up blog on the CDROM method as it was a fun detour and may be applicable to more distributions)</p>

<h2 id="kernel">Kernel</h2>

<p>For first run, we&#39;ll use the mainline kernel.</p>

<blockquote><p>git clone <a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git" rel="nofollow">https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git</a>
cd linux
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig</p></blockquote>

<p>To avoid the need for messing around with initrd images which is a big waste of time when developing, we&#39;ll tweak the config in order to ensure everything we &#39;need&#39; is built in.</p>

<p>Not all of these are technically necessary but they will probably be helpful if you are developing CXL stuff.</p>

<blockquote><p>CONFIG<em>ACPI</em>HMAT=y
CONFIG<em>ACPI</em>APEI<em>PCIEAER=y
CONFIG</em>ACPI<em>HOTPLUG</em>MEMORY=y
CONFIG<em>MEMORY</em>HOTPLUG=y
CONFIG<em>MEMORY</em>HOTPLUG<em>DEFAULT</em>ONLINE=y
CONFIG<em>MEMORY</em>HOTREMOVE=y
CONFIG<em>CXL</em>BUS=y
CONFIG<em>CXL</em>MEM=y</p></blockquote>

<p>Build the kernel and copy it to our images directory</p>

<blockquote><p>make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
cp arch/arm64/boot/Image ~/images</p></blockquote>

<h2 id="qemu">QEMU</h2>

<p>The CXL emulation in QEMU is not yet upstream.  So get it from Ben Widawsky&#39;s gitlab.  He&#39;s been kind enough to include almost all the patches we need to support CXL on arm64.</p>

<blockquote><p>git clone <a href="https://gitlab.com/bwidawsk/qemu" rel="nofollow">https://gitlab.com/bwidawsk/qemu</a>
cd qemu</p></blockquote>

<p>Now make a small change that I haven&#39;t shared upstream yet.
Note there has been some discussion on the right way to fix this but no firm conclusions yet.
<a href="https://lore.kernel.org/qemu-devel/20210513124737.00002b2d@Huawei.com/" rel="nofollow">https://lore.kernel.org/qemu-devel/20210513124737.00002b2d@Huawei.com/</a></p>

<blockquote><p> Fix unaligned undersized access</p>

<p> Signed-off-by: Jonathan Cameron <a href="mailto:Jonathan.Cameron@huawei.com" rel="nofollow">Jonathan.Cameron@huawei.com</a>                                                                                             &gt; —-
softmmu/memory.c | 10 ++++++++—
1 file changed, 8 insertions(+), 2 deletions(–)</p>

<p>diff —git a/softmmu/memory.c b/softmmu/memory.c
index d4493ef9e4..11c1d54077 100644
—– a/softmmu/memory.c
+++ b/softmmu/memory.c
@@ -531,6 +531,7 @@ static MemTxResult access<em>with</em>adjusted<em>size(hwaddr addr,
     unsigned access</em>size;
     unsigned i;
     MemTxResult r = MEMTX<em>OK;
+    int offset = 0;
     if (!access</em>size<em>min) {
         access</em>size<em>min = 1;
 @@ -541,7 +542,12 @@ static MemTxResult access</em>with<em>adjusted</em>size(hwaddr addr,
/* FIXME: support unaligned access? */
    access<em>size = MAX(MIN(size, access</em>size<em>max), access</em>size<em>min);
–    access</em>mask = MAKE<em>64BIT</em>MASK(0, access<em>size * 8);<br>
+    if (access</em>size &gt; size) {
+        offset = (addr % access<em>size) * 8;
+        access</em>mask = MAKE<em>64BIT</em>MASK(offset, size * 8);
+    } else {
+        access<em>mask = MAKE</em>64BIT<em>MASK(0, access</em>size * 8);
+    }<br>
     if (memory<em>region</em>big<em>endian(mr)) {
        for (i = 0; i &lt; size; i += access</em>size) {
            r |= access<em>fn(mr, addr + i, value, access</em>size,
@@ -549,7 +555,7 @@ static MemTxResult access<em>with</em>adjusted<em>size(hwaddr addr,<br>
    } else {
        for (i = 0; i &lt; size; i += access</em>size) {
–            r |= access<em>fn(mr, addr + i, value, access</em>size, i * 8,
+            r |= access<em>fn(mr, addr – (addr % access</em>size) + i, value,
+                           access<em>size, -offset + i * 8,
                            access</em>mask, attrs);
         }
    }</p></blockquote>

<h3 id="build-qemu">Build QEMU</h3>

<blockquote><p>mkdir -p bin/native
cd bin/native
../../configure —target-list=aarch64-softmmu —disable-docs
make</p></blockquote>

<h3 id="booting-the-result">Booting the result</h3>

<blockquote><p>cd ~/src/images/
./qemu-system-aarch64 -M virt -m 4g,maxmem=8G,slots=8 -cpu max \
 -smp 4 -kernel Image -nographic -no-reboot \
 -bios QEMU<em>EFI.fd \
 -drive if=none,file=cxl.qcow2,format=qcow2,id=hd \
 -device virtio-blk-pci,drive=hd \
 -append &#39;root=/dev/vda1&#39; \
 -object memory-backend-ram,size=4G,id=mem0 \
 -numa node,nodeid=0,cpus=0-3,memdev=mem0 \
 -object memory-backend-file,id=cxl-mem1,share,mem-path=/tmp/cxltest.raw,size=2G,align=2G \
 -device pxb-cxl,bus</em>nr=128,id=cxl<em>bus1,uid=1,len-window-base=1,window-base[0]=0x4c0000000,memdev[0]=cxl-mem1 \
 -device cxl-rp,bus=cxl</em>bus1,id=cxl<em>rp,chassis=0,slot=1 \
 -device cxl-type3,bus=cxl</em>rp,memdev=cxl-mem1,lsa=cxl-mem1,id=cxl-mem0,size=2G</p></blockquote>

<p>Login is [username: root, password:]</p>

<p>You will probably want to be able to scp to the board later, so take this opportunity to generate host keys</p>

<blockquote><p>dpkg-reconfigure openssh-server
Also, make your image nice an insecure by editing
/etc/ssh/sshd_config</p></blockquote>

<p>To set</p>

<blockquote><p>PasswordAuthentication yes
PermitEmptyPassword  yes</p></blockquote>

<h2 id="data-object-exchange-support">Data Object Exchange support</h2>

<h3 id="qemu-1">QEMU</h3>

<p>Need the patches from Avery Design.
<a href="https://lore.kernel.org/qemu-devel/1619454964-10190-1-git-send-email-cbrowy@avery-design.com/" rel="nofollow">https://lore.kernel.org/qemu-devel/1619454964-10190-1-git-send-email-cbrowy@avery-design.com/</a></p>

<p>If using the b4 tool then</p>

<blockquote><p>b4 am -t  1619454964-10190-1-git-send-email-cbrowy@avery-design.com</p></blockquote>

<p>Will fetch the patches.  Note the final test data appears to be corrupt, so given we don&#39;t need it use</p>

<blockquote><p>git am —skip</p></blockquote>

<h3 id="kernel-1">Kernel</h3>

<p>Need the Data Object Exchange patches from
<a href="https://lore.kernel.org/linux-pci/20210524133938.2815206-1-Jonathan.Cameron@huawei.com/T/#t" rel="nofollow">https://lore.kernel.org/linux-pci/20210524133938.2815206-1-Jonathan.Cameron@huawei.com/T/#t</a></p>

<blockquote><p>b4 am -t 20210524133938.2815206-1-Jonathan.Cameron@huawei.com</p></blockquote>

<p>which apply to
<a href="https://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl.git/commit/?h=next&amp;id=35c32e3095d396c750f5cdfdaa94cba83d9b23c6" rel="nofollow">https://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl.git/commit/?h=next&amp;id=35c32e3095d396c750f5cdfdaa94cba83d9b23c6</a></p>

<p>These both enable CDAT access via /sys/bus/cxl/devices/mem0/CDAT and a IOCTL interface (which will probably never be merged) for which there is a doetest program in tools/pci/</p>

<p>Cross compile the doetest program and test the DOE with:</p>

<blockquote><p>$ ./doetest -f /dev/pcidoe/doe[0000:81:00.0]_190 -l
 VID: 0x1, Protocol 0
 VID: 0x1e98, Protocol 0x2</p></blockquote>
]]></content:encoded>
      <guid>https://people.kernel.org/jic23/howto-test-cxl-enablement-on-arm64-using-qemu</guid>
      <pubDate>Tue, 04 May 2021 11:27:57 +0000</pubDate>
    </item>
  </channel>
</rss>