blob: 1e767d40c882cfac5002c8a84431abe91baa634f [file] [log] [blame]
#!/usr/bin/env python3
# Copyright (c) 2022 Project CHIP 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
#
# http://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.
import argparse
import logging
import os
import re
import shlex
import subprocess
import sys
# Absolute path to Tizen Studio CLI tool.
tizen_sdk_root = os.environ["TIZEN_SDK_ROOT"]
# Setup basic logging capabilities.
logging.basicConfig(level=logging.DEBUG)
parser = argparse.ArgumentParser(
description="Run Tizen on QEMU.")
parser.add_argument(
'-i', '--interactive', action='store_true',
help="run QEMU in interactive mode (no output redirection, no runner)")
parser.add_argument(
'--smp', metavar='NUM', type=int, default=2,
help=("the number of CPUs available in QEMU; default: %(default)s"))
parser.add_argument(
'--memory', metavar='SIZE', type=int, default=512,
help=("the size of RAM assigned to QEMU; default: %(default)s"))
parser.add_argument(
'--virtio-net', action='store_true',
help="enable external network access via virtio-net")
parser.add_argument(
'--kernel', metavar='PATH',
default=os.path.join(tizen_sdk_root, "iot-qemu-virt-zImage"),
help=("path to the kernel image; "
"default: $TIZEN_SDK_ROOT/iot-qemu-virt-zImage"))
parser.add_argument(
'--image-root', metavar='IMAGE',
default=os.path.join(tizen_sdk_root, "iot-rootfs.img"),
help=("path to the root image; "
"default: $TIZEN_SDK_ROOT/iot-rootfs.img"))
parser.add_argument(
'--image-data', metavar='IMAGE',
default=os.path.join(tizen_sdk_root, "iot-sysdata.img"),
help=("path to the system data image; "
"default: $TIZEN_SDK_ROOT/iot-sysdata.img"))
parser.add_argument(
'--image-iso', metavar='IMAGE',
help=("path to the ISO image with the runner script; the ISO image "
"should have 'CHIP' label and a file named 'runner.sh' at the "
"root directory"))
parser.add_argument(
'--output', metavar='FILE', default="/dev/null",
help="store the QEMU output in a FILE")
args = parser.parse_args()
qemu_args = [
'qemu-system-arm',
'-monitor', 'null',
'-serial', 'stdio',
'-display', 'none',
'-M', 'virt',
'-smp', str(args.smp),
'-m', str(args.memory),
]
if args.virtio_net:
# Add network support.
qemu_args += [
'-device', 'virtio-net-device,netdev=virtio-net',
'-netdev', 'user,id=virtio-net',
]
if args.image_iso:
# Add a block device for the runner ISO image.
qemu_args += [
'-device', 'virtio-blk-device,drive=virtio-blk3',
'-drive', 'file=%s,id=virtio-blk3,if=none,format=raw' % args.image_iso,
]
# Add Tizen image block devices.
qemu_args += [
'-device', 'virtio-blk-device,drive=virtio-blk2',
'-drive', 'file=%s,id=virtio-blk2,if=none,format=raw,readonly=on' % args.image_data,
# XXX: Device for the root image has to be added as the last one so we can
# use /dev/vda as the root device in the kernel command line arguments.
'-device', 'virtio-blk-device,drive=virtio-blk1',
'-drive', 'file=%s,id=virtio-blk1,if=none,format=raw,readonly=on' % args.image_root,
]
kernel_args = "console=ttyAMA0 earlyprintk earlycon root=/dev/vda"
if args.interactive:
# Run root shell instead of the runner script.
kernel_args += " rootshell"
qemu_args += [
'-kernel', args.kernel,
'-append', kernel_args,
]
if args.interactive:
# Run QEMU in interactive mode.
sys.exit(subprocess.call(qemu_args))
status = 0
# Run QEMU.
with open(args.output, "wb") as output:
logging.info("run: %s", " ".join(map(shlex.quote, qemu_args)))
with subprocess.Popen(qemu_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as proc:
for line in iter(proc.stdout.readline, b''):
# Forward the output to the stdout and the log file.
sys.stdout.write(line.decode(sys.stdout.encoding))
sys.stdout.flush()
output.write(line)
# Check if the runner script has finished and save the status.
stop = re.match(rb'^### RUNNER STOP: (?P<status>\d+)', line)
if stop:
status = int(stop.group('status'))
# Return with the status of the runner script.
sys.exit(status)