Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/build-daily.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ on:

# implicitely set all other permissions to none
permissions:
checks: write # test.yml
contents: read # debos.yml test.yml
packages: read # test.yml
pull-requests: write # test.yml
checks: write # lava-test.yml
contents: read # debos.yml lava-test.yml
packages: read # lava-test.yml
pull-requests: write # lava-test.yml

jobs:
build-daily:
Expand All @@ -23,7 +23,7 @@ jobs:
test-daily:
# don't run cron from forks of the main repository or from other branches
if: github.repository == 'qualcomm-linux/qcom-deb-images' && github.ref == 'refs/heads/main'
uses: ./.github/workflows/test.yml
uses: ./.github/workflows/lava-test.yml
needs: build-daily
secrets: inherit
with:
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/build-on-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ on:

# implicitely set all other permissions to none
permissions:
checks: write # test.yml
contents: read # debos.yml lava-schema-check.yml test.yml
packages: read # test.yml
pull-requests: write # test.yml
checks: write # lava-test.yml
contents: read # debos.yml lava-schema-check.yml lava-test.yml
packages: read # lava-test.yml
pull-requests: write # lava-test.yml

jobs:
event-file:
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/build-on-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ on:

# implicitely set all other permissions to none
permissions:
checks: write # test.yml
contents: read # debos.yml lava-schema-check.yml test.yml
packages: read # test.yml
pull-requests: write # test.yml
checks: write # lava-test.yml
contents: read # debos.yml lava-schema-check.yml lava-test.yml
packages: read # lava-test.yml
pull-requests: write # lava-test.yml

jobs:
build-daily:
uses: ./.github/workflows/debos.yml
schema-check:
uses: ./.github/workflows/lava-schema-check.yml
test:
uses: ./.github/workflows/test.yml
uses: ./.github/workflows/lava-test.yml
needs: [build-daily, schema-check]
secrets: inherit
with:
Expand Down
13 changes: 11 additions & 2 deletions .github/workflows/debos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ jobs:
run: cp -av "/fileserver-downloads/qcom-deb-images/u-boot-rb1-latest/rb1-boot.img" .

# mtools is needed for the flash recipe
- name: Install debos and dependencies of the recipes
run: apt -y install debos mtools
- name: Install debos and dependencies of the recipes and local tests
run: apt -y install debos make mtools python3-pexpect python3-pytest qemu-efi-aarch64 qemu-system-arm

- name: Setup local APT repo
run: |
Expand Down Expand Up @@ -210,3 +210,12 @@ jobs:
with:
name: build_url
path: build_url
- name: Invoke test runner
run: |
# This is currently a clone of Makefile's "test" target to avoid any
# unexpected interactions with triggering depending build targets.
# The plan is to move this entire workflow to use make targets
# instead but all at once. See #74 and #159.

# rootfs/ is a build artifact, so should not be scanned for tests
py.test-3 --ignore=rootfs
File renamed without changes.
10 changes: 5 additions & 5 deletions .github/workflows/test-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ on:

# implicitely set all other permissions to none
permissions:
checks: write # test.yml EnricoMi/publish-unit-test-result-action
contents: read # test.yml actions/checkout
packages: read # test.yml actions/download-artifact
# test.yml EnricoMi/publish-unit-test-result-action
checks: write # lava-test.yml EnricoMi/publish-unit-test-result-action
contents: read # lava-test.yml actions/checkout
packages: read # lava-test.yml actions/download-artifact
# lava-test.yml EnricoMi/publish-unit-test-result-action
# thollander/actions-comment-pull-request
pull-requests: write

Expand Down Expand Up @@ -59,7 +59,7 @@ jobs:
echo "url=${BUILD_URL}" >> $GITHUB_OUTPUT

test:
uses: ./.github/workflows/test.yml
uses: ./.github/workflows/lava-test.yml
secrets: inherit
needs: retrieve-build-url
with:
Expand Down
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ all: disk-ufs.img.gz disk-sdcard.img.gz
rootfs.tar.gz: debos-recipes/qualcomm-linux-debian-rootfs.yaml
$(DEBOS) $<

disk-ufs.img.gz: debos-recipes/qualcomm-linux-debian-image.yaml rootfs.tar.gz
disk-ufs.img disk-ufs.img.gz: debos-recipes/qualcomm-linux-debian-image.yaml rootfs.tar.gz
$(DEBOS) $<

disk-sdcard.img.gz: debos-recipes/qualcomm-linux-debian-image.yaml rootfs.tar.gz
$(DEBOS) -t imagetype:sdcard $<

.PHONY: all
test: disk-ufs.img
# rootfs/ is a build artifact, so should not be scanned for tests
py.test-3 --ignore=rootfs

.PHONY: all test
70 changes: 70 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,76 @@ NB: It's also possible to run qdl from the host while the baord is not connected

Want to join in the development? Changes welcome! See [CONTRIBUTING.md file](CONTRIBUTING.md) for step by step instructions.

### Test an image locally with qemu

You can boot an image locally with qemu as follows:

1. Install dependencies. `qemu-system-arm` is required together with
an aarch64 build of UEFI. On Debian and Ubuntu, this is provided by the
`qemu-system-arm` package which recommends `qemu-efi-aarch64`:
```bash
sudo apt install qemu-system-arm qemu-efi-aarch64
```

1. As above under "Usage", build the disk image from the root filesystem
tarball if you haven't done this already:
```bash
debos debos-recipes/qualcomm-linux-debian-image.yaml
```

1. Run qemu as follows:
```bash
# SCSI is required to present a device with a matching 4096 sector size
# inside the VM
qemu-system-aarch64 -cpu cortex-a57 -m 2048 -M virt -nographic \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That made me wonder how we should define the QEMU model. We could pick it to be fast and manage it like a reference device that we maintain, or we could try to follow the most constrained environment we're trying to support. For the latter, the RB1 is probably the oldest board we're trying to enable, so 2GiB of RAM is fitting. I don't think QEMU has support for Kryo CPUs, so not sure what Cortex equivalent we should pick.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since have dedicated hardware tests, I imagine the qemu tests to be primarily for hardware agnostic matters and mainly for the purposes of testing userspace matters to be correct.

Strict constraints like memory and CPU features would still be important though, as we'd want to know if any use case we test is memory constrained in order to make appropriate decisions, or indeed built for a too-high CPU target. We could mark tests differently depending on their requirements (eg. if we want a standard image to have functionality that we know won't work on the oldest supported hardware, but we still want to test it).

So then we would want the model to be fast and with the most limited memory, but with the option of marking tests that require more to automatically get more. And we'd keep hardware-specific tests out of this test suite.

-device virtio-scsi-pci,id=scsi1 \
-device scsi-hd,bus=scsi1.0,drive=disk1,physical_block_size=4096,logical_block_size=4096 \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh that's cool! Makes me think we should (separately) make a test to check the SD card/eMMC images boot too (with the normal 512 bytes sector size)!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only did what was necessary to get the image we already had booting :)

Would an additional test be valuable here? The risk would be that something later works in qemu but fails on real hardware - in which case - why not just rely on the test against the real hardware?

I'm imagining the qemu test to be solely for testing the userspace-specific bits, and the hardware-specific bits (that interact most with qemu) to be a necessary distraction for that purpose that we should minimise. Then we can rely on the hardware tests for the hardware-specific bits.

-drive if=none,file=disk-ufs.img,format=raw,id=disk1 \
-bios /usr/share/AAVMF/AAVMF_CODE.fd
```

#### Copy on write

Instead of modifying `file-ufs.img`, you can arrange copy-on-write, for example
to reproduce the same first boot multiple times:

1. Prepare a qcow file to contain the writes, backed by `disk-ufs.img`:
```bash
qemu-img create -b disk-ufs.img -f qcow -F raw disk1.qcow
```

1. Run qemu as follows:
```bash
qemu-system-aarch64 -cpu cortex-a57 -m 2048 -M virt -nographic \
-device virtio-scsi-pci,id=scsi1 \
-device scsi-hd,bus=scsi1.0,drive=disk1,physical_block_size=4096,logical_block_size=4096 \
-drive if=none,file=disk1.img,format=qcow,id=disk1 \
-bios /usr/share/AAVMF/AAVMF_CODE.fd
```

#### Direct kernel boot

For debugging purposes, it is sometimes useful to boot the kernel directly, for
example to confirm that an issue in the image lies in the bootloader
installation. You can do this as follows:

1. Extract the rootfs:
```bash
mkdir rootfs
tar xzC rootfs -f rootfs.tar.gz
```

2. Run qemu against the kernel and initrd present inside the rootfs directly:
```bash
qemu-system-aarch64 -cpu cortex-a57 -m 2048 -M virt -nographic \
-device virtio-scsi-pci,id=scsi1 \
-device scsi-hd,bus=scsi1.0,drive=disk1,physical_block_size=4096,logical_block_size=4096 \
-drive if=none,file=disk-ufs.img,format=raw,id=disk1 \
-kernel rootfs/boot/vmlinuz-*
-initrd rootfs/boot/initrd.img-*
-append root=/dev/sda2
```

## Reporting Issues

We'd love to hear if you run into issues or have ideas for improvements. [Report an Issue on GitHub](../../issues) to discuss, and try to include as much information as possible on your specific environment.
Expand Down
6 changes: 6 additions & 0 deletions ci/lava/qcs6490-rb3gen2-core-kit/boot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,17 @@ actions:
password_prompt: 'Password'
password: debian
login_commands:
- "debian"
- "new password"
- "new password"
- sudo su
method: minimal
prompts:
- root@debian
- debian@debian
- "Current password"
- "New password"
- "Retype new password"
timeout:
minutes: 3
- test:
Expand Down
6 changes: 6 additions & 0 deletions ci/lava/qrb2210-rb1/boot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,17 @@ actions:
password_prompt: 'Password'
password: debian
login_commands:
- "debian"
- "new password"
- "new password"
- sudo su
method: minimal
prompts:
- root@debian
- debian@debian
- "Current password"
- "New password"
- "Retype new password"
timeout:
minutes: 3
- test:
Expand Down
82 changes: 82 additions & 0 deletions ci/qemu_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"""Tests that are entirely qemu based, so do not require test hardware"""

# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
# SPDX-License-Identifier: BSD-3-Clause

import os
import signal
import subprocess
import tempfile

import pexpect
import pytest


@pytest.fixture
def vm():
"""A pexpect.spawn object attached to the serial console of a VM freshly
booting with a CoW base of disk-ufs.img"""
with tempfile.TemporaryDirectory() as tmpdir:
qcow_path = os.path.join(tmpdir, "disk1.qcow")
subprocess.run(
[
"qemu-img",
"create",
"-b",
os.path.join(os.getcwd(), "disk-ufs.img"),
"-f",
"qcow",
"-F",
"raw",
qcow_path,
],
check=True,
)
child = pexpect.spawn(
"qemu-system-aarch64",
[
"-cpu",
"cortex-a57",
"-m",
"2048",
"-M",
"virt",
"-drive",
f"if=none,file={qcow_path},format=qcow,id=disk1",
"-device",
"virtio-scsi-pci,id=scsi1",
"-device",
"scsi-hd,bus=scsi1.0,drive=disk1,physical_block_size=4096,logical_block_size=4096",
"-nographic",
"-bios",
"/usr/share/AAVMF/AAVMF_CODE.fd",
],
)
yield child

# No need to be nice; that would take time
child.kill(signal.SIGKILL)

# If this blocks then we have a problem. Better to hang than build up
# excess qemu processes that won't die.
child.wait()


def test_password_reset_required(vm):
"""On first login, there should be a mandatory reset password flow"""
# https://github.com/qualcomm-linux/qcom-deb-images/issues/69

# This takes a minute or two on a ThinkPad T14s Gen 6 Snapdragon
vm.expect_exact("debian login:", timeout=240)

vm.send("debian\r\n")
vm.expect_exact("Password:")
vm.send("debian\r\n")
vm.expect_exact("You are required to change your password immediately")
vm.expect_exact("Current password:")
vm.send("debian\r\n")
vm.expect_exact("New password:")
vm.send("new password\r\n")
vm.expect_exact("Retype new password:")
vm.send("new password\r\n")
vm.expect_exact("debian@debian:~$")
4 changes: 2 additions & 2 deletions debos-recipes/qualcomm-linux-debian-image.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,9 @@ actions:
done
- action: run
description: Compress image file
description: Add compressed image file
postprocess: true
command: gzip -v -f "${ARTIFACTDIR}/{{ $image }}"
command: gzip -v -f -k "${ARTIFACTDIR}/{{ $image }}"

# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
# SPDX-License-Identifier: BSD-3-Clause
5 changes: 3 additions & 2 deletions debos-recipes/qualcomm-linux-debian-rootfs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,10 @@ actions:
# session has not updated ACLs to the device nodes
useradd --create-home --shell /bin/bash --user-group \
--groups adm,audio,render,sudo,users,video debian
# password must be changed on first login; set it to "debian"
chage --lastday 0 debian
# set password to "debian"
echo debian:debian | chpasswd
# password must be changed on first login
chage --lastday 0 debian
# add to sudoers
mkdir -v --mode 755 --parents /etc/sudoers.d
# subshell to override umask
Expand Down
Loading