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:
Peter Maydell 2021-03-11 16:20:57 +00:00
commit f4abdf3271
56 changed files with 921 additions and 318 deletions

View File

@ -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

View File

@ -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:

View File

@ -2,3 +2,4 @@ source Kconfig.host
source backends/Kconfig
source accel/Kconfig
source hw/Kconfig
source semihosting/Kconfig

View File

@ -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>

View File

@ -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.

View 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.

View 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.

View File

@ -25,6 +25,8 @@ Contents:
usb
ivshmem
linuxboot
generic-loader
guest-loader
vnc-security
tls
gdb

View File

@ -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.

View File

@ -1,3 +1,5 @@
.. _system-targets-ref:
QEMU System Emulator Targets
============================

View File

@ -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"

View File

@ -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

View File

@ -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
View 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", &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
View 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

View File

@ -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',

View File

@ -30,7 +30,6 @@ subdir('rdma')
subdir('rtc')
subdir('scsi')
subdir('sd')
subdir('semihosting')
subdir('smbios')
subdir('ssi')
subdir('timer')

View File

@ -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"

View File

@ -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);

View File

@ -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;

View File

@ -258,6 +258,7 @@ struct MachineState {
/*< public >*/
void *fdt;
char *dtb;
char *dumpdtb;
int phandle_start;

View File

@ -41,7 +41,6 @@ struct RISCVVirtState {
DeviceState *plic[VIRT_SOCKETS_MAX];
PFlashCFI01 *flash[2];
void *fdt;
int fdt_size;
};

View File

@ -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);

View File

@ -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) \

View File

@ -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)); \

View File

@ -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)
{

View File

@ -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>

View File

@ -1951,6 +1951,7 @@ subdir('migration')
subdir('monitor')
subdir('net')
subdir('replay')
subdir('semihosting')
subdir('hw')
subdir('accel')
subdir('plugins')

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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)
{

View File

@ -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"

View File

@ -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 */

View File

@ -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 */

View File

@ -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,

View File

@ -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"

View File

@ -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"

View File

@ -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,

View File

@ -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)

View File

@ -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"

View File

@ -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,

View File

@ -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"

View File

@ -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)

View File

@ -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)
{

View File

@ -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

View File

@ -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"

View File

@ -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"

View 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)

View File

@ -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
View 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