PetaLinux 101.
I built my first embedded Linux image: a KV260-targeted PetaLinux build from my own Vivado hardware export.
Goal
Take a KV260 Vivado design through PetaLinux and successfully generate a Linux image. This first experiment ends at the build output. Along the way I want to understand the what, where, how and why of bespoke builds in the context of embedded linux, and to get hands-on experience with the PetaLinux flow.
Methodology
I spent the session in front of two terminals: Codex in one, PetaLinux in the other, with Vivado open for the hardware design. I asked Codex to take me through a first image build, using the documentation to guide each step, and to document the process in HTML as we went. I wanted to run the tools myself and understand what they were doing. Looking up installer dependencies and finding the right download for an old shared library were jobs I was happy to give the agent.
The practical guidance came from that back-and-forth. When I needed to know which command to run, which flags it required or what to select in a menu, Codex looked it up and gave me the next step. It had access to documentation, MCP tools including the Vivado integration, and the project files on the same machine. I ran the commands and worked through the GUI, then returned terminal output and screenshots to the conversation. The agent could inspect the resulting configuration and files, so its guidance could follow the state of this build as well as the instructions in the manual.
I set the scope and pursued the questions that interested me, particularly while the build was running. Several explanations took repeated questioning before they addressed what I was trying to understand. Having the agent consult the actual recipes and output files helped here: I could ask about the system being built in the other terminal, rather than settle for a general account of embedded Linux. The discussion below follows those questions and the explanations we arrived at.
This page was also agent-generated during the session. I read the drafts and asked for several revisions to the tone, structure and emphasis, and edited some wording myself. The installation initially occupied far too much of the account, while the conceptual discussion and the agent’s role were understated. The resulting note reflects that editorial process as well as the build.
Installation
The agent found Vivado/Vitis 2025.2 already installed. It first tried their unified installer, then found that PetaLinux has a separate installer. I downloaded the 2025.2 .run, and the agent installed the missing Ubuntu build prerequisites. I reviewed the licences and completed the install in my own terminal. Its text said to “click Accept” in a text-only viewer; q closed the viewer and led to the terminal prompt.
What I actually learned so far: Ubuntu normally uses dash for /bin/sh. The agent initially overplayed that as a problem; we left the shell alone.
Choosing the target
The target was the KV260 because that is the board on my desk. The agent checked AMD’s BSP list, found no KV260 PetaLinux 2025.2 BSP listed, and used Vivado MCP to confirm that Vivado 2025.2 had the board definitions. We proceeded with a hardware export and a PetaLinux project created from the zynqMP template.
In Vivado I paired the KV260 SOM with its Vision AI Starter Kit carrier, added a Zynq UltraScale+ MPSoC block and applied the board preset. Validation failed: the preset enabled two PS-to-PL AXI interfaces with unconnected clocks. The agent found AMD’s PS-only remedy; I disabled the unused interfaces and validation passed. I exported design_1_wrapper.xsa, which the agent checked, then imported it into PetaLinux. I kept the detected UART and SD settings and got “Successfully configured project.”
source ~/AMDDesignTools/2025.2/PetaLinux/settings.sh
cd ~/Projects
petalinux-create project --template zynqMP --name kv260-linux
cd kv260-linux
# After creating and exporting the Vivado design under vivado/:
petalinux-config --get-hw-description vivado/design_1_wrapper.xsa
petalinux-build
The first build stopped before compilation because AMD’s XSCT tooling needed libtinfo.so.5. My attempt to install libtinfo-dev did not supply it; Codex found and checked the older Ubuntu runtime package, which I installed. The next attempt hit Ubuntu’s AppArmor restriction on BitBake’s user namespaces. We used AMD’s documented temporary workaround, and the agent later restored the original host setting. The build could finally run.
What is the build actually making?
While the build ran, I asked about the breakpoints between this fresh, template-based PetaLinux build and the ready-made Ubuntu Server 24.04 image offered for the KV260. I wanted to understand how the software above the kernel was selected and assembled, and what I would find if I logged into the resulting system.
Prior explanations I've encountered consistently attacked the wrong abstraction layer, and merely re-explained things I already knew. Codex initially did much the same, answering in containers—“kernel,” “root filesystem,” “packages”—without showing me what was inside them. I revised my questioning until it became clear what kind of answer I was looking for.
“Name a single piece of software being built right now.”
The selection included systemd for init and service management, BusyBox for basic commands, and OpenSSH for remote access. There were also mtd-utils, nfs-utils, pciutils, u-boot-tools, filesystem-making tools, kernel modules and a boot package group. The names made the next question much more precise: with hardware support already provided by kernel drivers, what do these userspace packages add to the image?
I took pciutils as an example. Its lspci command lets a person inspect PCI devices the kernel has already found; it is not the driver that operates them. The same distinction applies to the kernel’s MTD flash subsystem and mtd-utils, or to the ext filesystem driver and e2fsprogs-mke2fs, which creates a filesystem. NFS has work on both sides of the boundary. This gave me a way to read the package list: a package might supply a command, daemon, library, configuration or kernel module. Its name alone does not tell me which. u-boot-tools, for example, contains tools for working with U-Boot-related data, rather than U-Boot itself.
I then tested what the image would actually provide at a shell: ls and cat, GNU coreutils, Bash, a package manager? Menu selections alone could not answer all of those, because dependencies can pull software in indirectly. After the build, the manifest listed 250 installed packages, including systemd, BusyBox, OpenSSH, Bash and iproute2; the rootfs archive contained ls and cat. GNU coreutils and target package-manager commands such as apt, dnf, rpm and opkg did not appear as installed packages. The agent’s earlier suggestion that Bash might be absent was wrong. Checking the produced filesystem corrected it.
These explanations came out of a fairly persistent exchange with Codex. I could follow up on a particular package, ask it to inspect a file, or tell it that an answer still missed the distinction I was asking about. That was useful for a subject where I had found the usual introductions unsatisfying.
Inputs and process
I also asked what the XSA contributes when our block design has no PL logic or enabled PS-to-PL AXI master ports. The agent inspected the export: it contains PS initialization and hardware-description files, but no bitstream. The PS configuration still identifies DDR and peripherals such as UART, Ethernet, QSPI and SD. PetaLinux uses that information to generate platform configuration and a device tree; existing kernel drivers can then bind to the described PS devices. The XSA is not a driver, and there is no PL peripheral here for a custom driver to operate. Disabling those PS-to-PL ports did not disable every AXI-based connection inside the SoC.
Alongside that hardware export, the build takes a PetaLinux project configuration and an image recipe. PetaLinux invokes Yocto/BitBake to build the software. The recipes describe sources, versions, build steps and dependencies; BitBake resolves those dependencies, fetches source, cross-compiles for the target, makes packages and assembles a root filesystem. Our requested target was petalinux-image-minimal. “Minimal” is the recipe’s name, not a promise of a kernel plus one lonely process. Codex used Yocto’s image-generation model to explain the distinction between a recipe, a package and a finished image. Producing RPM packages as part of that process does not itself mean the target will have a package manager or a configured feed.
Why not a pre-built distribution?
The KV260-capable Ubuntu Server 24.04 image is a completed integration: board support, kernel, device tree, root filesystem, service policy and Ubuntu’s package/update machinery have already been selected and assembled. This PetaLinux project starts with the hardware export and a set of build recipes. Both images can contain Linux, systemd and OpenSSH, but their versions, kernel configuration, device tree, included packages, defaults and maintenance model need not match.
Working through this with the agent helped me locate the distinction I had been asking about. With the prebuilt image, the board integration and distribution choices arrive together. With PetaLinux, those choices are expressed in a project we can change and rebuild. For this first attempt we largely accepted the template’s selections; a product could choose its services, commands, filesystem contents and update strategy more narrowly. It would also take on the work of making those choices coherent and maintaining them.
To test the edge of that idea, I asked whether the entire userspace could be my own /init and nothing else. In principle, yes: a tiny initramfs with one statically linked program could omit systemd, shell, SSH and cat. The kernel would run it as PID 1, and it would have to stay alive. The board would still need its earlier boot stages and device tree. The kernel’s initramfs documentation describes that hand-off. We did not build that version, but the thought experiment made the kernel/distribution boundary much less fuzzy.
On the KV260, the boot firmware lives in SOM QSPI and U-Boot hands off to the carrier’s SD card; AMD’s boot overview shows another boundary that a compiled root filesystem alone cannot settle. Whether our template-derived image would boot is a separate experiment, not a condition of this one.
Unrelated field note: I nicked my thumb while cooking dinner. It bled rather a lot. This has no bearing on PetaLinux.
Result: my first embedded Linux image
The build ran for ~35 minutes and ended with exactly the message I had expected: 225 errors, nonzero exit code, failure. Of course it did. Then we looked. The agent checked the logs and found that every one of those errors concerned a missing shared-state cache entry; BitBake had fallen back to running the real task. The task summary reported 6,388 tasks attempted, 5,139 not needing a rerun, and all succeeded. In images/linux sat the kernel (Image), device tree (system.dtb), FIT image (image.ub), root filesystems and package manifest. The apparent failure was a detour through the cache, not the outcome of the build. I had built my first embedded Linux image. Tomorrow I will boot it.
□