Testing, guest-loader and other misc tweaks
- add warning text to quickstart example - add CFI tests to CI - use --arch-only for docker pre-requisites - fix .editorconfig for emacs - add guest-loader for Xen-like hypervisor testing - move generic-loader docs into manual proper - move semihosting out of hw/ -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmBI50MACgkQ+9DbCVqe KkSyKggAhPZW+7sReVEsFdnVfwuo3evW7auoW44mghNbikTnm3RfoahYTrek8lGZ AEo2gFMbzENW0j88e0OvSYYtwkVz3sD68bygfXerti6sQwWlwkf42I/suWjJNLph oVKGEEdJess9+zR13Cu6RAq5RaTwzDPGPjUwTbeJPpAps4+UZV3hsxhaxs8keII6 GBa/idnh0qEApP2NDLKiSASrYZM7xGvljE7zO4qhchd6iSH/o5rCtkoB2tRCcXGo +KF8LyBsUNf7GiWp0yYZMZUQ3Pqskqma8N3d2A4UlS1kXvxeX/FiORkG/Ne8bH1Z VZ1Z/xbyXGlVkiP1bcoYSc6XWHNDTw== =R9zQ -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-docs-xen-updates-100321-2' into staging Testing, guest-loader and other misc tweaks - add warning text to quickstart example - add CFI tests to CI - use --arch-only for docker pre-requisites - fix .editorconfig for emacs - add guest-loader for Xen-like hypervisor testing - move generic-loader docs into manual proper - move semihosting out of hw/ # gpg: Signature made Wed 10 Mar 2021 15:35:31 GMT # gpg: using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44 # gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [full] # Primary key fingerprint: 6685 AE99 E751 67BC AFC8 DF35 FBD0 DB09 5A9E 2A44 * remotes/stsquad/tags/pull-testing-docs-xen-updates-100321-2: semihosting: Move hw/semihosting/ -> semihosting/ semihosting: Move include/hw/semihosting/ -> include/semihosting/ tests/avocado: add boot_xen tests docs: add some documentation for the guest-loader docs: move generic-loader documentation into the main manual hw/core: implement a guest-loader to support static hypervisor guests device_tree: add qemu_fdt_setprop_string_array helper hw/riscv: migrate fdt field to generic MachineState hw/board: promote fdt from ARM VirtMachineState to MachineState .editorconfig: update the automatic mode setting for Emacs tests/docker: Use --arch-only when building Debian cross image gitlab-ci.yml: Add jobs to test CFI flags gitlab-ci.yml: Allow custom # of parallel linkers tests/docker: add a test-tcg for building then running check-tcg docs/system: add a gentle prompt for the complexity to come Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
f4abdf3271
@ -4,6 +4,11 @@
|
||||
# plugin.
|
||||
#
|
||||
# Check https://editorconfig.org for details.
|
||||
#
|
||||
# Emacs: you need https://github.com/10sr/editorconfig-custom-majormode-el
|
||||
# to automatically enable the appropriate major-mode for your files
|
||||
# that aren't already caught by your existing config.
|
||||
#
|
||||
|
||||
root = true
|
||||
|
||||
@ -15,17 +20,17 @@ charset = utf-8
|
||||
[*.mak]
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
file_type_emacs = makefile
|
||||
emacs_mode = makefile
|
||||
|
||||
[Makefile*]
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
file_type_emacs = makefile
|
||||
emacs_mode = makefile
|
||||
|
||||
[*.{c,h,c.inc,h.inc}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
file_type_emacs = c
|
||||
emacs_mode = c
|
||||
|
||||
[*.sh]
|
||||
indent_style = space
|
||||
@ -34,11 +39,11 @@ indent_size = 4
|
||||
[*.{s,S}]
|
||||
indent_style = tab
|
||||
indent_size = 8
|
||||
file_type_emacs = asm
|
||||
emacs_mode = asm
|
||||
|
||||
[*.{vert,frag}]
|
||||
file_type_emacs = glsl
|
||||
emacs_mode = glsl
|
||||
|
||||
[*.json]
|
||||
indent_style = space
|
||||
file_type_emacs = python
|
||||
emacs_mode = python
|
||||
|
123
.gitlab-ci.yml
123
.gitlab-ci.yml
@ -27,6 +27,10 @@ include:
|
||||
else
|
||||
../configure --enable-werror $CONFIGURE_ARGS ;
|
||||
fi || { cat config.log meson-logs/meson-log.txt && exit 1; }
|
||||
- if test -n "$LD_JOBS";
|
||||
then
|
||||
meson configure . -Dbackend_max_links="$LD_JOBS" ;
|
||||
fi || exit 1;
|
||||
- make -j"$JOBS"
|
||||
- if test -n "$MAKE_CHECK_ARGS";
|
||||
then
|
||||
@ -481,6 +485,125 @@ clang-user:
|
||||
--extra-cflags=-fsanitize=undefined --extra-cflags=-fno-sanitize-recover=undefined
|
||||
MAKE_CHECK_ARGS: check-unit check-tcg
|
||||
|
||||
# Set LD_JOBS=1 because this requires LTO and ld consumes a large amount of memory.
|
||||
# On gitlab runners, default value sometimes end up calling 2 lds concurrently and
|
||||
# triggers an Out-Of-Memory error
|
||||
#
|
||||
# Since slirp callbacks are used in QEMU Timers, slirp needs to be compiled together
|
||||
# with QEMU and linked as a static library to avoid false positives in CFI checks.
|
||||
# This can be accomplished by using -enable-slirp=git, which avoids the use of
|
||||
# a system-wide version of the library
|
||||
#
|
||||
# Split in three sets of build/check/acceptance to limit the execution time of each
|
||||
# job
|
||||
build-cfi-aarch64:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
- job: amd64-fedora-container
|
||||
variables:
|
||||
LD_JOBS: 1
|
||||
AR: llvm-ar
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
||||
--enable-safe-stack --enable-slirp=git
|
||||
TARGETS: aarch64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-cfi-aarch64:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-aarch64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-cfi-aarch64:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-aarch64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-cfi-ppc64-s390x:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
- job: amd64-fedora-container
|
||||
variables:
|
||||
LD_JOBS: 1
|
||||
AR: llvm-ar
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
||||
--enable-safe-stack --enable-slirp=git
|
||||
TARGETS: ppc64-softmmu s390x-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-cfi-ppc64-s390x:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-ppc64-s390x
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-cfi-ppc64-s390x:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-ppc64-s390x
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
build-cfi-x86_64:
|
||||
<<: *native_build_job_definition
|
||||
needs:
|
||||
- job: amd64-fedora-container
|
||||
variables:
|
||||
LD_JOBS: 1
|
||||
AR: llvm-ar
|
||||
IMAGE: fedora
|
||||
CONFIGURE_ARGS: --cc=clang --cxx=clang++ --enable-cfi --enable-cfi-debug
|
||||
--enable-safe-stack --enable-slirp=git
|
||||
TARGETS: x86_64-softmmu
|
||||
MAKE_CHECK_ARGS: check-build
|
||||
artifacts:
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
|
||||
check-cfi-x86_64:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-x86_64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check
|
||||
|
||||
acceptance-cfi-x86_64:
|
||||
<<: *native_test_job_definition
|
||||
needs:
|
||||
- job: build-cfi-x86_64
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-acceptance
|
||||
<<: *acceptance_definition
|
||||
|
||||
tsan-build:
|
||||
<<: *native_build_job_definition
|
||||
variables:
|
||||
|
1
Kconfig
1
Kconfig
@ -2,3 +2,4 @@ source Kconfig.host
|
||||
source backends/Kconfig
|
||||
source accel/Kconfig
|
||||
source hw/Kconfig
|
||||
source semihosting/Kconfig
|
||||
|
13
MAINTAINERS
13
MAINTAINERS
@ -2027,7 +2027,14 @@ M: Alistair Francis <alistair@alistair23.me>
|
||||
S: Maintained
|
||||
F: hw/core/generic-loader.c
|
||||
F: include/hw/core/generic-loader.h
|
||||
F: docs/generic-loader.txt
|
||||
F: docs/system/generic-loader.rst
|
||||
|
||||
Guest Loader
|
||||
M: Alex Bennée <alex.bennee@linaro.org>
|
||||
S: Maintained
|
||||
F: hw/core/guest-loader.c
|
||||
F: docs/system/guest-loader.rst
|
||||
F: tests/acceptance/boot_xen.py
|
||||
|
||||
Intel Hexadecimal Object File Loader
|
||||
M: Su Hang <suhang16@mails.ucas.ac.cn>
|
||||
@ -3255,8 +3262,8 @@ F: qapi/rdma.json
|
||||
Semihosting
|
||||
M: Alex Bennée <alex.bennee@linaro.org>
|
||||
S: Maintained
|
||||
F: hw/semihosting/
|
||||
F: include/hw/semihosting/
|
||||
F: semihosting/
|
||||
F: include/semihosting/
|
||||
|
||||
Multi-process QEMU
|
||||
M: Elena Ufimtseva <elena.ufimtseva@oracle.com>
|
||||
|
@ -1,92 +0,0 @@
|
||||
Copyright (c) 2016 Xilinx Inc.
|
||||
|
||||
This work is licensed under the terms of the GNU GPL, version 2 or later. See
|
||||
the COPYING file in the top-level directory.
|
||||
|
||||
|
||||
The 'loader' device allows the user to load multiple images or values into
|
||||
QEMU at startup.
|
||||
|
||||
Loading Data into Memory Values
|
||||
-------------------------------
|
||||
The loader device allows memory values to be set from the command line. This
|
||||
can be done by following the syntax below:
|
||||
|
||||
-device loader,addr=<addr>,data=<data>,data-len=<data-len>
|
||||
[,data-be=<data-be>][,cpu-num=<cpu-num>]
|
||||
|
||||
<addr> - The address to store the data in.
|
||||
<data> - The value to be written to the address. The maximum size of
|
||||
the data is 8 bytes.
|
||||
<data-len> - The length of the data in bytes. This argument must be
|
||||
included if the data argument is.
|
||||
<data-be> - Set to true if the data to be stored on the guest should be
|
||||
written as big endian data. The default is to write little
|
||||
endian data.
|
||||
<cpu-num> - The number of the CPU's address space where the data should
|
||||
be loaded. If not specified the address space of the first
|
||||
CPU is used.
|
||||
|
||||
All values are parsed using the standard QemuOps parsing. This allows the user
|
||||
to specify any values in any format supported. By default the values
|
||||
will be parsed as decimal. To use hex values the user should prefix the number
|
||||
with a '0x'.
|
||||
|
||||
An example of loading value 0x8000000e to address 0xfd1a0104 is:
|
||||
-device loader,addr=0xfd1a0104,data=0x8000000e,data-len=4
|
||||
|
||||
Setting a CPU's Program Counter
|
||||
-------------------------------
|
||||
The loader device allows the CPU's PC to be set from the command line. This
|
||||
can be done by following the syntax below:
|
||||
|
||||
-device loader,addr=<addr>,cpu-num=<cpu-num>
|
||||
|
||||
<addr> - The value to use as the CPU's PC.
|
||||
<cpu-num> - The number of the CPU whose PC should be set to the
|
||||
specified value.
|
||||
|
||||
All values are parsed using the standard QemuOps parsing. This allows the user
|
||||
to specify any values in any format supported. By default the values
|
||||
will be parsed as decimal. To use hex values the user should prefix the number
|
||||
with a '0x'.
|
||||
|
||||
An example of setting CPU 0's PC to 0x8000 is:
|
||||
-device loader,addr=0x8000,cpu-num=0
|
||||
|
||||
Loading Files
|
||||
-------------
|
||||
The loader device also allows files to be loaded into memory. It can load ELF,
|
||||
U-Boot, and Intel HEX executable formats as well as raw images. The syntax is
|
||||
shown below:
|
||||
|
||||
-device loader,file=<file>[,addr=<addr>][,cpu-num=<cpu-num>][,force-raw=<raw>]
|
||||
|
||||
<file> - A file to be loaded into memory
|
||||
<addr> - The memory address where the file should be loaded. This is
|
||||
required for raw images and ignored for non-raw files.
|
||||
<cpu-num> - This specifies the CPU that should be used. This is an
|
||||
optional argument and will cause the CPU's PC to be set to
|
||||
the memory address where the raw file is loaded or the entry
|
||||
point specified in the executable format header. This option
|
||||
should only be used for the boot image.
|
||||
This will also cause the image to be written to the specified
|
||||
CPU's address space. If not specified, the default is CPU 0.
|
||||
<force-raw> - Setting force-raw=on forces the file to be treated as a raw
|
||||
image. This can be used to load supported executable formats
|
||||
as if they were raw.
|
||||
|
||||
All values are parsed using the standard QemuOps parsing. This allows the user
|
||||
to specify any values in any format supported. By default the values
|
||||
will be parsed as decimal. To use hex values the user should prefix the number
|
||||
with a '0x'.
|
||||
|
||||
An example of loading an ELF file which CPU0 will boot is shown below:
|
||||
-device loader,file=./images/boot.elf,cpu-num=0
|
||||
|
||||
Restrictions and ToDos
|
||||
----------------------
|
||||
- At the moment it is just assumed that if you specify a cpu-num then you
|
||||
want to set the PC as well. This might not always be the case. In future
|
||||
the internal state 'set_pc' (which exists in the generic loader now) should
|
||||
be exposed to the user so that they can choose if the PC is set or not.
|
117
docs/system/generic-loader.rst
Normal file
117
docs/system/generic-loader.rst
Normal file
@ -0,0 +1,117 @@
|
||||
..
|
||||
Copyright (c) 2016, Xilinx Inc.
|
||||
|
||||
This work is licensed under the terms of the GNU GPL, version 2 or later. See
|
||||
the COPYING file in the top-level directory.
|
||||
|
||||
Generic Loader
|
||||
--------------
|
||||
|
||||
The 'loader' device allows the user to load multiple images or values into
|
||||
QEMU at startup.
|
||||
|
||||
Loading Data into Memory Values
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The loader device allows memory values to be set from the command line. This
|
||||
can be done by following the syntax below::
|
||||
|
||||
-device loader,addr=<addr>,data=<data>,data-len=<data-len> \
|
||||
[,data-be=<data-be>][,cpu-num=<cpu-num>]
|
||||
|
||||
``<addr>``
|
||||
The address to store the data in.
|
||||
|
||||
``<data>``
|
||||
The value to be written to the address. The maximum size of the data
|
||||
is 8 bytes.
|
||||
|
||||
``<data-len>``
|
||||
The length of the data in bytes. This argument must be included if
|
||||
the data argument is.
|
||||
|
||||
``<data-be>``
|
||||
Set to true if the data to be stored on the guest should be written
|
||||
as big endian data. The default is to write little endian data.
|
||||
|
||||
``<cpu-num>``
|
||||
The number of the CPU's address space where the data should be
|
||||
loaded. If not specified the address space of the first CPU is used.
|
||||
|
||||
All values are parsed using the standard QemuOps parsing. This allows the user
|
||||
to specify any values in any format supported. By default the values
|
||||
will be parsed as decimal. To use hex values the user should prefix the number
|
||||
with a '0x'.
|
||||
|
||||
An example of loading value 0x8000000e to address 0xfd1a0104 is::
|
||||
|
||||
-device loader,addr=0xfd1a0104,data=0x8000000e,data-len=4
|
||||
|
||||
Setting a CPU's Program Counter
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The loader device allows the CPU's PC to be set from the command line. This
|
||||
can be done by following the syntax below::
|
||||
|
||||
-device loader,addr=<addr>,cpu-num=<cpu-num>
|
||||
|
||||
``<addr>``
|
||||
The value to use as the CPU's PC.
|
||||
|
||||
``<cpu-num>``
|
||||
The number of the CPU whose PC should be set to the specified value.
|
||||
|
||||
All values are parsed using the standard QemuOpts parsing. This allows the user
|
||||
to specify any values in any format supported. By default the values
|
||||
will be parsed as decimal. To use hex values the user should prefix the number
|
||||
with a '0x'.
|
||||
|
||||
An example of setting CPU 0's PC to 0x8000 is::
|
||||
|
||||
-device loader,addr=0x8000,cpu-num=0
|
||||
|
||||
Loading Files
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
The loader device also allows files to be loaded into memory. It can load ELF,
|
||||
U-Boot, and Intel HEX executable formats as well as raw images. The syntax is
|
||||
shown below:
|
||||
|
||||
-device loader,file=<file>[,addr=<addr>][,cpu-num=<cpu-num>][,force-raw=<raw>]
|
||||
|
||||
``<file>``
|
||||
A file to be loaded into memory
|
||||
|
||||
``<addr>``
|
||||
The memory address where the file should be loaded. This is required
|
||||
for raw images and ignored for non-raw files.
|
||||
|
||||
``<cpu-num>``
|
||||
This specifies the CPU that should be used. This is an
|
||||
optional argument and will cause the CPU's PC to be set to the
|
||||
memory address where the raw file is loaded or the entry point
|
||||
specified in the executable format header. This option should only
|
||||
be used for the boot image. This will also cause the image to be
|
||||
written to the specified CPU's address space. If not specified, the
|
||||
default is CPU 0. <force-raw> - Setting force-raw=on forces the file
|
||||
to be treated as a raw image. This can be used to load supported
|
||||
executable formats as if they were raw.
|
||||
|
||||
All values are parsed using the standard QemuOpts parsing. This allows the user
|
||||
to specify any values in any format supported. By default the values
|
||||
will be parsed as decimal. To use hex values the user should prefix the number
|
||||
with a '0x'.
|
||||
|
||||
An example of loading an ELF file which CPU0 will boot is shown below::
|
||||
|
||||
-device loader,file=./images/boot.elf,cpu-num=0
|
||||
|
||||
Restrictions and ToDos
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
At the moment it is just assumed that if you specify a cpu-num then
|
||||
you want to set the PC as well. This might not always be the case. In
|
||||
future the internal state 'set_pc' (which exists in the generic loader
|
||||
now) should be exposed to the user so that they can choose if the PC
|
||||
is set or not.
|
||||
|
||||
|
54
docs/system/guest-loader.rst
Normal file
54
docs/system/guest-loader.rst
Normal file
@ -0,0 +1,54 @@
|
||||
..
|
||||
Copyright (c) 2020, Linaro
|
||||
|
||||
Guest Loader
|
||||
------------
|
||||
|
||||
The guest loader is similar to the `generic-loader` although it is
|
||||
aimed at a particular use case of loading hypervisor guests. This is
|
||||
useful for debugging hypervisors without having to jump through the
|
||||
hoops of firmware and boot-loaders.
|
||||
|
||||
The guest loader does two things:
|
||||
|
||||
- load blobs (kernels and initial ram disks) into memory
|
||||
- sets platform FDT data so hypervisors can find and boot them
|
||||
|
||||
This is what is typically done by a boot-loader like grub using it's
|
||||
multi-boot capability. A typical example would look like:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
|qemu_system| -kernel ~/xen.git/xen/xen \
|
||||
-append "dom0_mem=1G,max:1G loglvl=all guest_loglvl=all" \
|
||||
-device guest-loader,addr=0x42000000,kernel=Image,bootargs="root=/dev/sda2 ro console=hvc0 earlyprintk=xen" \
|
||||
-device guest-loader,addr=0x47000000,initrd=rootfs.cpio
|
||||
|
||||
In the above example the Xen hypervisor is loaded by the -kernel
|
||||
parameter and passed it's boot arguments via -append. The Dom0 guest
|
||||
is loaded into the areas of memory. Each blob will get
|
||||
`/chosen/module@<addr>` entry in the FDT to indicate it's location and
|
||||
size. Additional information can be passed with by using additional
|
||||
arguments.
|
||||
|
||||
Currently the only supported machines which use FDT data to boot are
|
||||
the ARM and RiscV `virt` machines.
|
||||
|
||||
Arguments
|
||||
^^^^^^^^^
|
||||
|
||||
The full syntax of the guest-loader is::
|
||||
|
||||
-device guest-loader,addr=<addr>[,kernel=<file>,[bootargs=<args>]][,initrd=<file>]
|
||||
|
||||
``addr=<addr>``
|
||||
This is mandatory and indicates the start address of the blob.
|
||||
|
||||
``kernel|initrd=<file>``
|
||||
Indicates the filename of the kernel or initrd blob. Both blobs will
|
||||
have the "multiboot,module" compatibility string as well as
|
||||
"multiboot,kernel" or "multiboot,ramdisk" as appropriate.
|
||||
|
||||
``bootargs=<args>``
|
||||
This is an optional field for kernel blobs which will pass command
|
||||
like via the `/chosen/module@<addr>/bootargs` node.
|
@ -25,6 +25,8 @@ Contents:
|
||||
usb
|
||||
ivshmem
|
||||
linuxboot
|
||||
generic-loader
|
||||
guest-loader
|
||||
vnc-security
|
||||
tls
|
||||
gdb
|
||||
|
@ -11,3 +11,11 @@ Download and uncompress a PC hard disk image with Linux installed (e.g.
|
||||
|qemu_system| linux.img
|
||||
|
||||
Linux should boot and give you a prompt.
|
||||
|
||||
Users should be aware the above example elides a lot of the complexity
|
||||
of setting up a VM with x86_64 specific defaults and assumes the
|
||||
first non switch argument is a PC compatible disk image with a boot
|
||||
sector. For a non-x86 system where we emulate a broad range of machine
|
||||
types, the command lines are generally more explicit in defining the
|
||||
machine and boot behaviour. You will find more example command lines
|
||||
in the :ref:`system-targets-ref` section of the manual.
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _system-targets-ref:
|
||||
|
||||
QEMU System Emulator Targets
|
||||
============================
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "sysemu/replay.h"
|
||||
|
||||
|
@ -31,7 +31,6 @@ source remote/Kconfig
|
||||
source rtc/Kconfig
|
||||
source scsi/Kconfig
|
||||
source sd/Kconfig
|
||||
source semihosting/Kconfig
|
||||
source smbios/Kconfig
|
||||
source ssi/Kconfig
|
||||
source timer/Kconfig
|
||||
|
356
hw/arm/virt.c
356
hw/arm/virt.c
@ -218,14 +218,14 @@ static bool cpu_type_valid(const char *cpu)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void create_kaslr_seed(VirtMachineState *vms, const char *node)
|
||||
static void create_kaslr_seed(MachineState *ms, const char *node)
|
||||
{
|
||||
uint64_t seed;
|
||||
|
||||
if (qemu_guest_getrandom(&seed, sizeof(seed), NULL)) {
|
||||
return;
|
||||
}
|
||||
qemu_fdt_setprop_u64(vms->fdt, node, "kaslr-seed", seed);
|
||||
qemu_fdt_setprop_u64(ms->fdt, node, "kaslr-seed", seed);
|
||||
}
|
||||
|
||||
static void create_fdt(VirtMachineState *vms)
|
||||
@ -239,7 +239,7 @@ static void create_fdt(VirtMachineState *vms)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
vms->fdt = fdt;
|
||||
ms->fdt = fdt;
|
||||
|
||||
/* Header */
|
||||
qemu_fdt_setprop_string(fdt, "/", "compatible", "linux,dummy-virt");
|
||||
@ -248,11 +248,11 @@ static void create_fdt(VirtMachineState *vms)
|
||||
|
||||
/* /chosen must exist for load_dtb to fill in necessary properties later */
|
||||
qemu_fdt_add_subnode(fdt, "/chosen");
|
||||
create_kaslr_seed(vms, "/chosen");
|
||||
create_kaslr_seed(ms, "/chosen");
|
||||
|
||||
if (vms->secure) {
|
||||
qemu_fdt_add_subnode(fdt, "/secure-chosen");
|
||||
create_kaslr_seed(vms, "/secure-chosen");
|
||||
create_kaslr_seed(ms, "/secure-chosen");
|
||||
}
|
||||
|
||||
/* Clock node, for the benefit of the UART. The kernel device tree
|
||||
@ -316,6 +316,7 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms)
|
||||
ARMCPU *armcpu;
|
||||
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
|
||||
uint32_t irqflags = GIC_FDT_IRQ_FLAGS_LEVEL_HI;
|
||||
MachineState *ms = MACHINE(vms);
|
||||
|
||||
if (vmc->claim_edge_triggered_timers) {
|
||||
irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI;
|
||||
@ -327,19 +328,19 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms)
|
||||
(1 << MACHINE(vms)->smp.cpus) - 1);
|
||||
}
|
||||
|
||||
qemu_fdt_add_subnode(vms->fdt, "/timer");
|
||||
qemu_fdt_add_subnode(ms->fdt, "/timer");
|
||||
|
||||
armcpu = ARM_CPU(qemu_get_cpu(0));
|
||||
if (arm_feature(&armcpu->env, ARM_FEATURE_V8)) {
|
||||
const char compat[] = "arm,armv8-timer\0arm,armv7-timer";
|
||||
qemu_fdt_setprop(vms->fdt, "/timer", "compatible",
|
||||
qemu_fdt_setprop(ms->fdt, "/timer", "compatible",
|
||||
compat, sizeof(compat));
|
||||
} else {
|
||||
qemu_fdt_setprop_string(vms->fdt, "/timer", "compatible",
|
||||
qemu_fdt_setprop_string(ms->fdt, "/timer", "compatible",
|
||||
"arm,armv7-timer");
|
||||
}
|
||||
qemu_fdt_setprop(vms->fdt, "/timer", "always-on", NULL, 0);
|
||||
qemu_fdt_setprop_cells(vms->fdt, "/timer", "interrupts",
|
||||
qemu_fdt_setprop(ms->fdt, "/timer", "always-on", NULL, 0);
|
||||
qemu_fdt_setprop_cells(ms->fdt, "/timer", "interrupts",
|
||||
GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_S_EL1_IRQ, irqflags,
|
||||
GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL1_IRQ, irqflags,
|
||||
GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_VIRT_IRQ, irqflags,
|
||||
@ -375,35 +376,35 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
|
||||
}
|
||||
}
|
||||
|
||||
qemu_fdt_add_subnode(vms->fdt, "/cpus");
|
||||
qemu_fdt_setprop_cell(vms->fdt, "/cpus", "#address-cells", addr_cells);
|
||||
qemu_fdt_setprop_cell(vms->fdt, "/cpus", "#size-cells", 0x0);
|
||||
qemu_fdt_add_subnode(ms->fdt, "/cpus");
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", addr_cells);
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
|
||||
|
||||
for (cpu = smp_cpus - 1; cpu >= 0; cpu--) {
|
||||
char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
|
||||
ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
|
||||
CPUState *cs = CPU(armcpu);
|
||||
|
||||
qemu_fdt_add_subnode(vms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "device_type", "cpu");
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "compatible",
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu");
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
|
||||
armcpu->dtb_compatible);
|
||||
|
||||
if (vms->psci_conduit != QEMU_PSCI_CONDUIT_DISABLED && smp_cpus > 1) {
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename,
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename,
|
||||
"enable-method", "psci");
|
||||
}
|
||||
|
||||
if (addr_cells == 2) {
|
||||
qemu_fdt_setprop_u64(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_setprop_u64(ms->fdt, nodename, "reg",
|
||||
armcpu->mp_affinity);
|
||||
} else {
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "reg",
|
||||
armcpu->mp_affinity);
|
||||
}
|
||||
|
||||
if (ms->possible_cpus->cpus[cs->cpu_index].props.has_node_id) {
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "numa-node-id",
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id",
|
||||
ms->possible_cpus->cpus[cs->cpu_index].props.node_id);
|
||||
}
|
||||
|
||||
@ -414,71 +415,74 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
|
||||
static void fdt_add_its_gic_node(VirtMachineState *vms)
|
||||
{
|
||||
char *nodename;
|
||||
MachineState *ms = MACHINE(vms);
|
||||
|
||||
vms->msi_phandle = qemu_fdt_alloc_phandle(vms->fdt);
|
||||
vms->msi_phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
||||
nodename = g_strdup_printf("/intc/its@%" PRIx64,
|
||||
vms->memmap[VIRT_GIC_ITS].base);
|
||||
qemu_fdt_add_subnode(vms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "compatible",
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
|
||||
"arm,gic-v3-its");
|
||||
qemu_fdt_setprop(vms->fdt, nodename, "msi-controller", NULL, 0);
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "msi-controller", NULL, 0);
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
||||
2, vms->memmap[VIRT_GIC_ITS].base,
|
||||
2, vms->memmap[VIRT_GIC_ITS].size);
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", vms->msi_phandle);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", vms->msi_phandle);
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
static void fdt_add_v2m_gic_node(VirtMachineState *vms)
|
||||
{
|
||||
MachineState *ms = MACHINE(vms);
|
||||
char *nodename;
|
||||
|
||||
nodename = g_strdup_printf("/intc/v2m@%" PRIx64,
|
||||
vms->memmap[VIRT_GIC_V2M].base);
|
||||
vms->msi_phandle = qemu_fdt_alloc_phandle(vms->fdt);
|
||||
qemu_fdt_add_subnode(vms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "compatible",
|
||||
vms->msi_phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
|
||||
"arm,gic-v2m-frame");
|
||||
qemu_fdt_setprop(vms->fdt, nodename, "msi-controller", NULL, 0);
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "msi-controller", NULL, 0);
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
||||
2, vms->memmap[VIRT_GIC_V2M].base,
|
||||
2, vms->memmap[VIRT_GIC_V2M].size);
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", vms->msi_phandle);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", vms->msi_phandle);
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
static void fdt_add_gic_node(VirtMachineState *vms)
|
||||
{
|
||||
MachineState *ms = MACHINE(vms);
|
||||
char *nodename;
|
||||
|
||||
vms->gic_phandle = qemu_fdt_alloc_phandle(vms->fdt);
|
||||
qemu_fdt_setprop_cell(vms->fdt, "/", "interrupt-parent", vms->gic_phandle);
|
||||
vms->gic_phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
||||
qemu_fdt_setprop_cell(ms->fdt, "/", "interrupt-parent", vms->gic_phandle);
|
||||
|
||||
nodename = g_strdup_printf("/intc@%" PRIx64,
|
||||
vms->memmap[VIRT_GIC_DIST].base);
|
||||
qemu_fdt_add_subnode(vms->fdt, nodename);
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "#interrupt-cells", 3);
|
||||
qemu_fdt_setprop(vms->fdt, nodename, "interrupt-controller", NULL, 0);
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "#address-cells", 0x2);
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "#size-cells", 0x2);
|
||||
qemu_fdt_setprop(vms->fdt, nodename, "ranges", NULL, 0);
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 3);
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x2);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 0x2);
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "ranges", NULL, 0);
|
||||
if (vms->gic_version == VIRT_GIC_VERSION_3) {
|
||||
int nb_redist_regions = virt_gicv3_redist_region_count(vms);
|
||||
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "compatible",
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
|
||||
"arm,gic-v3");
|
||||
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename,
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename,
|
||||
"#redistributor-regions", nb_redist_regions);
|
||||
|
||||
if (nb_redist_regions == 1) {
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
||||
2, vms->memmap[VIRT_GIC_DIST].base,
|
||||
2, vms->memmap[VIRT_GIC_DIST].size,
|
||||
2, vms->memmap[VIRT_GIC_REDIST].base,
|
||||
2, vms->memmap[VIRT_GIC_REDIST].size);
|
||||
} else {
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
||||
2, vms->memmap[VIRT_GIC_DIST].base,
|
||||
2, vms->memmap[VIRT_GIC_DIST].size,
|
||||
2, vms->memmap[VIRT_GIC_REDIST].base,
|
||||
@ -488,22 +492,22 @@ static void fdt_add_gic_node(VirtMachineState *vms)
|
||||
}
|
||||
|
||||
if (vms->virt) {
|
||||
qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts",
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
|
||||
GIC_FDT_IRQ_TYPE_PPI, ARCH_GIC_MAINT_IRQ,
|
||||
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
|
||||
}
|
||||
} else {
|
||||
/* 'cortex-a15-gic' means 'GIC v2' */
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "compatible",
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
|
||||
"arm,cortex-a15-gic");
|
||||
if (!vms->virt) {
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
||||
2, vms->memmap[VIRT_GIC_DIST].base,
|
||||
2, vms->memmap[VIRT_GIC_DIST].size,
|
||||
2, vms->memmap[VIRT_GIC_CPU].base,
|
||||
2, vms->memmap[VIRT_GIC_CPU].size);
|
||||
} else {
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
||||
2, vms->memmap[VIRT_GIC_DIST].base,
|
||||
2, vms->memmap[VIRT_GIC_DIST].size,
|
||||
2, vms->memmap[VIRT_GIC_CPU].base,
|
||||
@ -512,13 +516,13 @@ static void fdt_add_gic_node(VirtMachineState *vms)
|
||||
2, vms->memmap[VIRT_GIC_HYP].size,
|
||||
2, vms->memmap[VIRT_GIC_VCPU].base,
|
||||
2, vms->memmap[VIRT_GIC_VCPU].size);
|
||||
qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts",
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
|
||||
GIC_FDT_IRQ_TYPE_PPI, ARCH_GIC_MAINT_IRQ,
|
||||
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
|
||||
}
|
||||
}
|
||||
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", vms->gic_phandle);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", vms->gic_phandle);
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
@ -526,6 +530,7 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms)
|
||||
{
|
||||
ARMCPU *armcpu = ARM_CPU(first_cpu);
|
||||
uint32_t irqflags = GIC_FDT_IRQ_FLAGS_LEVEL_HI;
|
||||
MachineState *ms = MACHINE(vms);
|
||||
|
||||
if (!arm_feature(&armcpu->env, ARM_FEATURE_PMU)) {
|
||||
assert(!object_property_get_bool(OBJECT(armcpu), "pmu", NULL));
|
||||
@ -538,12 +543,12 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms)
|
||||
(1 << MACHINE(vms)->smp.cpus) - 1);
|
||||
}
|
||||
|
||||
qemu_fdt_add_subnode(vms->fdt, "/pmu");
|
||||
qemu_fdt_add_subnode(ms->fdt, "/pmu");
|
||||
if (arm_feature(&armcpu->env, ARM_FEATURE_V8)) {
|
||||
const char compat[] = "arm,armv8-pmuv3";
|
||||
qemu_fdt_setprop(vms->fdt, "/pmu", "compatible",
|
||||
qemu_fdt_setprop(ms->fdt, "/pmu", "compatible",
|
||||
compat, sizeof(compat));
|
||||
qemu_fdt_setprop_cells(vms->fdt, "/pmu", "interrupts",
|
||||
qemu_fdt_setprop_cells(ms->fdt, "/pmu", "interrupts",
|
||||
GIC_FDT_IRQ_TYPE_PPI, VIRTUAL_PMU_IRQ, irqflags);
|
||||
}
|
||||
}
|
||||
@ -749,6 +754,7 @@ static void create_uart(const VirtMachineState *vms, int uart,
|
||||
const char clocknames[] = "uartclk\0apb_pclk";
|
||||
DeviceState *dev = qdev_new(TYPE_PL011);
|
||||
SysBusDevice *s = SYS_BUS_DEVICE(dev);
|
||||
MachineState *ms = MACHINE(vms);
|
||||
|
||||
qdev_prop_set_chr(dev, "chardev", chr);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
@ -757,28 +763,28 @@ static void create_uart(const VirtMachineState *vms, int uart,
|
||||
sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
|
||||
|
||||
nodename = g_strdup_printf("/pl011@%" PRIx64, base);
|
||||
qemu_fdt_add_subnode(vms->fdt, nodename);
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
/* Note that we can't use setprop_string because of the embedded NUL */
|
||||
qemu_fdt_setprop(vms->fdt, nodename, "compatible",
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "compatible",
|
||||
compat, sizeof(compat));
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
||||
2, base, 2, size);
|
||||
qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts",
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq,
|
||||
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
|
||||
qemu_fdt_setprop_cells(vms->fdt, nodename, "clocks",
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "clocks",
|
||||
vms->clock_phandle, vms->clock_phandle);
|
||||
qemu_fdt_setprop(vms->fdt, nodename, "clock-names",
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "clock-names",
|
||||
clocknames, sizeof(clocknames));
|
||||
|
||||
if (uart == VIRT_UART) {
|
||||
qemu_fdt_setprop_string(vms->fdt, "/chosen", "stdout-path", nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
|
||||
} else {
|
||||
/* Mark as not usable by the normal world */
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled");
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay");
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "status", "disabled");
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "secure-status", "okay");
|
||||
|
||||
qemu_fdt_setprop_string(vms->fdt, "/secure-chosen", "stdout-path",
|
||||
qemu_fdt_setprop_string(ms->fdt, "/secure-chosen", "stdout-path",
|
||||
nodename);
|
||||
}
|
||||
|
||||
@ -792,19 +798,20 @@ static void create_rtc(const VirtMachineState *vms)
|
||||
hwaddr size = vms->memmap[VIRT_RTC].size;
|
||||
int irq = vms->irqmap[VIRT_RTC];
|
||||
const char compat[] = "arm,pl031\0arm,primecell";
|
||||
MachineState *ms = MACHINE(vms);
|
||||
|
||||
sysbus_create_simple("pl031", base, qdev_get_gpio_in(vms->gic, irq));
|
||||
|
||||
nodename = g_strdup_printf("/pl031@%" PRIx64, base);
|
||||
qemu_fdt_add_subnode(vms->fdt, nodename);
|
||||
qemu_fdt_setprop(vms->fdt, nodename, "compatible", compat, sizeof(compat));
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat));
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
||||
2, base, 2, size);
|
||||
qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts",
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq,
|
||||
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "clocks", vms->clock_phandle);
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "clock-names", "apb_pclk");
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "clocks", vms->clock_phandle);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "clock-names", "apb_pclk");
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
@ -821,32 +828,30 @@ static void virt_powerdown_req(Notifier *n, void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
static void create_gpio_keys(const VirtMachineState *vms,
|
||||
DeviceState *pl061_dev,
|
||||
static void create_gpio_keys(char *fdt, DeviceState *pl061_dev,
|
||||
uint32_t phandle)
|
||||
{
|
||||
gpio_key_dev = sysbus_create_simple("gpio-key", -1,
|
||||
qdev_get_gpio_in(pl061_dev, 3));
|
||||
|
||||
qemu_fdt_add_subnode(vms->fdt, "/gpio-keys");
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-keys", "compatible", "gpio-keys");
|
||||
qemu_fdt_setprop_cell(vms->fdt, "/gpio-keys", "#size-cells", 0);
|
||||
qemu_fdt_setprop_cell(vms->fdt, "/gpio-keys", "#address-cells", 1);
|
||||
qemu_fdt_add_subnode(fdt, "/gpio-keys");
|
||||
qemu_fdt_setprop_string(fdt, "/gpio-keys", "compatible", "gpio-keys");
|
||||
qemu_fdt_setprop_cell(fdt, "/gpio-keys", "#size-cells", 0);
|
||||
qemu_fdt_setprop_cell(fdt, "/gpio-keys", "#address-cells", 1);
|
||||
|
||||
qemu_fdt_add_subnode(vms->fdt, "/gpio-keys/poweroff");
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-keys/poweroff",
|
||||
qemu_fdt_add_subnode(fdt, "/gpio-keys/poweroff");
|
||||
qemu_fdt_setprop_string(fdt, "/gpio-keys/poweroff",
|
||||
"label", "GPIO Key Poweroff");
|
||||
qemu_fdt_setprop_cell(vms->fdt, "/gpio-keys/poweroff", "linux,code",
|
||||
qemu_fdt_setprop_cell(fdt, "/gpio-keys/poweroff", "linux,code",
|
||||
KEY_POWER);
|
||||
qemu_fdt_setprop_cells(vms->fdt, "/gpio-keys/poweroff",
|
||||
qemu_fdt_setprop_cells(fdt, "/gpio-keys/poweroff",
|
||||
"gpios", phandle, 3, 0);
|
||||
}
|
||||
|
||||
#define SECURE_GPIO_POWEROFF 0
|
||||
#define SECURE_GPIO_RESET 1
|
||||
|
||||
static void create_secure_gpio_pwr(const VirtMachineState *vms,
|
||||
DeviceState *pl061_dev,
|
||||
static void create_secure_gpio_pwr(char *fdt, DeviceState *pl061_dev,
|
||||
uint32_t phandle)
|
||||
{
|
||||
DeviceState *gpio_pwr_dev;
|
||||
@ -860,22 +865,22 @@ static void create_secure_gpio_pwr(const VirtMachineState *vms,
|
||||
qdev_connect_gpio_out(pl061_dev, SECURE_GPIO_POWEROFF,
|
||||
qdev_get_gpio_in_named(gpio_pwr_dev, "shutdown", 0));
|
||||
|
||||
qemu_fdt_add_subnode(vms->fdt, "/gpio-poweroff");
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-poweroff", "compatible",
|
||||
qemu_fdt_add_subnode(fdt, "/gpio-poweroff");
|
||||
qemu_fdt_setprop_string(fdt, "/gpio-poweroff", "compatible",
|
||||
"gpio-poweroff");
|
||||
qemu_fdt_setprop_cells(vms->fdt, "/gpio-poweroff",
|
||||
qemu_fdt_setprop_cells(fdt, "/gpio-poweroff",
|
||||
"gpios", phandle, SECURE_GPIO_POWEROFF, 0);
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-poweroff", "status", "disabled");
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-poweroff", "secure-status",
|
||||
qemu_fdt_setprop_string(fdt, "/gpio-poweroff", "status", "disabled");
|
||||
qemu_fdt_setprop_string(fdt, "/gpio-poweroff", "secure-status",
|
||||
"okay");
|
||||
|
||||
qemu_fdt_add_subnode(vms->fdt, "/gpio-restart");
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-restart", "compatible",
|
||||
qemu_fdt_add_subnode(fdt, "/gpio-restart");
|
||||
qemu_fdt_setprop_string(fdt, "/gpio-restart", "compatible",
|
||||
"gpio-restart");
|
||||
qemu_fdt_setprop_cells(vms->fdt, "/gpio-restart",
|
||||
qemu_fdt_setprop_cells(fdt, "/gpio-restart",
|
||||
"gpios", phandle, SECURE_GPIO_RESET, 0);
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-restart", "status", "disabled");
|
||||
qemu_fdt_setprop_string(vms->fdt, "/gpio-restart", "secure-status",
|
||||
qemu_fdt_setprop_string(fdt, "/gpio-restart", "status", "disabled");
|
||||
qemu_fdt_setprop_string(fdt, "/gpio-restart", "secure-status",
|
||||
"okay");
|
||||
}
|
||||
|
||||
@ -889,6 +894,7 @@ static void create_gpio_devices(const VirtMachineState *vms, int gpio,
|
||||
int irq = vms->irqmap[gpio];
|
||||
const char compat[] = "arm,pl061\0arm,primecell";
|
||||
SysBusDevice *s;
|
||||
MachineState *ms = MACHINE(vms);
|
||||
|
||||
pl061_dev = qdev_new("pl061");
|
||||
s = SYS_BUS_DEVICE(pl061_dev);
|
||||
@ -896,33 +902,33 @@ static void create_gpio_devices(const VirtMachineState *vms, int gpio,
|
||||
memory_region_add_subregion(mem, base, sysbus_mmio_get_region(s, 0));
|
||||
sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
|
||||
|
||||
uint32_t phandle = qemu_fdt_alloc_phandle(vms->fdt);
|
||||
uint32_t phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
||||
nodename = g_strdup_printf("/pl061@%" PRIx64, base);
|
||||
qemu_fdt_add_subnode(vms->fdt, nodename);
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
||||
2, base, 2, size);
|
||||
qemu_fdt_setprop(vms->fdt, nodename, "compatible", compat, sizeof(compat));
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "#gpio-cells", 2);
|
||||
qemu_fdt_setprop(vms->fdt, nodename, "gpio-controller", NULL, 0);
|
||||
qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts",
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "compatible", compat, sizeof(compat));
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "#gpio-cells", 2);
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "gpio-controller", NULL, 0);
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq,
|
||||
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "clocks", vms->clock_phandle);
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "clock-names", "apb_pclk");
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", phandle);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "clocks", vms->clock_phandle);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "clock-names", "apb_pclk");
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", phandle);
|
||||
|
||||
if (gpio != VIRT_GPIO) {
|
||||
/* Mark as not usable by the normal world */
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled");
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay");
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "status", "disabled");
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "secure-status", "okay");
|
||||
}
|
||||
g_free(nodename);
|
||||
|
||||
/* Child gpio devices */
|
||||
if (gpio == VIRT_GPIO) {
|
||||
create_gpio_keys(vms, pl061_dev, phandle);
|
||||
create_gpio_keys(ms->fdt, pl061_dev, phandle);
|
||||
} else {
|
||||
create_secure_gpio_pwr(vms, pl061_dev, phandle);
|
||||
create_secure_gpio_pwr(ms->fdt, pl061_dev, phandle);
|
||||
}
|
||||
}
|
||||
|
||||
@ -930,6 +936,7 @@ static void create_virtio_devices(const VirtMachineState *vms)
|
||||
{
|
||||
int i;
|
||||
hwaddr size = vms->memmap[VIRT_MMIO].size;
|
||||
MachineState *ms = MACHINE(vms);
|
||||
|
||||
/* We create the transports in forwards order. Since qbus_realize()
|
||||
* prepends (not appends) new child buses, the incrementing loop below will
|
||||
@ -979,15 +986,15 @@ static void create_virtio_devices(const VirtMachineState *vms)
|
||||
hwaddr base = vms->memmap[VIRT_MMIO].base + i * size;
|
||||
|
||||
nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, base);
|
||||
qemu_fdt_add_subnode(vms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename,
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename,
|
||||
"compatible", "virtio,mmio");
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
||||
2, base, 2, size);
|
||||
qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts",
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq,
|
||||
GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
|
||||
qemu_fdt_setprop(vms->fdt, nodename, "dma-coherent", NULL, 0);
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
|
||||
g_free(nodename);
|
||||
}
|
||||
}
|
||||
@ -1068,17 +1075,18 @@ static void virt_flash_fdt(VirtMachineState *vms,
|
||||
{
|
||||
hwaddr flashsize = vms->memmap[VIRT_FLASH].size / 2;
|
||||
hwaddr flashbase = vms->memmap[VIRT_FLASH].base;
|
||||
MachineState *ms = MACHINE(vms);
|
||||
char *nodename;
|
||||
|
||||
if (sysmem == secure_sysmem) {
|
||||
/* Report both flash devices as a single node in the DT */
|
||||
nodename = g_strdup_printf("/flash@%" PRIx64, flashbase);
|
||||
qemu_fdt_add_subnode(vms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "cfi-flash");
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cfi-flash");
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
||||
2, flashbase, 2, flashsize,
|
||||
2, flashbase + flashsize, 2, flashsize);
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "bank-width", 4);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "bank-width", 4);
|
||||
g_free(nodename);
|
||||
} else {
|
||||
/*
|
||||
@ -1086,21 +1094,21 @@ static void virt_flash_fdt(VirtMachineState *vms,
|
||||
* only visible to the secure world.
|
||||
*/
|
||||
nodename = g_strdup_printf("/secflash@%" PRIx64, flashbase);
|
||||
qemu_fdt_add_subnode(vms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "cfi-flash");
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cfi-flash");
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
||||
2, flashbase, 2, flashsize);
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "bank-width", 4);
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled");
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay");
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "bank-width", 4);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "status", "disabled");
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "secure-status", "okay");
|
||||
g_free(nodename);
|
||||
|
||||
nodename = g_strdup_printf("/flash@%" PRIx64, flashbase);
|
||||
qemu_fdt_add_subnode(vms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "cfi-flash");
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cfi-flash");
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
||||
2, flashbase + flashsize, 2, flashsize);
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "bank-width", 4);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "bank-width", 4);
|
||||
g_free(nodename);
|
||||
}
|
||||
}
|
||||
@ -1167,17 +1175,17 @@ static FWCfgState *create_fw_cfg(const VirtMachineState *vms, AddressSpace *as)
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)ms->smp.cpus);
|
||||
|
||||
nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base);
|
||||
qemu_fdt_add_subnode(vms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename,
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename,
|
||||
"compatible", "qemu,fw-cfg-mmio");
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
||||
2, base, 2, size);
|
||||
qemu_fdt_setprop(vms->fdt, nodename, "dma-coherent", NULL, 0);
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
|
||||
g_free(nodename);
|
||||
return fw_cfg;
|
||||
}
|
||||
|
||||
static void create_pcie_irq_map(const VirtMachineState *vms,
|
||||
static void create_pcie_irq_map(const MachineState *ms,
|
||||
uint32_t gic_phandle,
|
||||
int first_irq, const char *nodename)
|
||||
{
|
||||
@ -1205,10 +1213,10 @@ static void create_pcie_irq_map(const VirtMachineState *vms,
|
||||
}
|
||||
}
|
||||
|
||||
qemu_fdt_setprop(vms->fdt, nodename, "interrupt-map",
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map",
|
||||
full_irq_map, sizeof(full_irq_map));
|
||||
|
||||
qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupt-map-mask",
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupt-map-mask",
|
||||
cpu_to_be16(PCI_DEVFN(3, 0)), /* Slot 3 */
|
||||
0, 0,
|
||||
0x7 /* PCI irq */);
|
||||
@ -1225,6 +1233,7 @@ static void create_smmu(const VirtMachineState *vms,
|
||||
hwaddr size = vms->memmap[VIRT_SMMU].size;
|
||||
const char irq_names[] = "eventq\0priq\0cmdq-sync\0gerror";
|
||||
DeviceState *dev;
|
||||
MachineState *ms = MACHINE(vms);
|
||||
|
||||
if (vms->iommu != VIRT_IOMMU_SMMUV3 || !vms->iommu_phandle) {
|
||||
return;
|
||||
@ -1242,26 +1251,26 @@ static void create_smmu(const VirtMachineState *vms,
|
||||
}
|
||||
|
||||
node = g_strdup_printf("/smmuv3@%" PRIx64, base);
|
||||
qemu_fdt_add_subnode(vms->fdt, node);
|
||||
qemu_fdt_setprop(vms->fdt, node, "compatible", compat, sizeof(compat));
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, node, "reg", 2, base, 2, size);
|
||||
qemu_fdt_add_subnode(ms->fdt, node);
|
||||
qemu_fdt_setprop(ms->fdt, node, "compatible", compat, sizeof(compat));
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, node, "reg", 2, base, 2, size);
|
||||
|
||||
qemu_fdt_setprop_cells(vms->fdt, node, "interrupts",
|
||||
qemu_fdt_setprop_cells(ms->fdt, node, "interrupts",
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq , GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq + 1, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq + 2, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI,
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq + 3, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
|
||||
|
||||
qemu_fdt_setprop(vms->fdt, node, "interrupt-names", irq_names,
|
||||
qemu_fdt_setprop(ms->fdt, node, "interrupt-names", irq_names,
|
||||
sizeof(irq_names));
|
||||
|
||||
qemu_fdt_setprop_cell(vms->fdt, node, "clocks", vms->clock_phandle);
|
||||
qemu_fdt_setprop_string(vms->fdt, node, "clock-names", "apb_pclk");
|
||||
qemu_fdt_setprop(vms->fdt, node, "dma-coherent", NULL, 0);
|
||||
qemu_fdt_setprop_cell(ms->fdt, node, "clocks", vms->clock_phandle);
|
||||
qemu_fdt_setprop_string(ms->fdt, node, "clock-names", "apb_pclk");
|
||||
qemu_fdt_setprop(ms->fdt, node, "dma-coherent", NULL, 0);
|
||||
|
||||
qemu_fdt_setprop_cell(vms->fdt, node, "#iommu-cells", 1);
|
||||
qemu_fdt_setprop_cell(ms->fdt, node, "#iommu-cells", 1);
|
||||
|
||||
qemu_fdt_setprop_cell(vms->fdt, node, "phandle", vms->iommu_phandle);
|
||||
qemu_fdt_setprop_cell(ms->fdt, node, "phandle", vms->iommu_phandle);
|
||||
g_free(node);
|
||||
}
|
||||
|
||||
@ -1269,22 +1278,23 @@ static void create_virtio_iommu_dt_bindings(VirtMachineState *vms)
|
||||
{
|
||||
const char compat[] = "virtio,pci-iommu";
|
||||
uint16_t bdf = vms->virtio_iommu_bdf;
|
||||
MachineState *ms = MACHINE(vms);
|
||||
char *node;
|
||||
|
||||
vms->iommu_phandle = qemu_fdt_alloc_phandle(vms->fdt);
|
||||
vms->iommu_phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
||||
|
||||
node = g_strdup_printf("%s/virtio_iommu@%d", vms->pciehb_nodename, bdf);
|
||||
qemu_fdt_add_subnode(vms->fdt, node);
|
||||
qemu_fdt_setprop(vms->fdt, node, "compatible", compat, sizeof(compat));
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, node, "reg",
|
||||
qemu_fdt_add_subnode(ms->fdt, node);
|
||||
qemu_fdt_setprop(ms->fdt, node, "compatible", compat, sizeof(compat));
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, node, "reg",
|
||||
1, bdf << 8, 1, 0, 1, 0,
|
||||
1, 0, 1, 0);
|
||||
|
||||
qemu_fdt_setprop_cell(vms->fdt, node, "#iommu-cells", 1);
|
||||
qemu_fdt_setprop_cell(vms->fdt, node, "phandle", vms->iommu_phandle);
|
||||
qemu_fdt_setprop_cell(ms->fdt, node, "#iommu-cells", 1);
|
||||
qemu_fdt_setprop_cell(ms->fdt, node, "phandle", vms->iommu_phandle);
|
||||
g_free(node);
|
||||
|
||||
qemu_fdt_setprop_cells(vms->fdt, vms->pciehb_nodename, "iommu-map",
|
||||
qemu_fdt_setprop_cells(ms->fdt, vms->pciehb_nodename, "iommu-map",
|
||||
0x0, vms->iommu_phandle, 0x0, bdf,
|
||||
bdf + 1, vms->iommu_phandle, bdf + 1, 0xffff - bdf);
|
||||
}
|
||||
@ -1309,6 +1319,7 @@ static void create_pcie(VirtMachineState *vms)
|
||||
char *nodename;
|
||||
int i, ecam_id;
|
||||
PCIHostState *pci;
|
||||
MachineState *ms = MACHINE(vms);
|
||||
|
||||
dev = qdev_new(TYPE_GPEX_HOST);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
@ -1369,27 +1380,27 @@ static void create_pcie(VirtMachineState *vms)
|
||||
}
|
||||
|
||||
nodename = vms->pciehb_nodename = g_strdup_printf("/pcie@%" PRIx64, base);
|
||||
qemu_fdt_add_subnode(vms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename,
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename,
|
||||
"compatible", "pci-host-ecam-generic");
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "device_type", "pci");
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "#address-cells", 3);
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "#size-cells", 2);
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "linux,pci-domain", 0);
|
||||
qemu_fdt_setprop_cells(vms->fdt, nodename, "bus-range", 0,
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "pci");
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 3);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 2);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "linux,pci-domain", 0);
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "bus-range", 0,
|
||||
nr_pcie_buses - 1);
|
||||
qemu_fdt_setprop(vms->fdt, nodename, "dma-coherent", NULL, 0);
|
||||
qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
|
||||
|
||||
if (vms->msi_phandle) {
|
||||
qemu_fdt_setprop_cells(vms->fdt, nodename, "msi-parent",
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-parent",
|
||||
vms->msi_phandle);
|
||||
}
|
||||
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
|
||||
2, base_ecam, 2, size_ecam);
|
||||
|
||||
if (vms->highmem) {
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "ranges",
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "ranges",
|
||||
1, FDT_PCI_RANGE_IOPORT, 2, 0,
|
||||
2, base_pio, 2, size_pio,
|
||||
1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
|
||||
@ -1398,23 +1409,23 @@ static void create_pcie(VirtMachineState *vms)
|
||||
2, base_mmio_high,
|
||||
2, base_mmio_high, 2, size_mmio_high);
|
||||
} else {
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "ranges",
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "ranges",
|
||||
1, FDT_PCI_RANGE_IOPORT, 2, 0,
|
||||
2, base_pio, 2, size_pio,
|
||||
1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
|
||||
2, base_mmio, 2, size_mmio);
|
||||
}
|
||||
|
||||
qemu_fdt_setprop_cell(vms->fdt, nodename, "#interrupt-cells", 1);
|
||||
create_pcie_irq_map(vms, vms->gic_phandle, irq, nodename);
|
||||
qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
|
||||
create_pcie_irq_map(ms, vms->gic_phandle, irq, nodename);
|
||||
|
||||
if (vms->iommu) {
|
||||
vms->iommu_phandle = qemu_fdt_alloc_phandle(vms->fdt);
|
||||
vms->iommu_phandle = qemu_fdt_alloc_phandle(ms->fdt);
|
||||
|
||||
switch (vms->iommu) {
|
||||
case VIRT_IOMMU_SMMUV3:
|
||||
create_smmu(vms, vms->bus);
|
||||
qemu_fdt_setprop_cells(vms->fdt, nodename, "iommu-map",
|
||||
qemu_fdt_setprop_cells(ms->fdt, nodename, "iommu-map",
|
||||
0x0, vms->iommu_phandle, 0x0, 0x10000);
|
||||
break;
|
||||
default:
|
||||
@ -1466,17 +1477,18 @@ static void create_secure_ram(VirtMachineState *vms,
|
||||
char *nodename;
|
||||
hwaddr base = vms->memmap[VIRT_SECURE_MEM].base;
|
||||
hwaddr size = vms->memmap[VIRT_SECURE_MEM].size;
|
||||
MachineState *ms = MACHINE(vms);
|
||||
|
||||
memory_region_init_ram(secram, NULL, "virt.secure-ram", size,
|
||||
&error_fatal);
|
||||
memory_region_add_subregion(secure_sysmem, base, secram);
|
||||
|
||||
nodename = g_strdup_printf("/secram@%" PRIx64, base);
|
||||
qemu_fdt_add_subnode(vms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "device_type", "memory");
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg", 2, base, 2, size);
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "status", "disabled");
|
||||
qemu_fdt_setprop_string(vms->fdt, nodename, "secure-status", "okay");
|
||||
qemu_fdt_add_subnode(ms->fdt, nodename);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory");
|
||||
qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "status", "disabled");
|
||||
qemu_fdt_setprop_string(ms->fdt, nodename, "secure-status", "okay");
|
||||
|
||||
if (secure_tag_sysmem) {
|
||||
create_tag_ram(secure_tag_sysmem, base, size, "mach-virt.secure-tag");
|
||||
@ -1489,9 +1501,11 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
||||
{
|
||||
const VirtMachineState *board = container_of(binfo, VirtMachineState,
|
||||
bootinfo);
|
||||
MachineState *ms = MACHINE(board);
|
||||
|
||||
|
||||
*fdt_size = board->fdt_size;
|
||||
return board->fdt;
|
||||
return ms->fdt;
|
||||
}
|
||||
|
||||
static void virt_build_smbios(VirtMachineState *vms)
|
||||
@ -1539,7 +1553,7 @@ void virt_machine_done(Notifier *notifier, void *data)
|
||||
* while qemu takes charge of the qom stuff.
|
||||
*/
|
||||
if (info->dtb_filename == NULL) {
|
||||
platform_bus_add_all_fdt_nodes(vms->fdt, "/intc",
|
||||
platform_bus_add_all_fdt_nodes(ms->fdt, "/intc",
|
||||
vms->memmap[VIRT_PLATFORM_BUS].base,
|
||||
vms->memmap[VIRT_PLATFORM_BUS].size,
|
||||
vms->irqmap[VIRT_PLATFORM_BUS]);
|
||||
|
145
hw/core/guest-loader.c
Normal file
145
hw/core/guest-loader.c
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Guest Loader
|
||||
*
|
||||
* Copyright (C) 2020 Linaro
|
||||
* Written by Alex Bennée <alex.bennee@linaro.org>
|
||||
* (based on the generic-loader by Li Guang <lig.fnst@cn.fujitsu.com>)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Much like the generic-loader this is treated as a special device
|
||||
* inside QEMU. However unlike the generic-loader this device is used
|
||||
* to load guest images for hypervisors. As part of that process the
|
||||
* hypervisor needs to have platform information passed to it by the
|
||||
* lower levels of the stack (e.g. firmware/bootloader). If you boot
|
||||
* the hypervisor directly you use the guest-loader to load the Dom0
|
||||
* or equivalent guest images in the right place in the same way a
|
||||
* boot loader would.
|
||||
*
|
||||
* This is only relevant for full system emulation.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/core/cpu.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/module.h"
|
||||
#include "guest-loader.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "hw/boards.h"
|
||||
|
||||
/*
|
||||
* Insert some FDT nodes for the loaded blob.
|
||||
*/
|
||||
static void loader_insert_platform_data(GuestLoaderState *s, int size,
|
||||
Error **errp)
|
||||
{
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
void *fdt = machine->fdt;
|
||||
g_autofree char *node = g_strdup_printf("/chosen/module@0x%08" PRIx64,
|
||||
s->addr);
|
||||
uint64_t reg_attr[2] = {cpu_to_be64(s->addr), cpu_to_be64(size)};
|
||||
|
||||
if (!fdt) {
|
||||
error_setg(errp, "Cannot modify FDT fields if the machine has none");
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_fdt_add_subnode(fdt, node);
|
||||
qemu_fdt_setprop(fdt, node, "reg", ®_attr, sizeof(reg_attr));
|
||||
|
||||
if (s->kernel) {
|
||||
const char *compat[2] = { "multiboot,module", "multiboot,kernel" };
|
||||
if (qemu_fdt_setprop_string_array(fdt, node, "compatible",
|
||||
(char **) &compat,
|
||||
ARRAY_SIZE(compat)) < 0) {
|
||||
error_setg(errp, "couldn't set %s/compatible", node);
|
||||
return;
|
||||
}
|
||||
if (s->args) {
|
||||
if (qemu_fdt_setprop_string(fdt, node, "bootargs", s->args) < 0) {
|
||||
error_setg(errp, "couldn't set %s/bootargs", node);
|
||||
}
|
||||
}
|
||||
} else if (s->initrd) {
|
||||
const char *compat[2] = { "multiboot,module", "multiboot,ramdisk" };
|
||||
if (qemu_fdt_setprop_string_array(fdt, node, "compatible",
|
||||
(char **) &compat,
|
||||
ARRAY_SIZE(compat)) < 0) {
|
||||
error_setg(errp, "couldn't set %s/compatible", node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void guest_loader_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
GuestLoaderState *s = GUEST_LOADER(dev);
|
||||
char *file = s->kernel ? s->kernel : s->initrd;
|
||||
int size = 0;
|
||||
|
||||
/* Perform some error checking on the user's options */
|
||||
if (s->kernel && s->initrd) {
|
||||
error_setg(errp, "Cannot specify a kernel and initrd in same stanza");
|
||||
return;
|
||||
} else if (!s->kernel && !s->initrd) {
|
||||
error_setg(errp, "Need to specify a kernel or initrd image");
|
||||
return;
|
||||
} else if (!s->addr) {
|
||||
error_setg(errp, "Need to specify the address of guest blob");
|
||||
return;
|
||||
} else if (s->args && !s->kernel) {
|
||||
error_setg(errp, "Boot args only relevant to kernel blobs");
|
||||
}
|
||||
|
||||
/* Default to the maximum size being the machine's ram size */
|
||||
size = load_image_targphys_as(file, s->addr, current_machine->ram_size,
|
||||
NULL);
|
||||
if (size < 0) {
|
||||
error_setg(errp, "Cannot load specified image %s", file);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now the image is loaded we need to update the platform data */
|
||||
loader_insert_platform_data(s, size, errp);
|
||||
}
|
||||
|
||||
static Property guest_loader_props[] = {
|
||||
DEFINE_PROP_UINT64("addr", GuestLoaderState, addr, 0),
|
||||
DEFINE_PROP_STRING("kernel", GuestLoaderState, kernel),
|
||||
DEFINE_PROP_STRING("bootargs", GuestLoaderState, args),
|
||||
DEFINE_PROP_STRING("initrd", GuestLoaderState, initrd),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void guest_loader_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = guest_loader_realize;
|
||||
device_class_set_props(dc, guest_loader_props);
|
||||
dc->desc = "Guest Loader";
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
}
|
||||
|
||||
static TypeInfo guest_loader_info = {
|
||||
.name = TYPE_GUEST_LOADER,
|
||||
.parent = TYPE_DEVICE,
|
||||
.instance_size = sizeof(GuestLoaderState),
|
||||
.class_init = guest_loader_class_init,
|
||||
};
|
||||
|
||||
static void guest_loader_register_type(void)
|
||||
{
|
||||
type_register_static(&guest_loader_info);
|
||||
}
|
||||
|
||||
type_init(guest_loader_register_type)
|
34
hw/core/guest-loader.h
Normal file
34
hw/core/guest-loader.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Guest Loader
|
||||
*
|
||||
* Copyright (C) 2020 Linaro
|
||||
* Written by Alex Bennée <alex.bennee@linaro.org>
|
||||
* (based on the generic-loader by Li Guang <lig.fnst@cn.fujitsu.com>)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef GUEST_LOADER_H
|
||||
#define GUEST_LOADER_H
|
||||
|
||||
#include "hw/qdev-core.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
struct GuestLoaderState {
|
||||
/* <private> */
|
||||
DeviceState parent_obj;
|
||||
|
||||
/* <public> */
|
||||
uint64_t addr;
|
||||
char *kernel;
|
||||
char *args;
|
||||
char *initrd;
|
||||
};
|
||||
|
||||
#define TYPE_GUEST_LOADER "guest-loader"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(GuestLoaderState, GUEST_LOADER)
|
||||
|
||||
#endif
|
@ -37,6 +37,8 @@ softmmu_ss.add(files(
|
||||
'clock-vmstate.c',
|
||||
))
|
||||
|
||||
softmmu_ss.add(when: 'CONFIG_TCG', if_true: files('guest-loader.c'))
|
||||
|
||||
specific_ss.add(when: 'CONFIG_SOFTMMU', if_true: files(
|
||||
'machine-qmp-cmds.c',
|
||||
'numa.c',
|
||||
|
@ -30,7 +30,6 @@ subdir('rdma')
|
||||
subdir('rtc')
|
||||
subdir('scsi')
|
||||
subdir('sd')
|
||||
subdir('semihosting')
|
||||
subdir('smbios')
|
||||
subdir('ssi')
|
||||
subdir('timer')
|
||||
|
@ -58,7 +58,7 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/misc/empty_slot.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "hw/mips/cps.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
|
||||
|
@ -195,14 +195,14 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
|
||||
hwaddr flashbase = virt_memmap[VIRT_FLASH].base;
|
||||
|
||||
if (mc->dtb) {
|
||||
fdt = s->fdt = load_device_tree(mc->dtb, &s->fdt_size);
|
||||
fdt = mc->fdt = load_device_tree(mc->dtb, &s->fdt_size);
|
||||
if (!fdt) {
|
||||
error_report("load_device_tree() failed");
|
||||
exit(1);
|
||||
}
|
||||
goto update_bootargs;
|
||||
} else {
|
||||
fdt = s->fdt = create_device_tree(&s->fdt_size);
|
||||
fdt = mc->fdt = create_device_tree(&s->fdt_size);
|
||||
if (!fdt) {
|
||||
error_report("create_device_tree() failed");
|
||||
exit(1);
|
||||
@ -444,12 +444,12 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
|
||||
g_free(name);
|
||||
|
||||
name = g_strdup_printf("/soc/flash@%" PRIx64, flashbase);
|
||||
qemu_fdt_add_subnode(s->fdt, name);
|
||||
qemu_fdt_setprop_string(s->fdt, name, "compatible", "cfi-flash");
|
||||
qemu_fdt_setprop_sized_cells(s->fdt, name, "reg",
|
||||
qemu_fdt_add_subnode(mc->fdt, name);
|
||||
qemu_fdt_setprop_string(mc->fdt, name, "compatible", "cfi-flash");
|
||||
qemu_fdt_setprop_sized_cells(mc->fdt, name, "reg",
|
||||
2, flashbase, 2, flashsize,
|
||||
2, flashbase + flashsize, 2, flashsize);
|
||||
qemu_fdt_setprop_cell(s->fdt, name, "bank-width", 4);
|
||||
qemu_fdt_setprop_cell(mc->fdt, name, "bank-width", 4);
|
||||
g_free(name);
|
||||
|
||||
update_bootargs:
|
||||
@ -667,9 +667,9 @@ static void virt_machine_init(MachineState *machine)
|
||||
hwaddr end = riscv_load_initrd(machine->initrd_filename,
|
||||
machine->ram_size, kernel_entry,
|
||||
&start);
|
||||
qemu_fdt_setprop_cell(s->fdt, "/chosen",
|
||||
qemu_fdt_setprop_cell(machine->fdt, "/chosen",
|
||||
"linux,initrd-start", start);
|
||||
qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end",
|
||||
qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-end",
|
||||
end);
|
||||
}
|
||||
} else {
|
||||
@ -690,12 +690,12 @@ static void virt_machine_init(MachineState *machine)
|
||||
|
||||
/* Compute the fdt load address in dram */
|
||||
fdt_load_addr = riscv_load_fdt(memmap[VIRT_DRAM].base,
|
||||
machine->ram_size, s->fdt);
|
||||
machine->ram_size, machine->fdt);
|
||||
/* load the reset vector */
|
||||
riscv_setup_rom_reset_vec(machine, &s->soc[0], start_addr,
|
||||
virt_memmap[VIRT_MROM].base,
|
||||
virt_memmap[VIRT_MROM].size, kernel_entry,
|
||||
fdt_load_addr, s->fdt);
|
||||
fdt_load_addr, machine->fdt);
|
||||
|
||||
/* SiFive Test MMIO device */
|
||||
sifive_test_create(memmap[VIRT_TEST].base);
|
||||
|
@ -153,7 +153,6 @@ struct VirtMachineState {
|
||||
MemMapEntry *memmap;
|
||||
char *pciehb_nodename;
|
||||
const int *irqmap;
|
||||
void *fdt;
|
||||
int fdt_size;
|
||||
uint32_t clock_phandle;
|
||||
uint32_t gic_phandle;
|
||||
|
@ -258,6 +258,7 @@ struct MachineState {
|
||||
|
||||
/*< public >*/
|
||||
|
||||
void *fdt;
|
||||
char *dtb;
|
||||
char *dumpdtb;
|
||||
int phandle_start;
|
||||
|
@ -41,7 +41,6 @@ struct RISCVVirtState {
|
||||
DeviceState *plic[VIRT_SOCKETS_MAX];
|
||||
PFlashCFI01 *flash[2];
|
||||
|
||||
void *fdt;
|
||||
int fdt_size;
|
||||
};
|
||||
|
||||
|
@ -70,6 +70,23 @@ int qemu_fdt_setprop_u64(void *fdt, const char *node_path,
|
||||
const char *property, uint64_t val);
|
||||
int qemu_fdt_setprop_string(void *fdt, const char *node_path,
|
||||
const char *property, const char *string);
|
||||
|
||||
/**
|
||||
* qemu_fdt_setprop_string_array: set a string array property
|
||||
*
|
||||
* @fdt: pointer to the dt blob
|
||||
* @name: node name
|
||||
* @prop: property array
|
||||
* @array: pointer to an array of string pointers
|
||||
* @len: length of array
|
||||
*
|
||||
* assigns a string array to a property. This function converts and
|
||||
* array of strings to a sequential string with \0 separators before
|
||||
* setting the property.
|
||||
*/
|
||||
int qemu_fdt_setprop_string_array(void *fdt, const char *node_path,
|
||||
const char *prop, char **array, int len);
|
||||
|
||||
int qemu_fdt_setprop_phandle(void *fdt, const char *node_path,
|
||||
const char *property,
|
||||
const char *target_node_path);
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "qemu.h"
|
||||
#include "cpu_loop-common.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "hw/semihosting/common-semi.h"
|
||||
#include "semihosting/common-semi.h"
|
||||
#include "target/arm/syndrome.h"
|
||||
|
||||
#define get_user_code_u32(x, gaddr, env) \
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "qemu.h"
|
||||
#include "elf.h"
|
||||
#include "cpu_loop-common.h"
|
||||
#include "hw/semihosting/common-semi.h"
|
||||
#include "semihosting/common-semi.h"
|
||||
|
||||
#define get_user_code_u32(x, gaddr, env) \
|
||||
({ abi_long __r = get_user_u32((x), (gaddr)); \
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "qemu.h"
|
||||
#include "cpu_loop-common.h"
|
||||
#include "elf.h"
|
||||
#include "hw/semihosting/common-semi.h"
|
||||
#include "semihosting/common-semi.h"
|
||||
|
||||
void cpu_loop(CPURISCVState *env)
|
||||
{
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/semihosting/console.h"
|
||||
#include "semihosting/console.h"
|
||||
#include "qemu.h"
|
||||
#include <termios.h>
|
||||
|
||||
|
@ -1951,6 +1951,7 @@ subdir('migration')
|
||||
subdir('monitor')
|
||||
subdir('net')
|
||||
subdir('replay')
|
||||
subdir('semihosting')
|
||||
subdir('hw')
|
||||
subdir('accel')
|
||||
subdir('plugins')
|
||||
|
@ -34,9 +34,9 @@
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "hw/semihosting/console.h"
|
||||
#include "hw/semihosting/common-semi.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "semihosting/console.h"
|
||||
#include "semihosting/common-semi.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/timer.h"
|
||||
#ifdef CONFIG_USER_ONLY
|
@ -22,7 +22,7 @@
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "chardev/char.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
@ -17,8 +17,8 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "hw/semihosting/console.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "semihosting/console.h"
|
||||
#include "exec/gdbstub.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "qemu/log.h"
|
@ -21,6 +21,7 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/loader.h"
|
||||
@ -397,6 +398,31 @@ int qemu_fdt_setprop_string(void *fdt, const char *node_path,
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* libfdt doesn't allow us to add string arrays directly but they are
|
||||
* test a series of null terminated strings with a length. We build
|
||||
* the string up here so we can calculate the final length.
|
||||
*/
|
||||
int qemu_fdt_setprop_string_array(void *fdt, const char *node_path,
|
||||
const char *prop, char **array, int len)
|
||||
{
|
||||
int ret, i, total_len = 0;
|
||||
char *str, *p;
|
||||
for (i = 0; i < len; i++) {
|
||||
total_len += strlen(array[i]) + 1;
|
||||
}
|
||||
p = str = g_malloc0(total_len);
|
||||
for (i = 0; i < len; i++) {
|
||||
int len = strlen(array[i]) + 1;
|
||||
pstrcpy(p, len, array[i]);
|
||||
p += len;
|
||||
}
|
||||
|
||||
ret = qemu_fdt_setprop(fdt, node_path, prop, str, total_len);
|
||||
g_free(str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const void *qemu_fdt_getprop(void *fdt, const char *node_path,
|
||||
const char *property, int *lenp, Error **errp)
|
||||
{
|
||||
|
@ -108,7 +108,7 @@
|
||||
#include "qapi/opts-visitor.h"
|
||||
#include "qapi/clone-visitor.h"
|
||||
#include "qom/object_interfaces.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "crypto/init.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "qapi/qapi-events-run-state.h"
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
/* Empty config */
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "exec/exec-all.h"
|
||||
#include <zlib.h> /* For crc32 */
|
||||
#include "hw/irq.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "sysemu/cpu-timers.h"
|
||||
#include "sysemu/kvm.h"
|
||||
@ -34,7 +34,7 @@
|
||||
#ifdef CONFIG_TCG
|
||||
#include "arm_ldst.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "hw/semihosting/common-semi.h"
|
||||
#include "semihosting/common-semi.h"
|
||||
#endif
|
||||
|
||||
#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "qemu/qemu-print.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include <zlib.h> /* For crc32 */
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "qemu/range.h"
|
||||
@ -31,7 +31,7 @@
|
||||
#ifdef CONFIG_TCG
|
||||
#include "arm_ldst.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "hw/semihosting/common-semi.h"
|
||||
#include "semihosting/common-semi.h"
|
||||
#endif
|
||||
|
||||
static void v7m_msr_xpsr(CPUARMState *env, uint32_t mask,
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "internals.h"
|
||||
#include "qemu/host-utils.h"
|
||||
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "exec/gen-icount.h"
|
||||
|
||||
#include "exec/helper-proto.h"
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "arm_ldst.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/helper-gen.h"
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "exec/log.h"
|
||||
|
||||
bool lm32_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "exec/exec-all.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "qapi/qapi-commands-machine-target.h"
|
||||
#include "fpu_helper.h"
|
||||
|
||||
|
@ -22,8 +22,8 @@
|
||||
#include "qemu/log.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/softmmu-semi.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "hw/semihosting/console.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "semihosting/console.h"
|
||||
|
||||
typedef enum UHIOp {
|
||||
UHI_exit = 1,
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "exec/translator.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "exec/helper-gen.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
|
||||
#include "target/mips/trace.h"
|
||||
#include "trace-tcg.h"
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "exec/log.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "exec/exec-all.h"
|
||||
#include "tcg/tcg-op.h"
|
||||
#include "trace.h"
|
||||
#include "hw/semihosting/common-semi.h"
|
||||
#include "semihosting/common-semi.h"
|
||||
|
||||
int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
|
||||
{
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "hw/semihosting/console.h"
|
||||
#include "semihosting/console.h"
|
||||
|
||||
#undef DEBUG_UC32
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/qemu-print.h"
|
||||
#include "exec/cpu_ldst.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "exec/translator.h"
|
||||
|
||||
#include "exec/helper-proto.h"
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "cpu.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "exec/helper-proto.h"
|
||||
#include "hw/semihosting/semihost.h"
|
||||
#include "semihosting/semihost.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
|
||||
|
118
tests/acceptance/boot_xen.py
Normal file
118
tests/acceptance/boot_xen.py
Normal file
@ -0,0 +1,118 @@
|
||||
# Functional test that boots a Xen hypervisor with a domU kernel and
|
||||
# checks the console output is vaguely sane .
|
||||
#
|
||||
# Copyright (c) 2020 Linaro
|
||||
#
|
||||
# Author:
|
||||
# Alex Bennée <alex.bennee@linaro.org>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
# later. See the COPYING file in the top-level directory.
|
||||
|
||||
import os
|
||||
|
||||
from avocado import skipIf
|
||||
from avocado_qemu import wait_for_console_pattern
|
||||
from boot_linux_console import LinuxKernelTest
|
||||
|
||||
|
||||
class BootXenBase(LinuxKernelTest):
|
||||
"""
|
||||
Boots a Xen hypervisor with a Linux DomU kernel.
|
||||
"""
|
||||
|
||||
timeout = 90
|
||||
XEN_COMMON_COMMAND_LINE = 'dom0_mem=128M loglvl=all guest_loglvl=all'
|
||||
|
||||
def fetch_guest_kernel(self):
|
||||
# Using my own built kernel - which works
|
||||
kernel_url = ('https://fileserver.linaro.org/'
|
||||
's/JSsewXGZ6mqxPr5/download?path=%2F&files='
|
||||
'linux-5.9.9-arm64-ajb')
|
||||
kernel_sha1 = '4f92bc4b9f88d5ab792fa7a43a68555d344e1b83'
|
||||
kernel_path = self.fetch_asset(kernel_url,
|
||||
asset_hash=kernel_sha1)
|
||||
|
||||
return kernel_path
|
||||
|
||||
def launch_xen(self, xen_path):
|
||||
"""
|
||||
Launch Xen with a dom0 guest kernel
|
||||
"""
|
||||
self.log.info("launch with xen_path: %s", xen_path)
|
||||
kernel_path = self.fetch_guest_kernel()
|
||||
|
||||
self.vm.set_console()
|
||||
|
||||
xen_command_line = self.XEN_COMMON_COMMAND_LINE
|
||||
self.vm.add_args('-machine', 'virtualization=on',
|
||||
'-cpu', 'cortex-a57',
|
||||
'-m', '768',
|
||||
'-kernel', xen_path,
|
||||
'-append', xen_command_line,
|
||||
'-device',
|
||||
'guest-loader,addr=0x47000000,kernel=%s,bootargs=console=hvc0'
|
||||
% (kernel_path))
|
||||
|
||||
self.vm.launch()
|
||||
|
||||
console_pattern = 'VFS: Cannot open root device'
|
||||
wait_for_console_pattern(self, console_pattern, "Panic on CPU 0:")
|
||||
|
||||
|
||||
class BootXen(BootXenBase):
|
||||
|
||||
def test_arm64_xen_411_and_dom0(self):
|
||||
"""
|
||||
:avocado: tags=arch:aarch64
|
||||
:avocado: tags=accel:tcg
|
||||
:avocado: tags=cpu:cortex-a57
|
||||
:avocado: tags=machine:virt
|
||||
"""
|
||||
|
||||
# archive of file from https://deb.debian.org/debian/pool/main/x/xen/
|
||||
xen_url = ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/'
|
||||
'download?path=%2F&files='
|
||||
'xen-hypervisor-4.11-arm64_4.11.4%2B37-g3263f257ca-1_arm64.deb')
|
||||
xen_sha1 = '034e634d4416adbad1212d59b62bccdcda63e62a'
|
||||
xen_deb = self.fetch_asset(xen_url, asset_hash=xen_sha1)
|
||||
xen_path = self.extract_from_deb(xen_deb, "/boot/xen-4.11-arm64")
|
||||
|
||||
self.launch_xen(xen_path)
|
||||
|
||||
def test_arm64_xen_414_and_dom0(self):
|
||||
"""
|
||||
:avocado: tags=arch:aarch64
|
||||
:avocado: tags=accel:tcg
|
||||
:avocado: tags=cpu:cortex-a57
|
||||
:avocado: tags=machine:virt
|
||||
"""
|
||||
|
||||
# archive of file from https://deb.debian.org/debian/pool/main/x/xen/
|
||||
xen_url = ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/'
|
||||
'download?path=%2F&files='
|
||||
'xen-hypervisor-4.14-arm64_4.14.0%2B80-gd101b417b7-1_arm64.deb')
|
||||
xen_sha1 = 'b9d209dd689ed2b393e625303a225badefec1160'
|
||||
xen_deb = self.fetch_asset(xen_url, asset_hash=xen_sha1)
|
||||
xen_path = self.extract_from_deb(xen_deb, "/boot/xen-4.14-arm64")
|
||||
|
||||
self.launch_xen(xen_path)
|
||||
|
||||
def test_arm64_xen_415_and_dom0(self):
|
||||
"""
|
||||
:avocado: tags=arch:aarch64
|
||||
:avocado: tags=accel:tcg
|
||||
:avocado: tags=cpu:cortex-a57
|
||||
:avocado: tags=machine:virt
|
||||
"""
|
||||
|
||||
xen_url = ('https://fileserver.linaro.org/'
|
||||
's/JSsewXGZ6mqxPr5/download'
|
||||
'?path=%2F&files=xen-upstream-4.15-unstable.deb')
|
||||
xen_sha1 = 'fc191172b85cf355abb95d275a24cc0f6d6579d8'
|
||||
xen_deb = self.fetch_asset(xen_url, asset_hash=xen_sha1)
|
||||
xen_path = self.extract_from_deb(xen_deb, "/boot/xen-4.15-unstable")
|
||||
|
||||
self.launch_xen(xen_path)
|
@ -32,6 +32,6 @@ RUN apt update && \
|
||||
psmisc \
|
||||
python3 \
|
||||
python3-sphinx \
|
||||
$(apt-get -s build-dep qemu | egrep ^Inst | fgrep '[all]' | cut -d\ -f2)
|
||||
$(apt-get -s build-dep --arch-only qemu | egrep ^Inst | fgrep '[all]' | cut -d\ -f2)
|
||||
|
||||
ENV FEATURES docs
|
||||
|
22
tests/docker/test-tcg
Executable file
22
tests/docker/test-tcg
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/bash -e
|
||||
#
|
||||
# Build and run the TCG tests
|
||||
#
|
||||
# Copyright (c) 2021 Linaro Ltd.
|
||||
#
|
||||
# Authors:
|
||||
# Alex Bennée <alex.bennee@linaro.org>
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2
|
||||
# or (at your option) any later version. See the COPYING file in
|
||||
# the top-level directory.
|
||||
|
||||
. common.rc
|
||||
|
||||
cd "$BUILD_DIR"
|
||||
|
||||
# although we are not building QEMU itself we still need a configured
|
||||
# build for the unit tests to be built and run
|
||||
TARGET_LIST=${TARGET_LIST:-$DEF_TARGET_LIST} \
|
||||
build_qemu
|
||||
check_qemu check-tcg
|
Loading…
Reference in New Issue
Block a user