| # Copyright 2026 The Pigweed Authors |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| # use this file except in compliance with the License. You may obtain a copy of |
| # the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| # License for the specific language governing permissions and limitations under |
| # the License. |
| """Rule for interactively running a QEMU system image using qemu_runner.""" |
| |
| load("//pw_kernel/tooling:system_image.bzl", "SystemImageInfo") |
| |
| def _qemu_run_impl(ctx): |
| runner = ctx.actions.declare_file(ctx.label.name + ".sh") |
| elf_file = ctx.attr.image[SystemImageInfo].elf |
| |
| uart_arg = "" |
| if ctx.attr.uart_tcp_port > 0: |
| uart_arg = " --uart-tcp-port {}".format(ctx.attr.uart_tcp_port) |
| |
| gdb_arg = "" |
| if ctx.attr.gdb_tcp_port > 0: |
| gdb_arg = " --gdb-tcp-port {}".format(ctx.attr.gdb_tcp_port) |
| |
| if ctx.attr.pause_for_gdb: |
| gdb_arg += " --gdb-pause" |
| |
| script = """#!/bin/sh |
| exec "{qemu_runner}" --cpu {cpu} --machine {machine} --semihosting --image "{image}"{uart_arg}{gdb_arg} "$@" |
| """.format( |
| qemu_runner = ctx.executable._qemu_runner.short_path, |
| cpu = ctx.attr.cpu, |
| machine = ctx.attr.machine, |
| image = elf_file.short_path, |
| uart_arg = uart_arg, |
| gdb_arg = gdb_arg, |
| ) |
| |
| ctx.actions.write( |
| output = runner, |
| content = script, |
| is_executable = True, |
| ) |
| |
| runfiles = ctx.runfiles(files = [elf_file]).merge( |
| ctx.attr._qemu_runner[DefaultInfo].default_runfiles, |
| ) |
| |
| return [ |
| DefaultInfo( |
| executable = runner, |
| runfiles = runfiles, |
| ), |
| ] |
| |
| qemu_runner = rule( |
| implementation = _qemu_run_impl, |
| executable = True, |
| attrs = { |
| "cpu": attr.string( |
| doc = "QEMU CPU type.", |
| mandatory = True, |
| ), |
| "gdb_tcp_port": attr.int( |
| doc = "Optional TCP port for gdb server.", |
| default = 0, |
| ), |
| "image": attr.label( |
| doc = "The system_image target to run.", |
| mandatory = True, |
| providers = [SystemImageInfo], |
| ), |
| "machine": attr.string( |
| doc = "QEMU machine type.", |
| mandatory = True, |
| ), |
| "pause_for_gdb": attr.bool( |
| doc = "If set, the guest will pause on startup.", |
| default = False, |
| ), |
| "uart_tcp_port": attr.int( |
| doc = "Optional TCP port for serial console redirection.", |
| default = 0, |
| ), |
| "_qemu_runner": attr.label( |
| default = "@pigweed//pw_kernel/tooling:qemu", |
| executable = True, |
| cfg = "target", |
| ), |
| }, |
| doc = "Runs a QEMU hardware target interactively.", |
| ) |