Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
29ff573753
@ -100,6 +100,17 @@ avocado-system-debian:
|
||||
IMAGE: debian-amd64
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
|
||||
crash-test-debian:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-system-debian
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: debian-amd64
|
||||
script:
|
||||
- cd build
|
||||
- scripts/device-crash-test -q ./qemu-system-i386
|
||||
|
||||
build-system-fedora:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
@ -134,6 +145,18 @@ avocado-system-fedora:
|
||||
IMAGE: fedora
|
||||
MAKE_CHECK_ARGS: check-avocado
|
||||
|
||||
crash-test-fedora:
|
||||
extends: .native_test_job_template
|
||||
needs:
|
||||
- job: build-system-fedora
|
||||
artifacts: true
|
||||
variables:
|
||||
IMAGE: fedora
|
||||
script:
|
||||
- cd build
|
||||
- scripts/device-crash-test -q ./qemu-system-ppc
|
||||
- scripts/device-crash-test -q ./qemu-system-riscv32
|
||||
|
||||
build-system-centos:
|
||||
extends: .native_build_job_template
|
||||
needs:
|
||||
|
@ -89,3 +89,38 @@ x64-macos-11-base-build:
|
||||
PATH_EXTRA: /usr/local/opt/ccache/libexec:/usr/local/opt/gettext/bin
|
||||
PKG_CONFIG_PATH: /usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/ncurses/lib/pkgconfig:/usr/local/opt/readline/lib/pkgconfig
|
||||
TEST_TARGETS: check-unit check-block check-qapi-schema check-softfloat check-qtest-x86_64
|
||||
|
||||
|
||||
# The following jobs run VM-based tests via KVM on a Linux-based Cirrus-CI job
|
||||
.cirrus_kvm_job:
|
||||
stage: build
|
||||
image: registry.gitlab.com/libvirt/libvirt-ci/cirrus-run:master
|
||||
needs: []
|
||||
timeout: 80m
|
||||
allow_failure: true
|
||||
script:
|
||||
- sed -e "s|[@]CI_REPOSITORY_URL@|$CI_REPOSITORY_URL|g"
|
||||
-e "s|[@]CI_COMMIT_REF_NAME@|$CI_COMMIT_REF_NAME|g"
|
||||
-e "s|[@]CI_COMMIT_SHA@|$CI_COMMIT_SHA|g"
|
||||
-e "s|[@]NAME@|$NAME|g"
|
||||
-e "s|[@]CONFIGURE_ARGS@|$CONFIGURE_ARGS|g"
|
||||
-e "s|[@]TEST_TARGETS@|$TEST_TARGETS|g"
|
||||
<.gitlab-ci.d/cirrus/kvm-build.yml >.gitlab-ci.d/cirrus/$NAME.yml
|
||||
- cat .gitlab-ci.d/cirrus/$NAME.yml
|
||||
- cirrus-run -v --show-build-log always .gitlab-ci.d/cirrus/$NAME.yml
|
||||
rules:
|
||||
- when: manual
|
||||
|
||||
x86-netbsd:
|
||||
extends: .cirrus_kvm_job
|
||||
variables:
|
||||
NAME: netbsd
|
||||
CONFIGURE_ARGS: --target-list=x86_64-softmmu,ppc64-softmmu,aarch64-softmmu
|
||||
TEST_TARGETS: check
|
||||
|
||||
x86-openbsd:
|
||||
extends: .cirrus_kvm_job
|
||||
variables:
|
||||
NAME: openbsd
|
||||
CONFIGURE_ARGS: --target-list=i386-softmmu,riscv64-softmmu,mips64-softmmu
|
||||
TEST_TARGETS: check
|
||||
|
31
.gitlab-ci.d/cirrus/kvm-build.yml
Normal file
31
.gitlab-ci.d/cirrus/kvm-build.yml
Normal file
@ -0,0 +1,31 @@
|
||||
container:
|
||||
image: fedora:35
|
||||
cpu: 4
|
||||
memory: 8Gb
|
||||
kvm: true
|
||||
|
||||
env:
|
||||
CIRRUS_CLONE_DEPTH: 1
|
||||
CI_REPOSITORY_URL: "@CI_REPOSITORY_URL@"
|
||||
CI_COMMIT_REF_NAME: "@CI_COMMIT_REF_NAME@"
|
||||
CI_COMMIT_SHA: "@CI_COMMIT_SHA@"
|
||||
|
||||
@NAME@_task:
|
||||
@NAME@_vm_cache:
|
||||
folder: $HOME/.cache/qemu-vm
|
||||
install_script:
|
||||
- dnf update -y
|
||||
- dnf install -y git make openssh-clients qemu-img qemu-system-x86 wget
|
||||
clone_script:
|
||||
- git clone --depth 100 "$CI_REPOSITORY_URL" .
|
||||
- git fetch origin "$CI_COMMIT_REF_NAME"
|
||||
- git reset --hard "$CI_COMMIT_SHA"
|
||||
build_script:
|
||||
- if [ -f $HOME/.cache/qemu-vm/images/@NAME@.img ]; then
|
||||
make vm-build-@NAME@ J=$(getconf _NPROCESSORS_ONLN)
|
||||
EXTRA_CONFIGURE_OPTS="@CONFIGURE_ARGS@"
|
||||
BUILD_TARGET="@TEST_TARGETS@" ;
|
||||
else
|
||||
make vm-build-@NAME@ J=$(getconf _NPROCESSORS_ONLN) BUILD_TARGET=help
|
||||
EXTRA_CONFIGURE_OPTS="--disable-system --disable-user --disable-tools" ;
|
||||
fi
|
@ -11,3 +11,4 @@ include:
|
||||
- local: '/.gitlab-ci.d/static_checks.yml'
|
||||
- local: '/.gitlab-ci.d/custom-runners.yml'
|
||||
- local: '/.gitlab-ci.d/cirrus.yml'
|
||||
- local: '/.gitlab-ci.d/windows.yml'
|
||||
|
98
.gitlab-ci.d/windows.yml
Normal file
98
.gitlab-ci.d/windows.yml
Normal file
@ -0,0 +1,98 @@
|
||||
.shared_msys2_builder:
|
||||
tags:
|
||||
- shared-windows
|
||||
- windows
|
||||
- windows-1809
|
||||
cache:
|
||||
key: "${CI_JOB_NAME}-cache"
|
||||
paths:
|
||||
- ${CI_PROJECT_DIR}/msys64/var/cache
|
||||
needs: []
|
||||
stage: build
|
||||
timeout: 70m
|
||||
before_script:
|
||||
- If ( !(Test-Path -Path msys64\var\cache ) ) {
|
||||
mkdir msys64\var\cache
|
||||
}
|
||||
- If ( !(Test-Path -Path msys64\var\cache\msys2.exe ) ) {
|
||||
Invoke-WebRequest
|
||||
"https://github.com/msys2/msys2-installer/releases/download/2021-07-25/msys2-base-x86_64-20210725.sfx.exe"
|
||||
-outfile "msys64\var\cache\msys2.exe"
|
||||
}
|
||||
- msys64\var\cache\msys2.exe -y
|
||||
- ((Get-Content -path .\msys64\etc\\post-install\\07-pacman-key.post -Raw)
|
||||
-replace '--refresh-keys', '--version') |
|
||||
Set-Content -Path ${CI_PROJECT_DIR}\msys64\etc\\post-install\\07-pacman-key.post
|
||||
- .\msys64\usr\bin\bash -lc "sed -i 's/^CheckSpace/#CheckSpace/g' /etc/pacman.conf"
|
||||
- .\msys64\usr\bin\bash -lc 'pacman --noconfirm -Syuu' # Core update
|
||||
- .\msys64\usr\bin\bash -lc 'pacman --noconfirm -Syuu' # Normal update
|
||||
- taskkill /F /FI "MODULES eq msys-2.0.dll"
|
||||
|
||||
msys2-64bit:
|
||||
extends: .shared_msys2_builder
|
||||
script:
|
||||
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
|
||||
diffutils git grep make sed
|
||||
mingw-w64-x86_64-capstone
|
||||
mingw-w64-x86_64-curl
|
||||
mingw-w64-x86_64-cyrus-sasl
|
||||
mingw-w64-x86_64-gcc
|
||||
mingw-w64-x86_64-glib2
|
||||
mingw-w64-x86_64-gnutls
|
||||
mingw-w64-x86_64-libnfs
|
||||
mingw-w64-x86_64-libpng
|
||||
mingw-w64-x86_64-libssh
|
||||
mingw-w64-x86_64-libtasn1
|
||||
mingw-w64-x86_64-libusb
|
||||
mingw-w64-x86_64-libxml2
|
||||
mingw-w64-x86_64-nettle
|
||||
mingw-w64-x86_64-ninja
|
||||
mingw-w64-x86_64-pixman
|
||||
mingw-w64-x86_64-pkgconf
|
||||
mingw-w64-x86_64-python
|
||||
mingw-w64-x86_64-SDL2
|
||||
mingw-w64-x86_64-SDL2_image
|
||||
mingw-w64-x86_64-snappy
|
||||
mingw-w64-x86_64-usbredir
|
||||
mingw-w64-x86_64-zstd "
|
||||
- $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
|
||||
- $env:MSYSTEM = 'MINGW64' # Start a 64 bit Mingw environment
|
||||
- .\msys64\usr\bin\bash -lc './configure --target-list=x86_64-softmmu
|
||||
--enable-capstone=system --without-default-devices'
|
||||
- .\msys64\usr\bin\bash -lc "sed -i '/^ROMS=/d' build/config-host.mak"
|
||||
- .\msys64\usr\bin\bash -lc 'make -j2'
|
||||
- .\msys64\usr\bin\bash -lc 'make check'
|
||||
|
||||
msys2-32bit:
|
||||
extends: .shared_msys2_builder
|
||||
script:
|
||||
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
|
||||
diffutils git grep make sed
|
||||
mingw-w64-i686-capstone
|
||||
mingw-w64-i686-curl
|
||||
mingw-w64-i686-cyrus-sasl
|
||||
mingw-w64-i686-gcc
|
||||
mingw-w64-i686-glib2
|
||||
mingw-w64-i686-gnutls
|
||||
mingw-w64-i686-gtk3
|
||||
mingw-w64-i686-libgcrypt
|
||||
mingw-w64-i686-libjpeg-turbo
|
||||
mingw-w64-i686-libssh
|
||||
mingw-w64-i686-libtasn1
|
||||
mingw-w64-i686-libusb
|
||||
mingw-w64-i686-libxml2
|
||||
mingw-w64-i686-lzo2
|
||||
mingw-w64-i686-ninja
|
||||
mingw-w64-i686-pixman
|
||||
mingw-w64-i686-pkgconf
|
||||
mingw-w64-i686-python
|
||||
mingw-w64-i686-snappy
|
||||
mingw-w64-i686-usbredir "
|
||||
- $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
|
||||
- $env:MSYSTEM = 'MINGW32' # Start a 32-bit MinG environment
|
||||
- mkdir output
|
||||
- cd output
|
||||
- ..\msys64\usr\bin\bash -lc "../configure --target-list=ppc64-softmmu
|
||||
--enable-capstone=system"
|
||||
- ..\msys64\usr\bin\bash -lc 'make -j2'
|
||||
- ..\msys64\usr\bin\bash -lc 'make check'
|
1
.mailmap
1
.mailmap
@ -50,6 +50,7 @@ Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> <arikalo@wavecomp.com>
|
||||
Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> <aleksandar.rikalo@rt-rk.com>
|
||||
Alexander Graf <agraf@csgraf.de> <agraf@suse.de>
|
||||
Anthony Liguori <anthony@codemonkey.ws> Anthony Liguori <aliguori@us.ibm.com>
|
||||
Christian Borntraeger <borntraeger@linux.ibm.com> <borntraeger@de.ibm.com>
|
||||
Filip Bozuta <filip.bozuta@syrmia.com> <filip.bozuta@rt-rk.com.com>
|
||||
Frederic Konrad <konrad@adacore.com> <fred.konrad@greensocs.com>
|
||||
Greg Kurz <groug@kaod.org> <gkurz@linux.vnet.ibm.com>
|
||||
|
10
MAINTAINERS
10
MAINTAINERS
@ -393,7 +393,7 @@ F: target/ppc/kvm.c
|
||||
|
||||
S390 KVM CPUs
|
||||
M: Halil Pasic <pasic@linux.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@de.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@linux.ibm.com>
|
||||
S: Supported
|
||||
F: target/s390x/kvm/
|
||||
F: target/s390x/ioinst.[ch]
|
||||
@ -1527,7 +1527,7 @@ S390 Machines
|
||||
-------------
|
||||
S390 Virtio-ccw
|
||||
M: Halil Pasic <pasic@linux.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@de.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@linux.ibm.com>
|
||||
S: Supported
|
||||
F: hw/char/sclp*.[hc]
|
||||
F: hw/char/terminal3270.c
|
||||
@ -1541,7 +1541,7 @@ T: git https://github.com/borntraeger/qemu.git s390-next
|
||||
L: qemu-s390x@nongnu.org
|
||||
|
||||
S390-ccw boot
|
||||
M: Christian Borntraeger <borntraeger@de.ibm.com>
|
||||
M: Christian Borntraeger <borntraeger@linux.ibm.com>
|
||||
M: Thomas Huth <thuth@redhat.com>
|
||||
S: Supported
|
||||
F: hw/s390x/ipl.*
|
||||
@ -1825,6 +1825,7 @@ F: hw/scsi/*
|
||||
F: tests/qtest/virtio-scsi-test.c
|
||||
F: tests/qtest/fuzz-virtio-scsi-test.c
|
||||
F: tests/qtest/am53c974-test.c
|
||||
F: tests/qtest/fuzz-lsi53c895a-test.c
|
||||
T: git https://github.com/bonzini/qemu.git scsi-next
|
||||
|
||||
SSI
|
||||
@ -3076,8 +3077,9 @@ Usermode Emulation
|
||||
Overall usermode emulation
|
||||
M: Riku Voipio <riku.voipio@iki.fi>
|
||||
S: Maintained
|
||||
F: thunk.c
|
||||
F: accel/tcg/user-exec*.c
|
||||
F: include/user/
|
||||
F: common-user/
|
||||
|
||||
BSD user
|
||||
M: Warner Losh <imp@bsdimp.com>
|
||||
|
@ -61,6 +61,10 @@
|
||||
#endif
|
||||
#define PAGE_SIZE qemu_real_host_page_size
|
||||
|
||||
#ifndef KVM_GUESTDBG_BLOCKIRQ
|
||||
#define KVM_GUESTDBG_BLOCKIRQ 0
|
||||
#endif
|
||||
|
||||
//#define DEBUG_KVM
|
||||
|
||||
#ifdef DEBUG_KVM
|
||||
@ -168,6 +172,8 @@ bool kvm_vm_attributes_allowed;
|
||||
bool kvm_direct_msi_allowed;
|
||||
bool kvm_ioeventfd_any_length_allowed;
|
||||
bool kvm_msi_use_devid;
|
||||
bool kvm_has_guest_debug;
|
||||
int kvm_sstep_flags;
|
||||
static bool kvm_immediate_exit;
|
||||
static hwaddr kvm_max_slot_size = ~0;
|
||||
|
||||
@ -2564,6 +2570,25 @@ static int kvm_init(MachineState *ms)
|
||||
kvm_ioeventfd_any_length_allowed =
|
||||
(kvm_check_extension(s, KVM_CAP_IOEVENTFD_ANY_LENGTH) > 0);
|
||||
|
||||
#ifdef KVM_CAP_SET_GUEST_DEBUG
|
||||
kvm_has_guest_debug =
|
||||
(kvm_check_extension(s, KVM_CAP_SET_GUEST_DEBUG) > 0);
|
||||
#endif
|
||||
|
||||
kvm_sstep_flags = 0;
|
||||
if (kvm_has_guest_debug) {
|
||||
kvm_sstep_flags = SSTEP_ENABLE;
|
||||
|
||||
#if defined KVM_CAP_SET_GUEST_DEBUG2
|
||||
int guest_debug_flags =
|
||||
kvm_check_extension(s, KVM_CAP_SET_GUEST_DEBUG2);
|
||||
|
||||
if (guest_debug_flags & KVM_GUESTDBG_BLOCKIRQ) {
|
||||
kvm_sstep_flags |= SSTEP_NOIRQ;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
kvm_state = s;
|
||||
|
||||
ret = kvm_arch_init(ms, s);
|
||||
@ -3193,6 +3218,10 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
|
||||
|
||||
if (cpu->singlestep_enabled) {
|
||||
data.dbg.control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP;
|
||||
|
||||
if (cpu->singlestep_enabled & SSTEP_NOIRQ) {
|
||||
data.dbg.control |= KVM_GUESTDBG_BLOCKIRQ;
|
||||
}
|
||||
}
|
||||
kvm_arch_update_guest_debug(cpu, &data.dbg);
|
||||
|
||||
|
@ -206,8 +206,9 @@ static void nvme_free_req_queue_cb(void *opaque)
|
||||
NVMeQueuePair *q = opaque;
|
||||
|
||||
qemu_mutex_lock(&q->lock);
|
||||
while (qemu_co_enter_next(&q->free_req_queue, &q->lock)) {
|
||||
/* Retry all pending requests */
|
||||
while (q->free_req_head != -1 &&
|
||||
qemu_co_enter_next(&q->free_req_queue, &q->lock)) {
|
||||
/* Retry waiting requests */
|
||||
}
|
||||
qemu_mutex_unlock(&q->lock);
|
||||
}
|
||||
|
10
blockdev.c
10
blockdev.c
@ -303,16 +303,6 @@ int drive_get_max_bus(BlockInterfaceType type)
|
||||
return max_bus;
|
||||
}
|
||||
|
||||
/* Get a block device. This should only be used for single-drive devices
|
||||
(e.g. SD/Floppy/MTD). Multi-disk devices (scsi/ide) should use the
|
||||
appropriate bus. */
|
||||
DriveInfo *drive_get_next(BlockInterfaceType type)
|
||||
{
|
||||
static int next_block_unit[IF_COUNT];
|
||||
|
||||
return drive_get(type, 0, next_block_unit[type]++);
|
||||
}
|
||||
|
||||
static void bdrv_format_print(void *opaque, const char *name)
|
||||
{
|
||||
qemu_printf(" %s", name);
|
||||
|
@ -151,6 +151,10 @@
|
||||
/* Internal errors: */
|
||||
#define TARGET_EJUSTRETURN 254 /* Just return without modifing regs */
|
||||
#define TARGET_ERESTART 255 /* Restart syscall */
|
||||
#define TARGET_ERESTARTSYS TARGET_ERESTART /* Linux compat */
|
||||
|
||||
#include "special-errno.h"
|
||||
|
||||
_Static_assert(TARGET_ERESTART == QEMU_ERESTARTSYS,
|
||||
"TARGET_ERESTART and QEMU_ERESTARTSYS expected to match");
|
||||
|
||||
#endif /* ! _ERRNO_DEFS_H_ */
|
||||
|
@ -2,6 +2,10 @@ if not have_bsd_user
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
bsd_user_ss = ss.source_set()
|
||||
|
||||
common_user_inc += include_directories('.')
|
||||
|
||||
bsd_user_ss.add(files(
|
||||
'bsdload.c',
|
||||
'elfload.c',
|
||||
@ -15,3 +19,5 @@ bsd_user_ss.add(files(
|
||||
|
||||
# Pull in the OS-specific build glue, if any
|
||||
subdir(targetos)
|
||||
|
||||
specific_ss.add_all(when: 'CONFIG_BSD_USER', if_true: bsd_user_ss)
|
||||
|
24
bsd-user/special-errno.h
Normal file
24
bsd-user/special-errno.h
Normal file
@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
/*
|
||||
* QEMU internal errno values for implementing user-only POSIX.
|
||||
*
|
||||
* Copyright (c) 2021 Linaro, Ltd.
|
||||
*/
|
||||
|
||||
#ifndef SPECIAL_ERRNO_H
|
||||
#define SPECIAL_ERRNO_H
|
||||
|
||||
/*
|
||||
* All of these are QEMU internal, not visible to the guest.
|
||||
* They should be chosen so as to not overlap with any host
|
||||
* or guest errno.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is returned when a system call should be restarted, to tell the
|
||||
* main loop that it should wind the guest PC backwards so it will
|
||||
* re-execute the syscall after handling any pending signals.
|
||||
*/
|
||||
#define QEMU_ERESTARTSYS 255
|
||||
|
||||
#endif /* SPECIAL_ERRNO_H */
|
88
common-user/host/aarch64/safe-syscall.inc.S
Normal file
88
common-user/host/aarch64/safe-syscall.inc.S
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by common-user/safe-syscall.S
|
||||
*
|
||||
* Written by Richard Henderson <rth@twiddle.net>
|
||||
* Copyright (C) 2016 Red Hat, 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.
|
||||
*/
|
||||
|
||||
.global safe_syscall_base
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_base, #function
|
||||
.type safe_syscall_start, #function
|
||||
.type safe_syscall_end, #function
|
||||
|
||||
/* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
*/
|
||||
safe_syscall_base:
|
||||
.cfi_startproc
|
||||
/* The syscall calling convention isn't the same as the
|
||||
* C one:
|
||||
* we enter with x0 == &signal_pending
|
||||
* x1 == syscall number
|
||||
* x2 ... x7, (stack) == syscall arguments
|
||||
* and return the result in x0
|
||||
* and the syscall instruction needs
|
||||
* x8 == syscall number
|
||||
* x0 ... x6 == syscall arguments
|
||||
* and returns the result in x0
|
||||
* Shuffle everything around appropriately.
|
||||
*/
|
||||
mov x9, x0 /* signal_pending pointer */
|
||||
mov x8, x1 /* syscall number */
|
||||
mov x0, x2 /* syscall arguments */
|
||||
mov x1, x3
|
||||
mov x2, x4
|
||||
mov x3, x5
|
||||
mov x4, x6
|
||||
mov x5, x7
|
||||
ldr x6, [sp]
|
||||
|
||||
/* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* if signal_pending is non-zero, don't do the call */
|
||||
ldr w10, [x9]
|
||||
cbnz w10, 2f
|
||||
svc 0x0
|
||||
safe_syscall_end:
|
||||
|
||||
/* code path for having successfully executed the syscall */
|
||||
#if defined(__linux__)
|
||||
/* Linux kernel returns (small) negative errno. */
|
||||
cmp x0, #-4096
|
||||
b.hi 0f
|
||||
#elif defined(__FreeBSD__)
|
||||
/* FreeBSD kernel returns positive errno and C bit set. */
|
||||
b.cs 1f
|
||||
#else
|
||||
#error "unsupported os"
|
||||
#endif
|
||||
ret
|
||||
|
||||
#if defined(__linux__)
|
||||
/* code path setting errno */
|
||||
0: neg w0, w0
|
||||
b safe_syscall_set_errno_tail
|
||||
#endif
|
||||
|
||||
/* code path when we didn't execute the syscall */
|
||||
2: mov w0, #QEMU_ERESTARTSYS
|
||||
1: b safe_syscall_set_errno_tail
|
||||
|
||||
.cfi_endproc
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
108
common-user/host/arm/safe-syscall.inc.S
Normal file
108
common-user/host/arm/safe-syscall.inc.S
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by common-user/safe-syscall.S
|
||||
*
|
||||
* Written by Richard Henderson <rth@twiddle.net>
|
||||
* Copyright (C) 2016 Red Hat, 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.
|
||||
*/
|
||||
|
||||
.global safe_syscall_base
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_base, %function
|
||||
|
||||
.cfi_sections .debug_frame
|
||||
|
||||
.text
|
||||
.syntax unified
|
||||
.arm
|
||||
.align 2
|
||||
|
||||
/* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
*/
|
||||
safe_syscall_base:
|
||||
.fnstart
|
||||
.cfi_startproc
|
||||
mov r12, sp /* save entry stack */
|
||||
push { r4, r5, r6, r7, r8, lr }
|
||||
.save { r4, r5, r6, r7, r8, lr }
|
||||
.cfi_adjust_cfa_offset 24
|
||||
.cfi_rel_offset r4, 0
|
||||
.cfi_rel_offset r5, 4
|
||||
.cfi_rel_offset r6, 8
|
||||
.cfi_rel_offset r7, 12
|
||||
.cfi_rel_offset r8, 16
|
||||
.cfi_rel_offset lr, 20
|
||||
|
||||
/* The syscall calling convention isn't the same as the C one:
|
||||
* we enter with r0 == &signal_pending
|
||||
* r1 == syscall number
|
||||
* r2, r3, [sp+0] ... [sp+12] == syscall arguments
|
||||
* and return the result in r0
|
||||
* and the syscall instruction needs
|
||||
* r7 == syscall number
|
||||
* r0 ... r6 == syscall arguments
|
||||
* and returns the result in r0
|
||||
* Shuffle everything around appropriately.
|
||||
* Note the 16 bytes that we pushed to save registers.
|
||||
*/
|
||||
mov r8, r0 /* copy signal_pending */
|
||||
mov r7, r1 /* syscall number */
|
||||
mov r0, r2 /* syscall args */
|
||||
mov r1, r3
|
||||
ldm r12, { r2, r3, r4, r5, r6 }
|
||||
|
||||
/* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* if signal_pending is non-zero, don't do the call */
|
||||
ldr r12, [r8] /* signal_pending */
|
||||
tst r12, r12
|
||||
bne 2f
|
||||
swi 0
|
||||
safe_syscall_end:
|
||||
|
||||
/* code path for having successfully executed the syscall */
|
||||
#if defined(__linux__)
|
||||
/* Linux kernel returns (small) negative errno. */
|
||||
cmp r0, #-4096
|
||||
neghi r0, r0
|
||||
bhi 1f
|
||||
#elif defined(__FreeBSD__)
|
||||
/* FreeBSD kernel returns positive errno and C bit set. */
|
||||
bcs 1f
|
||||
#else
|
||||
#error "unsupported os"
|
||||
#endif
|
||||
pop { r4, r5, r6, r7, r8, pc }
|
||||
|
||||
/* code path when we didn't execute the syscall */
|
||||
2: mov r0, #QEMU_ERESTARTSYS
|
||||
|
||||
/* code path setting errno */
|
||||
1: pop { r4, r5, r6, r7, r8, lr }
|
||||
.cfi_adjust_cfa_offset -24
|
||||
.cfi_restore r4
|
||||
.cfi_restore r5
|
||||
.cfi_restore r6
|
||||
.cfi_restore r7
|
||||
.cfi_restore r8
|
||||
.cfi_restore lr
|
||||
b safe_syscall_set_errno_tail
|
||||
|
||||
.fnend
|
||||
.cfi_endproc
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
126
common-user/host/i386/safe-syscall.inc.S
Normal file
126
common-user/host/i386/safe-syscall.inc.S
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by common-user/safe-syscall.S
|
||||
*
|
||||
* Written by Richard Henderson <rth@twiddle.net>
|
||||
* Copyright (C) 2016 Red Hat, 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.
|
||||
*/
|
||||
|
||||
.global safe_syscall_base
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_base, @function
|
||||
|
||||
/* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
*/
|
||||
safe_syscall_base:
|
||||
.cfi_startproc
|
||||
push %ebp
|
||||
.cfi_adjust_cfa_offset 4
|
||||
.cfi_rel_offset ebp, 0
|
||||
push %esi
|
||||
.cfi_adjust_cfa_offset 4
|
||||
.cfi_rel_offset esi, 0
|
||||
push %edi
|
||||
.cfi_adjust_cfa_offset 4
|
||||
.cfi_rel_offset edi, 0
|
||||
push %ebx
|
||||
.cfi_adjust_cfa_offset 4
|
||||
.cfi_rel_offset ebx, 0
|
||||
|
||||
/* The syscall calling convention isn't the same as the C one:
|
||||
* we enter with 0(%esp) == return address
|
||||
* 4(%esp) == &signal_pending
|
||||
* 8(%esp) == syscall number
|
||||
* 12(%esp) ... 32(%esp) == syscall arguments
|
||||
* and return the result in eax
|
||||
* and the syscall instruction needs
|
||||
* eax == syscall number
|
||||
* ebx, ecx, edx, esi, edi, ebp == syscall arguments
|
||||
* and returns the result in eax
|
||||
* Shuffle everything around appropriately.
|
||||
* Note the 16 bytes that we pushed to save registers.
|
||||
*/
|
||||
mov 12+16(%esp), %ebx /* the syscall arguments */
|
||||
mov 16+16(%esp), %ecx
|
||||
mov 20+16(%esp), %edx
|
||||
mov 24+16(%esp), %esi
|
||||
mov 28+16(%esp), %edi
|
||||
mov 32+16(%esp), %ebp
|
||||
|
||||
/* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* if signal_pending is non-zero, don't do the call */
|
||||
mov 4+16(%esp), %eax /* signal_pending */
|
||||
cmpl $0, (%eax)
|
||||
jnz 2f
|
||||
mov 8+16(%esp), %eax /* syscall number */
|
||||
int $0x80
|
||||
safe_syscall_end:
|
||||
|
||||
/* code path for having successfully executed the syscall */
|
||||
#if defined(__linux__)
|
||||
/* Linux kernel returns (small) negative errno. */
|
||||
cmp $-4095, %eax
|
||||
jae 0f
|
||||
#elif defined(__FreeBSD__)
|
||||
/* FreeBSD kernel returns positive errno and C bit set. */
|
||||
jc 1f
|
||||
#else
|
||||
#error "unsupported os"
|
||||
#endif
|
||||
pop %ebx
|
||||
.cfi_remember_state
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore ebx
|
||||
pop %edi
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore edi
|
||||
pop %esi
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore esi
|
||||
pop %ebp
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore ebp
|
||||
ret
|
||||
.cfi_restore_state
|
||||
|
||||
#if defined(__linux__)
|
||||
0: neg %eax
|
||||
jmp 1f
|
||||
#endif
|
||||
|
||||
/* code path when we didn't execute the syscall */
|
||||
2: mov $QEMU_ERESTARTSYS, %eax
|
||||
|
||||
/* code path setting errno */
|
||||
1: pop %ebx
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore ebx
|
||||
pop %edi
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore edi
|
||||
pop %esi
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore esi
|
||||
pop %ebp
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore ebp
|
||||
jmp safe_syscall_set_errno_tail
|
||||
|
||||
.cfi_endproc
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
148
common-user/host/mips/safe-syscall.inc.S
Normal file
148
common-user/host/mips/safe-syscall.inc.S
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by common-user/safe-syscall.S
|
||||
*
|
||||
* Written by Richard Henderson <richard.henderson@linaro.org>
|
||||
* Copyright (C) 2021 Linaro, 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.
|
||||
*/
|
||||
|
||||
#include "sys/regdef.h"
|
||||
#include "sys/asm.h"
|
||||
|
||||
.text
|
||||
.set nomips16
|
||||
.set reorder
|
||||
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_start, @function
|
||||
.type safe_syscall_end, @function
|
||||
|
||||
/*
|
||||
* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
*/
|
||||
|
||||
#if _MIPS_SIM == _ABIO32
|
||||
/* 8 * 4 = 32 for outgoing parameters; 1 * 4 for s0 save; 1 * 4 for align. */
|
||||
#define FRAME 40
|
||||
#define OFS_S0 32
|
||||
#else
|
||||
/* 1 * 8 for s0 save; 1 * 8 for align. */
|
||||
#define FRAME 16
|
||||
#define OFS_S0 0
|
||||
#endif
|
||||
|
||||
|
||||
NESTED(safe_syscall_base, FRAME, ra)
|
||||
.cfi_startproc
|
||||
PTR_ADDIU sp, sp, -FRAME
|
||||
.cfi_adjust_cfa_offset FRAME
|
||||
REG_S s0, OFS_S0(sp)
|
||||
.cfi_rel_offset s0, OFS_S0
|
||||
#if _MIPS_SIM == _ABIO32
|
||||
/*
|
||||
* The syscall calling convention is nearly the same as C:
|
||||
* we enter with a0 == &signal_pending
|
||||
* a1 == syscall number
|
||||
* a2, a3, stack == syscall arguments
|
||||
* and return the result in a0
|
||||
* and the syscall instruction needs
|
||||
* v0 == syscall number
|
||||
* a0 ... a3, stack == syscall arguments
|
||||
* and returns the result in v0
|
||||
* Shuffle everything around appropriately.
|
||||
*/
|
||||
move s0, a0 /* signal_pending pointer */
|
||||
move v0, a1 /* syscall number */
|
||||
move a0, a2 /* syscall arguments */
|
||||
move a1, a3
|
||||
lw a2, FRAME+16(sp)
|
||||
lw a3, FRAME+20(sp)
|
||||
lw t4, FRAME+24(sp)
|
||||
lw t5, FRAME+28(sp)
|
||||
lw t6, FRAME+32(sp)
|
||||
lw t7, FRAME+40(sp)
|
||||
sw t4, 16(sp)
|
||||
sw t5, 20(sp)
|
||||
sw t6, 24(sp)
|
||||
sw t7, 28(sp)
|
||||
#else
|
||||
/*
|
||||
* The syscall calling convention is nearly the same as C:
|
||||
* we enter with a0 == &signal_pending
|
||||
* a1 == syscall number
|
||||
* a2 ... a7 == syscall arguments
|
||||
* and return the result in a0
|
||||
* and the syscall instruction needs
|
||||
* v0 == syscall number
|
||||
* a0 ... a5 == syscall arguments
|
||||
* and returns the result in v0
|
||||
* Shuffle everything around appropriately.
|
||||
*/
|
||||
move s0, a0 /* signal_pending pointer */
|
||||
move v0, a1 /* syscall number */
|
||||
move a0, a2 /* syscall arguments */
|
||||
move a1, a3
|
||||
move a2, a4
|
||||
move a3, a5
|
||||
move a4, a6
|
||||
move a5, a7
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* If signal_pending is non-zero, don't do the call */
|
||||
lw t1, 0(s0)
|
||||
bnez t1, 2f
|
||||
syscall
|
||||
safe_syscall_end:
|
||||
|
||||
/* code path for having successfully executed the syscall */
|
||||
REG_L s0, OFS_S0(sp)
|
||||
PTR_ADDIU sp, sp, FRAME
|
||||
.cfi_remember_state
|
||||
.cfi_adjust_cfa_offset -FRAME
|
||||
.cfi_restore s0
|
||||
bnez a3, 1f
|
||||
jr ra
|
||||
.cfi_restore_state
|
||||
|
||||
/* code path when we didn't execute the syscall */
|
||||
2: REG_L s0, OFS_S0(sp)
|
||||
PTR_ADDIU sp, sp, FRAME
|
||||
.cfi_adjust_cfa_offset -FRAME
|
||||
.cfi_restore s0
|
||||
li v0, QEMU_ERESTARTSYS
|
||||
|
||||
/* code path setting errno */
|
||||
/*
|
||||
* We didn't setup GP on entry, optimistic of the syscall success.
|
||||
* We must do so now to load the address of the helper, as required
|
||||
* by the ABI, into t9.
|
||||
*
|
||||
* Note that SETUP_GPX and SETUP_GPX64 are themselves conditional,
|
||||
* so we can simply let the one that's not empty succeed.
|
||||
*/
|
||||
1: USE_ALT_CP(t0)
|
||||
SETUP_GPX(t1)
|
||||
SETUP_GPX64(t0, t1)
|
||||
PTR_LA t9, safe_syscall_set_errno_tail
|
||||
jr t9
|
||||
|
||||
.cfi_endproc
|
||||
END(safe_syscall_base)
|
94
common-user/host/ppc64/safe-syscall.inc.S
Normal file
94
common-user/host/ppc64/safe-syscall.inc.S
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by common-user/safe-syscall.S
|
||||
*
|
||||
* Written by Richard Henderson <rth@twiddle.net>
|
||||
* Copyright (C) 2016 Red Hat, 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.
|
||||
*/
|
||||
|
||||
.global safe_syscall_base
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_base, @function
|
||||
|
||||
.text
|
||||
|
||||
/* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
*/
|
||||
#if _CALL_ELF == 2
|
||||
safe_syscall_base:
|
||||
.cfi_startproc
|
||||
.localentry safe_syscall_base,0
|
||||
#else
|
||||
.section ".opd","aw"
|
||||
.align 3
|
||||
safe_syscall_base:
|
||||
.quad .L.safe_syscall_base,.TOC.@tocbase,0
|
||||
.previous
|
||||
.L.safe_syscall_base:
|
||||
.cfi_startproc
|
||||
#endif
|
||||
/* We enter with r3 == &signal_pending
|
||||
* r4 == syscall number
|
||||
* r5 ... r10 == syscall arguments
|
||||
* and return the result in r3
|
||||
* and the syscall instruction needs
|
||||
* r0 == syscall number
|
||||
* r3 ... r8 == syscall arguments
|
||||
* and returns the result in r3
|
||||
* Shuffle everything around appropriately.
|
||||
*/
|
||||
std 14, 16(1) /* Preserve r14 in SP+16 */
|
||||
.cfi_offset 14, 16
|
||||
mr 14, 3 /* signal_pending */
|
||||
mr 0, 4 /* syscall number */
|
||||
mr 3, 5 /* syscall arguments */
|
||||
mr 4, 6
|
||||
mr 5, 7
|
||||
mr 6, 8
|
||||
mr 7, 9
|
||||
mr 8, 10
|
||||
|
||||
/* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* if signal_pending is non-zero, don't do the call */
|
||||
lwz 12, 0(14)
|
||||
cmpwi 0, 12, 0
|
||||
bne- 2f
|
||||
sc
|
||||
safe_syscall_end:
|
||||
/* code path when we did execute the syscall */
|
||||
ld 14, 16(1) /* restore r14 */
|
||||
bso- 1f
|
||||
blr
|
||||
|
||||
/* code path when we didn't execute the syscall */
|
||||
2: ld 14, 16(1) /* restore r14 */
|
||||
addi 3, 0, QEMU_ERESTARTSYS
|
||||
|
||||
/* code path setting errno */
|
||||
1: b safe_syscall_set_errno_tail
|
||||
nop /* per abi, for the linker to modify */
|
||||
|
||||
.cfi_endproc
|
||||
|
||||
#if _CALL_ELF == 2
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
||||
#else
|
||||
.size safe_syscall_base, .-.L.safe_syscall_base
|
||||
.size .L.safe_syscall_base, .-.L.safe_syscall_base
|
||||
#endif
|
79
common-user/host/riscv/safe-syscall.inc.S
Normal file
79
common-user/host/riscv/safe-syscall.inc.S
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by common-user/safe-syscall.S
|
||||
*
|
||||
* Written by Richard Henderson <rth@twiddle.net>
|
||||
* Copyright (C) 2018 Linaro, 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.
|
||||
*/
|
||||
|
||||
.global safe_syscall_base
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_base, @function
|
||||
.type safe_syscall_start, @function
|
||||
.type safe_syscall_end, @function
|
||||
|
||||
/*
|
||||
* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
*/
|
||||
safe_syscall_base:
|
||||
.cfi_startproc
|
||||
/*
|
||||
* The syscall calling convention is nearly the same as C:
|
||||
* we enter with a0 == &signal_pending
|
||||
* a1 == syscall number
|
||||
* a2 ... a7 == syscall arguments
|
||||
* and return the result in a0
|
||||
* and the syscall instruction needs
|
||||
* a7 == syscall number
|
||||
* a0 ... a5 == syscall arguments
|
||||
* and returns the result in a0
|
||||
* Shuffle everything around appropriately.
|
||||
*/
|
||||
mv t0, a0 /* signal_pending pointer */
|
||||
mv t1, a1 /* syscall number */
|
||||
mv a0, a2 /* syscall arguments */
|
||||
mv a1, a3
|
||||
mv a2, a4
|
||||
mv a3, a5
|
||||
mv a4, a6
|
||||
mv a5, a7
|
||||
mv a7, t1
|
||||
|
||||
/*
|
||||
* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* If signal_pending is non-zero, don't do the call */
|
||||
lw t1, 0(t0)
|
||||
bnez t1, 2f
|
||||
scall
|
||||
safe_syscall_end:
|
||||
/* code path for having successfully executed the syscall */
|
||||
li t2, -4096
|
||||
bgtu a0, t2, 0f
|
||||
ret
|
||||
|
||||
/* code path setting errno */
|
||||
0: neg a0, a0
|
||||
j safe_syscall_set_errno_tail
|
||||
|
||||
/* code path when we didn't execute the syscall */
|
||||
2: li a0, QEMU_ERESTARTSYS
|
||||
j safe_syscall_set_errno_tail
|
||||
|
||||
.cfi_endproc
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
98
common-user/host/s390x/safe-syscall.inc.S
Normal file
98
common-user/host/s390x/safe-syscall.inc.S
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by common-user/safe-syscall.S
|
||||
*
|
||||
* Written by Richard Henderson <rth@twiddle.net>
|
||||
* Copyright (C) 2016 Red Hat, 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.
|
||||
*/
|
||||
|
||||
.global safe_syscall_base
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_base, @function
|
||||
|
||||
/* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
*/
|
||||
safe_syscall_base:
|
||||
.cfi_startproc
|
||||
stmg %r6,%r15,48(%r15) /* save all call-saved registers */
|
||||
.cfi_offset %r15,-40
|
||||
.cfi_offset %r14,-48
|
||||
.cfi_offset %r13,-56
|
||||
.cfi_offset %r12,-64
|
||||
.cfi_offset %r11,-72
|
||||
.cfi_offset %r10,-80
|
||||
.cfi_offset %r9,-88
|
||||
.cfi_offset %r8,-96
|
||||
.cfi_offset %r7,-104
|
||||
.cfi_offset %r6,-112
|
||||
lgr %r1,%r15
|
||||
lg %r0,8(%r15) /* load eos */
|
||||
aghi %r15,-160
|
||||
.cfi_adjust_cfa_offset 160
|
||||
stg %r1,0(%r15) /* store back chain */
|
||||
stg %r0,8(%r15) /* store eos */
|
||||
|
||||
/*
|
||||
* The syscall calling convention isn't the same as the C one:
|
||||
* we enter with r2 == &signal_pending
|
||||
* r3 == syscall number
|
||||
* r4, r5, r6, (stack) == syscall arguments
|
||||
* and return the result in r2
|
||||
* and the syscall instruction needs
|
||||
* r1 == syscall number
|
||||
* r2 ... r7 == syscall arguments
|
||||
* and returns the result in r2
|
||||
* Shuffle everything around appropriately.
|
||||
*/
|
||||
lgr %r8,%r2 /* signal_pending pointer */
|
||||
lgr %r1,%r3 /* syscall number */
|
||||
lgr %r2,%r4 /* syscall args */
|
||||
lgr %r3,%r5
|
||||
lgr %r4,%r6
|
||||
lmg %r5,%r7,320(%r15)
|
||||
|
||||
/* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* if signal_pending is non-zero, don't do the call */
|
||||
icm %r0,15,0(%r8)
|
||||
jne 2f
|
||||
svc 0
|
||||
safe_syscall_end:
|
||||
|
||||
/* code path for having successfully executed the syscall */
|
||||
lg %r15,0(%r15) /* load back chain */
|
||||
.cfi_remember_state
|
||||
.cfi_adjust_cfa_offset -160
|
||||
lmg %r6,%r15,48(%r15) /* load saved registers */
|
||||
|
||||
lghi %r0, -4095 /* check for syscall error */
|
||||
clgr %r2, %r0
|
||||
blr %r14 /* return on success */
|
||||
lcr %r2, %r2 /* create positive errno */
|
||||
jg safe_syscall_set_errno_tail
|
||||
.cfi_restore_state
|
||||
|
||||
/* code path when we didn't execute the syscall */
|
||||
2: lg %r15,0(%r15) /* load back chain */
|
||||
.cfi_adjust_cfa_offset -160
|
||||
lmg %r6,%r15,48(%r15) /* load saved registers */
|
||||
lghi %r2, QEMU_ERESTARTSYS
|
||||
jg safe_syscall_set_errno_tail
|
||||
|
||||
.cfi_endproc
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
89
common-user/host/sparc64/safe-syscall.inc.S
Normal file
89
common-user/host/sparc64/safe-syscall.inc.S
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by common-user/safe-syscall.S
|
||||
*
|
||||
* Written by Richard Henderson <richard.henderson@linaro.org>
|
||||
* Copyright (C) 2021 Linaro, 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.
|
||||
*/
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
|
||||
.register %g2, #scratch
|
||||
.register %g3, #scratch
|
||||
|
||||
.global safe_syscall_base
|
||||
.global safe_syscall_start
|
||||
.global safe_syscall_end
|
||||
.type safe_syscall_base, @function
|
||||
.type safe_syscall_start, @function
|
||||
.type safe_syscall_end, @function
|
||||
|
||||
#define STACK_BIAS 2047
|
||||
#define PARAM(N) STACK_BIAS + N*8
|
||||
|
||||
/*
|
||||
* This is the entry point for making a system call. The calling
|
||||
* convention here is that of a C varargs function with the
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
*/
|
||||
safe_syscall_base:
|
||||
.cfi_startproc
|
||||
/*
|
||||
* The syscall calling convention isn't the same as the C one:
|
||||
* we enter with o0 == &signal_pending
|
||||
* o1 == syscall number
|
||||
* o2 ... o5, (stack) == syscall arguments
|
||||
* and return the result in x0
|
||||
* and the syscall instruction needs
|
||||
* g1 == syscall number
|
||||
* o0 ... o5 == syscall arguments
|
||||
* and returns the result in o0
|
||||
* Shuffle everything around appropriately.
|
||||
*/
|
||||
mov %o0, %g2 /* signal_pending pointer */
|
||||
mov %o1, %g1 /* syscall number */
|
||||
mov %o2, %o0 /* syscall arguments */
|
||||
mov %o3, %o1
|
||||
mov %o4, %o2
|
||||
mov %o5, %o3
|
||||
ldx [%sp + PARAM(6)], %o4
|
||||
ldx [%sp + PARAM(7)], %o5
|
||||
|
||||
/*
|
||||
* This next sequence of code works in conjunction with the
|
||||
* rewind_if_safe_syscall_function(). If a signal is taken
|
||||
* and the interrupted PC is anywhere between 'safe_syscall_start'
|
||||
* and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
|
||||
* The code sequence must therefore be able to cope with this, and
|
||||
* the syscall instruction must be the final one in the sequence.
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* if signal_pending is non-zero, don't do the call */
|
||||
lduw [%g2], %g3
|
||||
brnz,pn %g3, 2f
|
||||
nop
|
||||
ta 0x6d
|
||||
safe_syscall_end:
|
||||
/* code path for having successfully executed the syscall */
|
||||
bcs,pn %xcc, 1f
|
||||
nop
|
||||
ret
|
||||
nop
|
||||
|
||||
/* code path when we didn't execute the syscall */
|
||||
2: set QEMU_ERESTARTSYS, %o0
|
||||
|
||||
/* code path setting errno */
|
||||
1: mov %o7, %g1
|
||||
call safe_syscall_set_errno_tail
|
||||
mov %g1, %o7
|
||||
|
||||
.cfi_endproc
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* safe-syscall.inc.S : host-specific assembly fragment
|
||||
* to handle signals occurring at the same time as system calls.
|
||||
* This is intended to be included by linux-user/safe-syscall.S
|
||||
* This is intended to be included by common-user/safe-syscall.S
|
||||
*
|
||||
* Copyright (C) 2015 Timothy Edward Baldwin <T.E.Baldwin99@members.leeds.ac.uk>
|
||||
*
|
||||
@ -19,9 +19,6 @@
|
||||
* first argument an 'int *' to the signal_pending flag, the
|
||||
* second one the system call number (as a 'long'), and all further
|
||||
* arguments being syscall arguments (also 'long').
|
||||
* We return a long which is the syscall's return value, which
|
||||
* may be negative-errno on failure. Conversion to the
|
||||
* -1-and-errno-set convention is done by the calling wrapper.
|
||||
*/
|
||||
safe_syscall_base:
|
||||
.cfi_startproc
|
||||
@ -35,9 +32,9 @@ safe_syscall_base:
|
||||
.cfi_adjust_cfa_offset 8
|
||||
.cfi_rel_offset rbp, 0
|
||||
|
||||
/* The syscall calling convention isn't the same as the
|
||||
* C one:
|
||||
* we enter with rdi == *signal_pending
|
||||
/*
|
||||
* The syscall calling convention isn't the same as the C one:
|
||||
* we enter with rdi == &signal_pending
|
||||
* rsi == syscall number
|
||||
* rdx, rcx, r8, r9, (stack), (stack) == syscall arguments
|
||||
* and return the result in rax
|
||||
@ -68,24 +65,41 @@ safe_syscall_base:
|
||||
safe_syscall_start:
|
||||
/* if signal_pending is non-zero, don't do the call */
|
||||
cmpl $0, (%rbp)
|
||||
jnz 1f
|
||||
jnz 2f
|
||||
syscall
|
||||
safe_syscall_end:
|
||||
|
||||
/* code path for having successfully executed the syscall */
|
||||
#if defined(__linux__)
|
||||
/* Linux kernel returns (small) negative errno. */
|
||||
cmp $-4095, %rax
|
||||
jae 0f
|
||||
#elif defined(__FreeBSD__)
|
||||
/* FreeBSD kernel returns positive errno and C bit set. */
|
||||
jc 1f
|
||||
#else
|
||||
#error "unsupported os"
|
||||
#endif
|
||||
pop %rbp
|
||||
.cfi_remember_state
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_restore rbp
|
||||
ret
|
||||
|
||||
1:
|
||||
/* code path when we didn't execute the syscall */
|
||||
.cfi_restore_state
|
||||
mov $-TARGET_ERESTARTSYS, %rax
|
||||
pop %rbp
|
||||
|
||||
#if defined(__linux__)
|
||||
0: neg %eax
|
||||
jmp 1f
|
||||
#endif
|
||||
|
||||
/* code path when we didn't execute the syscall */
|
||||
2: mov $QEMU_ERESTARTSYS, %eax
|
||||
|
||||
/* code path setting errno */
|
||||
1: pop %rbp
|
||||
.cfi_def_cfa_offset 8
|
||||
.cfi_restore rbp
|
||||
ret
|
||||
jmp safe_syscall_set_errno_tail
|
||||
.cfi_endproc
|
||||
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
6
common-user/meson.build
Normal file
6
common-user/meson.build
Normal file
@ -0,0 +1,6 @@
|
||||
common_user_inc += include_directories('host/' / host_arch)
|
||||
|
||||
common_user_ss.add(files(
|
||||
'safe-syscall.S',
|
||||
'safe-syscall-error.c',
|
||||
))
|
25
common-user/safe-syscall-error.c
Normal file
25
common-user/safe-syscall-error.c
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* safe-syscall-error.c: errno setting fragment
|
||||
* This is intended to be invoked by safe-syscall.S
|
||||
*
|
||||
* Written by Richard Henderson <rth@twiddle.net>
|
||||
* Copyright (C) 2021 Red Hat, 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.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "user/safe-syscall.h"
|
||||
|
||||
/*
|
||||
* This is intended to be invoked via tail-call on the error path
|
||||
* from the assembly in host/arch/safe-syscall.inc.S. This takes
|
||||
* care of the host specific addressing of errno.
|
||||
* Return -1 to finalize the return value for safe_syscall_base.
|
||||
*/
|
||||
long safe_syscall_set_errno_tail(int value)
|
||||
{
|
||||
errno = value;
|
||||
return -1;
|
||||
}
|
@ -10,15 +10,12 @@
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "hostdep.h"
|
||||
#include "target_errno_defs.h"
|
||||
#include "special-errno.h"
|
||||
|
||||
/* We have the correct host directory on our include path
|
||||
* so that this will pull in the right fragment for the architecture.
|
||||
*/
|
||||
#ifdef HAVE_SAFE_SYSCALL
|
||||
#include "safe-syscall.inc.S"
|
||||
#endif
|
||||
|
||||
/* We must specifically say that we're happy for the stack to not be
|
||||
* executable, otherwise the toolchain will default to assuming our
|
287
configure
vendored
287
configure
vendored
@ -344,7 +344,6 @@ debug_stack_usage="no"
|
||||
crypto_afalg="no"
|
||||
tls_priority="NORMAL"
|
||||
tpm="$default_feature"
|
||||
libssh="$default_feature"
|
||||
live_block_migration=${default_feature:-yes}
|
||||
numa="$default_feature"
|
||||
replication=${default_feature:-yes}
|
||||
@ -502,42 +501,93 @@ EOF
|
||||
}
|
||||
|
||||
if check_define __linux__ ; then
|
||||
targetos="Linux"
|
||||
targetos=linux
|
||||
elif check_define _WIN32 ; then
|
||||
targetos='MINGW32'
|
||||
targetos=windows
|
||||
elif check_define __OpenBSD__ ; then
|
||||
targetos='OpenBSD'
|
||||
targetos=openbsd
|
||||
elif check_define __sun__ ; then
|
||||
targetos='SunOS'
|
||||
targetos=sunos
|
||||
elif check_define __HAIKU__ ; then
|
||||
targetos='Haiku'
|
||||
targetos=haiku
|
||||
elif check_define __FreeBSD__ ; then
|
||||
targetos='FreeBSD'
|
||||
targetos=freebsd
|
||||
elif check_define __FreeBSD_kernel__ && check_define __GLIBC__; then
|
||||
targetos='GNU/kFreeBSD'
|
||||
targetos=gnu/kfreebsd
|
||||
elif check_define __DragonFly__ ; then
|
||||
targetos='DragonFly'
|
||||
targetos=dragonfly
|
||||
elif check_define __NetBSD__; then
|
||||
targetos='NetBSD'
|
||||
targetos=netbsd
|
||||
elif check_define __APPLE__; then
|
||||
targetos='Darwin'
|
||||
targetos=darwin
|
||||
else
|
||||
# This is a fatal error, but don't report it yet, because we
|
||||
# might be going to just print the --help text, or it might
|
||||
# be the result of a missing compiler.
|
||||
targetos='bogus'
|
||||
targetos=bogus
|
||||
fi
|
||||
|
||||
# Some host OSes need non-standard checks for which CPU to use.
|
||||
# Note that these checks are broken for cross-compilation: if you're
|
||||
# cross-compiling to one of these OSes then you'll need to specify
|
||||
# the correct CPU with the --cpu option.
|
||||
# OS specific
|
||||
|
||||
case $targetos in
|
||||
SunOS)
|
||||
windows)
|
||||
mingw32="yes"
|
||||
plugins="no"
|
||||
pie="no"
|
||||
;;
|
||||
gnu/kfreebsd)
|
||||
bsd="yes"
|
||||
;;
|
||||
freebsd)
|
||||
bsd="yes"
|
||||
bsd_user="yes"
|
||||
make="${MAKE-gmake}"
|
||||
# needed for kinfo_getvmmap(3) in libutil.h
|
||||
;;
|
||||
dragonfly)
|
||||
bsd="yes"
|
||||
make="${MAKE-gmake}"
|
||||
;;
|
||||
netbsd)
|
||||
bsd="yes"
|
||||
make="${MAKE-gmake}"
|
||||
;;
|
||||
openbsd)
|
||||
bsd="yes"
|
||||
make="${MAKE-gmake}"
|
||||
;;
|
||||
darwin)
|
||||
bsd="yes"
|
||||
darwin="yes"
|
||||
# Disable attempts to use ObjectiveC features in os/object.h since they
|
||||
# won't work when we're compiling with gcc as a C compiler.
|
||||
QEMU_CFLAGS="-DOS_OBJECT_USE_OBJC=0 $QEMU_CFLAGS"
|
||||
;;
|
||||
sunos)
|
||||
solaris="yes"
|
||||
make="${MAKE-gmake}"
|
||||
smbd="${SMBD-/usr/sfw/sbin/smbd}"
|
||||
# needed for CMSG_ macros in sys/socket.h
|
||||
QEMU_CFLAGS="-D_XOPEN_SOURCE=600 $QEMU_CFLAGS"
|
||||
# needed for TIOCWIN* defines in termios.h
|
||||
QEMU_CFLAGS="-D__EXTENSIONS__ $QEMU_CFLAGS"
|
||||
# $(uname -m) returns i86pc even on an x86_64 box, so default based on isainfo
|
||||
# Note that this check is broken for cross-compilation: if you're
|
||||
# cross-compiling to one of these OSes then you'll need to specify
|
||||
# the correct CPU with the --cpu option.
|
||||
if test -z "$cpu" && test "$(isainfo -k)" = "amd64"; then
|
||||
cpu="x86_64"
|
||||
fi
|
||||
;;
|
||||
haiku)
|
||||
pie="no"
|
||||
QEMU_CFLAGS="-DB_USE_POSITIVE_POSIX_ERRORS -D_BSD_SOURCE -fPIC $QEMU_CFLAGS"
|
||||
;;
|
||||
linux)
|
||||
linux="yes"
|
||||
linux_user="yes"
|
||||
vhost_user=${default_feature:-yes}
|
||||
;;
|
||||
esac
|
||||
|
||||
if test ! -z "$cpu" ; then
|
||||
@ -585,98 +635,46 @@ else
|
||||
cpu=$(uname -m)
|
||||
fi
|
||||
|
||||
ARCH=
|
||||
# Normalise host CPU name and set ARCH.
|
||||
# Normalise host CPU name, set multilib cflags
|
||||
# Note that this case should only have supported host CPUs, not guests.
|
||||
case "$cpu" in
|
||||
ppc|ppc64|s390x|sparc64|x32|riscv)
|
||||
;;
|
||||
ppc64le)
|
||||
ARCH="ppc64"
|
||||
;;
|
||||
armv*b|armv*l|arm)
|
||||
cpu="arm" ;;
|
||||
|
||||
i386|i486|i586|i686|i86pc|BePC)
|
||||
cpu="i386"
|
||||
;;
|
||||
CPU_CFLAGS="-m32" ;;
|
||||
x32)
|
||||
cpu="x86_64"
|
||||
CPU_CFLAGS="-mx32" ;;
|
||||
x86_64|amd64)
|
||||
cpu="x86_64"
|
||||
;;
|
||||
armv*b|armv*l|arm)
|
||||
cpu="arm"
|
||||
;;
|
||||
aarch64)
|
||||
cpu="aarch64"
|
||||
;;
|
||||
# ??? Only extremely old AMD cpus do not have cmpxchg16b.
|
||||
# If we truly care, we should simply detect this case at
|
||||
# runtime and generate the fallback to serial emulation.
|
||||
CPU_CFLAGS="-m64 -mcx16" ;;
|
||||
|
||||
mips*)
|
||||
cpu="mips"
|
||||
;;
|
||||
cpu="mips" ;;
|
||||
|
||||
ppc)
|
||||
CPU_CFLAGS="-m32" ;;
|
||||
ppc64)
|
||||
CPU_CFLAGS="-m64 -mbig" ;;
|
||||
ppc64le)
|
||||
cpu="ppc64"
|
||||
CPU_CFLAGS="-m64 -mlittle" ;;
|
||||
|
||||
s390)
|
||||
CPU_CFLAGS="-m31" ;;
|
||||
s390x)
|
||||
CPU_CFLAGS="-m64" ;;
|
||||
|
||||
sparc|sun4[cdmuv])
|
||||
cpu="sparc"
|
||||
;;
|
||||
*)
|
||||
# This will result in either an error or falling back to TCI later
|
||||
ARCH=unknown
|
||||
;;
|
||||
esac
|
||||
if test -z "$ARCH"; then
|
||||
ARCH="$cpu"
|
||||
fi
|
||||
|
||||
# OS specific
|
||||
|
||||
case $targetos in
|
||||
MINGW32*)
|
||||
mingw32="yes"
|
||||
supported_os="yes"
|
||||
plugins="no"
|
||||
pie="no"
|
||||
;;
|
||||
GNU/kFreeBSD)
|
||||
bsd="yes"
|
||||
;;
|
||||
FreeBSD)
|
||||
bsd="yes"
|
||||
bsd_user="yes"
|
||||
make="${MAKE-gmake}"
|
||||
# needed for kinfo_getvmmap(3) in libutil.h
|
||||
;;
|
||||
DragonFly)
|
||||
bsd="yes"
|
||||
make="${MAKE-gmake}"
|
||||
;;
|
||||
NetBSD)
|
||||
bsd="yes"
|
||||
make="${MAKE-gmake}"
|
||||
;;
|
||||
OpenBSD)
|
||||
bsd="yes"
|
||||
make="${MAKE-gmake}"
|
||||
;;
|
||||
Darwin)
|
||||
bsd="yes"
|
||||
darwin="yes"
|
||||
# Disable attempts to use ObjectiveC features in os/object.h since they
|
||||
# won't work when we're compiling with gcc as a C compiler.
|
||||
QEMU_CFLAGS="-DOS_OBJECT_USE_OBJC=0 $QEMU_CFLAGS"
|
||||
;;
|
||||
SunOS)
|
||||
solaris="yes"
|
||||
make="${MAKE-gmake}"
|
||||
smbd="${SMBD-/usr/sfw/sbin/smbd}"
|
||||
# needed for CMSG_ macros in sys/socket.h
|
||||
QEMU_CFLAGS="-D_XOPEN_SOURCE=600 $QEMU_CFLAGS"
|
||||
# needed for TIOCWIN* defines in termios.h
|
||||
QEMU_CFLAGS="-D__EXTENSIONS__ $QEMU_CFLAGS"
|
||||
;;
|
||||
Haiku)
|
||||
haiku="yes"
|
||||
pie="no"
|
||||
QEMU_CFLAGS="-DB_USE_POSITIVE_POSIX_ERRORS -D_BSD_SOURCE -fPIC $QEMU_CFLAGS"
|
||||
;;
|
||||
Linux)
|
||||
linux="yes"
|
||||
linux_user="yes"
|
||||
vhost_user=${default_feature:-yes}
|
||||
;;
|
||||
CPU_CFLAGS="-m32 -mv8plus -mcpu=ultrasparc" ;;
|
||||
sparc64)
|
||||
CPU_CFLAGS="-m64 -mcpu=ultrasparc" ;;
|
||||
esac
|
||||
|
||||
: ${make=${MAKE-make}}
|
||||
@ -1080,10 +1078,6 @@ for opt do
|
||||
;;
|
||||
--enable-tpm) tpm="yes"
|
||||
;;
|
||||
--disable-libssh) libssh="no"
|
||||
;;
|
||||
--enable-libssh) libssh="yes"
|
||||
;;
|
||||
--disable-live-block-migration) live_block_migration="no"
|
||||
;;
|
||||
--enable-live-block-migration) live_block_migration="yes"
|
||||
@ -1276,24 +1270,6 @@ local_statedir="${local_statedir:-$prefix/var}"
|
||||
firmwarepath="${firmwarepath:-$datadir/qemu-firmware}"
|
||||
localedir="${localedir:-$datadir/locale}"
|
||||
|
||||
case "$cpu" in
|
||||
ppc) CPU_CFLAGS="-m32" ;;
|
||||
ppc64) CPU_CFLAGS="-m64" ;;
|
||||
sparc) CPU_CFLAGS="-m32 -mv8plus -mcpu=ultrasparc" ;;
|
||||
sparc64) CPU_CFLAGS="-m64 -mcpu=ultrasparc" ;;
|
||||
s390) CPU_CFLAGS="-m31" ;;
|
||||
s390x) CPU_CFLAGS="-m64" ;;
|
||||
i386) CPU_CFLAGS="-m32" ;;
|
||||
x32) CPU_CFLAGS="-mx32" ;;
|
||||
|
||||
# ??? Only extremely old AMD cpus do not have cmpxchg16b.
|
||||
# If we truly care, we should simply detect this case at
|
||||
# runtime and generate the fallback to serial emulation.
|
||||
x86_64) CPU_CFLAGS="-m64 -mcx16" ;;
|
||||
|
||||
# No special flags required for other host CPUs
|
||||
esac
|
||||
|
||||
if eval test -z "\${cross_cc_$cpu}"; then
|
||||
eval "cross_cc_${cpu}=\$cc"
|
||||
cross_cc_vars="$cross_cc_vars cross_cc_${cpu}"
|
||||
@ -1460,7 +1436,6 @@ cat << EOF
|
||||
live-block-migration Block migration in the main migration stream
|
||||
coroutine-pool coroutine freelist (better performance)
|
||||
tpm TPM support
|
||||
libssh ssh block device support
|
||||
numa libnuma support
|
||||
avx2 AVX2 optimization support
|
||||
avx512f AVX512F optimization support
|
||||
@ -2573,21 +2548,6 @@ if test "$modules" = yes; then
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# libssh probe
|
||||
if test "$libssh" != "no" ; then
|
||||
if $pkg_config --exists "libssh >= 0.8.7"; then
|
||||
libssh_cflags=$($pkg_config libssh --cflags)
|
||||
libssh_libs=$($pkg_config libssh --libs)
|
||||
libssh=yes
|
||||
else
|
||||
if test "$libssh" = "yes" ; then
|
||||
error_exit "libssh required for --enable-libssh"
|
||||
fi
|
||||
libssh=no
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# TPM emulation is only on POSIX
|
||||
|
||||
@ -3369,8 +3329,8 @@ QEMU_GA_MSI_MINGW_DLL_PATH="$($pkg_config --variable=prefix glib-2.0)/bin"
|
||||
# Mac OS X ships with a broken assembler
|
||||
roms=
|
||||
if { test "$cpu" = "i386" || test "$cpu" = "x86_64"; } && \
|
||||
test "$targetos" != "Darwin" && test "$targetos" != "SunOS" && \
|
||||
test "$targetos" != "Haiku" && test "$softmmu" = yes ; then
|
||||
test "$targetos" != "darwin" && test "$targetos" != "sunos" && \
|
||||
test "$targetos" != "haiku" && test "$softmmu" = yes ; then
|
||||
# Different host OS linkers have different ideas about the name of the ELF
|
||||
# emulation. Linux and OpenBSD/amd64 use 'elf_i386'; FreeBSD uses the _fbsd
|
||||
# variant; OpenBSD/i386 uses the _obsd variant; and Windows uses i386pe.
|
||||
@ -3447,8 +3407,6 @@ echo "GIT=$git" >> $config_host_mak
|
||||
echo "GIT_SUBMODULES=$git_submodules" >> $config_host_mak
|
||||
echo "GIT_SUBMODULES_ACTION=$git_submodules_action" >> $config_host_mak
|
||||
|
||||
echo "ARCH=$ARCH" >> $config_host_mak
|
||||
|
||||
if test "$debug_tcg" = "yes" ; then
|
||||
echo "CONFIG_DEBUG_TCG=y" >> $config_host_mak
|
||||
fi
|
||||
@ -3484,9 +3442,6 @@ fi
|
||||
if test "$solaris" = "yes" ; then
|
||||
echo "CONFIG_SOLARIS=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$haiku" = "yes" ; then
|
||||
echo "CONFIG_HAIKU=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$static" = "yes" ; then
|
||||
echo "CONFIG_STATIC=y" >> $config_host_mak
|
||||
fi
|
||||
@ -3648,12 +3603,6 @@ if test "$cmpxchg128" = "yes" ; then
|
||||
echo "CONFIG_CMPXCHG128=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$libssh" = "yes" ; then
|
||||
echo "CONFIG_LIBSSH=y" >> $config_host_mak
|
||||
echo "LIBSSH_CFLAGS=$libssh_cflags" >> $config_host_mak
|
||||
echo "LIBSSH_LIBS=$libssh_libs" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$live_block_migration" = "yes" ; then
|
||||
echo "CONFIG_LIVE_BLOCK_MIGRATION=y" >> $config_host_mak
|
||||
fi
|
||||
@ -3777,10 +3726,10 @@ fi
|
||||
if test "$linux" = "yes" ; then
|
||||
mkdir -p linux-headers
|
||||
case "$cpu" in
|
||||
i386|x86_64|x32)
|
||||
i386|x86_64)
|
||||
linux_arch=x86
|
||||
;;
|
||||
ppc|ppc64|ppc64le)
|
||||
ppc|ppc64)
|
||||
linux_arch=powerpc
|
||||
;;
|
||||
s390x)
|
||||
@ -3805,7 +3754,7 @@ fi
|
||||
|
||||
for target in $target_list; do
|
||||
target_dir="$target"
|
||||
target_name=$(echo $target | cut -d '-' -f 1)
|
||||
target_name=$(echo $target | cut -d '-' -f 1)$EXESUF
|
||||
mkdir -p $target_dir
|
||||
case $target in
|
||||
*-user) symlink "../qemu-$target_name" "$target_dir/qemu-$target_name" ;;
|
||||
@ -3832,7 +3781,6 @@ if test "$safe_stack" = "yes"; then
|
||||
fi
|
||||
|
||||
# If we're using a separate build tree, set it up now.
|
||||
# DIRS are directories which we simply mkdir in the build tree;
|
||||
# LINKS are things to symlink back into the source tree
|
||||
# (these can be both files and directories).
|
||||
# Caution: do not add files or directories here using wildcards. This
|
||||
@ -3844,12 +3792,6 @@ fi
|
||||
# UNLINK is used to remove symlinks from older development versions
|
||||
# that might get into the way when doing "git update" without doing
|
||||
# a "make distclean" in between.
|
||||
DIRS="tests tests/tcg tests/qapi-schema tests/qtest/libqos"
|
||||
DIRS="$DIRS tests/qtest tests/qemu-iotests tests/vm tests/fp tests/qgraph"
|
||||
DIRS="$DIRS docs docs/interop fsdev scsi"
|
||||
DIRS="$DIRS pc-bios/optionrom pc-bios/s390-ccw"
|
||||
DIRS="$DIRS roms/seabios"
|
||||
DIRS="$DIRS contrib/plugins/"
|
||||
LINKS="Makefile"
|
||||
LINKS="$LINKS tests/tcg/Makefile.target"
|
||||
LINKS="$LINKS pc-bios/optionrom/Makefile"
|
||||
@ -3871,16 +3813,15 @@ for bios_file in \
|
||||
$source_path/pc-bios/*.img \
|
||||
$source_path/pc-bios/openbios-* \
|
||||
$source_path/pc-bios/u-boot.* \
|
||||
$source_path/pc-bios/edk2-*.fd.bz2 \
|
||||
$source_path/pc-bios/palcode-* \
|
||||
$source_path/pc-bios/qemu_vga.ndrv
|
||||
|
||||
do
|
||||
LINKS="$LINKS pc-bios/$(basename $bios_file)"
|
||||
done
|
||||
mkdir -p $DIRS
|
||||
for f in $LINKS ; do
|
||||
if [ -e "$source_path/$f" ]; then
|
||||
mkdir -p `dirname ./$f`
|
||||
symlink "$source_path/$f" "$f"
|
||||
fi
|
||||
done
|
||||
@ -3954,27 +3895,13 @@ if test "$skip_meson" = no; then
|
||||
if test "$cross_compile" = "yes"; then
|
||||
cross_arg="--cross-file config-meson.cross"
|
||||
echo "[host_machine]" >> $cross
|
||||
if test "$mingw32" = "yes" ; then
|
||||
echo "system = 'windows'" >> $cross
|
||||
fi
|
||||
if test "$linux" = "yes" ; then
|
||||
echo "system = 'linux'" >> $cross
|
||||
fi
|
||||
if test "$darwin" = "yes" ; then
|
||||
echo "system = 'darwin'" >> $cross
|
||||
fi
|
||||
case "$ARCH" in
|
||||
echo "system = '$targetos'" >> $cross
|
||||
case "$cpu" in
|
||||
i386)
|
||||
echo "cpu_family = 'x86'" >> $cross
|
||||
;;
|
||||
x86_64|x32)
|
||||
echo "cpu_family = 'x86_64'" >> $cross
|
||||
;;
|
||||
ppc64le)
|
||||
echo "cpu_family = 'ppc64'" >> $cross
|
||||
;;
|
||||
*)
|
||||
echo "cpu_family = '$ARCH'" >> $cross
|
||||
echo "cpu_family = '$cpu'" >> $cross
|
||||
;;
|
||||
esac
|
||||
echo "cpu = '$cpu'" >> $cross
|
||||
|
5
cpu.c
5
cpu.c
@ -318,12 +318,10 @@ void cpu_exec_realizefn(CPUState *cpu, Error **errp)
|
||||
if (!accel_cpu_realizefn(cpu, errp)) {
|
||||
return;
|
||||
}
|
||||
#ifdef CONFIG_TCG
|
||||
/* NB: errp parameter is unused currently */
|
||||
if (tcg_enabled()) {
|
||||
tcg_exec_realizefn(cpu, errp);
|
||||
}
|
||||
#endif /* CONFIG_TCG */
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
assert(qdev_get_vmsd(DEVICE(cpu)) == NULL ||
|
||||
@ -350,12 +348,9 @@ void cpu_exec_unrealizefn(CPUState *cpu)
|
||||
vmstate_unregister(NULL, &vmstate_cpu_common, cpu);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_TCG
|
||||
/* NB: errp parameter is unused currently */
|
||||
if (tcg_enabled()) {
|
||||
tcg_exec_unrealizefn(cpu);
|
||||
}
|
||||
#endif /* CONFIG_TCG */
|
||||
|
||||
cpu_list_remove(cpu);
|
||||
}
|
||||
|
@ -315,6 +315,15 @@ This machine is deprecated because we have enough AST2500 based OpenPOWER
|
||||
machines. It can be easily replaced by the ``witherspoon-bmc`` or the
|
||||
``romulus-bmc`` machines.
|
||||
|
||||
PPC 405 ``taihu`` machine (since 7.0)
|
||||
'''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The PPC 405 CPU is a system-on-a-chip, so all 405 machines are very similar,
|
||||
except for some external periphery. However, the periphery of the ``taihu``
|
||||
machine is hardly emulated at all (e.g. neither the LCD nor the USB part had
|
||||
been implemented), so there is not much value added by this board. Use the
|
||||
``ref405ep`` machine instead.
|
||||
|
||||
Backend options
|
||||
---------------
|
||||
|
||||
|
@ -179,7 +179,7 @@ Primary:
|
||||
|
||||
Secondary:
|
||||
-drive if=none,driver=raw,file.filename=1.raw,id=colo1 \
|
||||
-drive if=none,id=childs1,driver=replication,mode=secondary,top-id=childs1
|
||||
-drive if=none,id=childs1,driver=replication,mode=secondary,top-id=top-disk1
|
||||
file.file.filename=active_disk.qcow2,\
|
||||
file.driver=qcow2,\
|
||||
file.backing.file.filename=hidden_disk.qcow2,\
|
||||
|
@ -18,12 +18,12 @@ if sphinx_build.found()
|
||||
# This is a bit awkward but works: create a trivial document and
|
||||
# try to run it with our configuration file (which enforces a
|
||||
# version requirement). This will fail if sphinx-build is too old.
|
||||
run_command('mkdir', ['-p', tmpdir / 'sphinx'])
|
||||
run_command('touch', [tmpdir / 'sphinx/index.rst'])
|
||||
run_command('mkdir', ['-p', tmpdir / 'sphinx'], check: true)
|
||||
run_command('touch', [tmpdir / 'sphinx/index.rst'], check: true)
|
||||
sphinx_build_test_out = run_command(SPHINX_ARGS + [
|
||||
'-c', meson.current_source_dir(),
|
||||
'-b', 'html', tmpdir / 'sphinx',
|
||||
tmpdir / 'sphinx/out'])
|
||||
tmpdir / 'sphinx/out'], check: false)
|
||||
build_docs = (sphinx_build_test_out.returncode() == 0)
|
||||
|
||||
if not build_docs
|
||||
|
100
docs/specs/ppc-spapr-hcalls.rst
Normal file
100
docs/specs/ppc-spapr-hcalls.rst
Normal file
@ -0,0 +1,100 @@
|
||||
sPAPR hypervisor calls
|
||||
----------------------
|
||||
|
||||
When used with the ``pseries`` machine type, ``qemu-system-ppc64`` implements
|
||||
a set of hypervisor calls (a.k.a. hcalls) defined in the `Linux on Power
|
||||
Architecture Reference document (LoPAR)
|
||||
<https://cdn.openpowerfoundation.org/wp-content/uploads/2020/07/LoPAR-20200812.pdf>`_.
|
||||
This document is a subset of the Power Architecture Platform Reference (PAPR+)
|
||||
specification (IBM internal only), which is what PowerVM, the IBM proprietary
|
||||
hypervisor, adheres to.
|
||||
|
||||
The subset in LoPAR is selected based on the requirements of Linux as a guest.
|
||||
|
||||
In addition to those calls, we have added our own private hypervisor
|
||||
calls which are mostly used as a private interface between the firmware
|
||||
running in the guest and QEMU.
|
||||
|
||||
All those hypercalls start at hcall number 0xf000 which correspond
|
||||
to an implementation specific range in PAPR.
|
||||
|
||||
H_RTAS (0xf000)
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
RTAS stands for Run-Time Abstraction Sercies and is a set of runtime services
|
||||
generally provided by the firmware inside the guest to the operating system. It
|
||||
predates the existence of hypervisors (it was originally an extension to Open
|
||||
Firmware) and is still used by PAPR and LoPAR to provide various services that
|
||||
are not performance sensitive.
|
||||
|
||||
We currently implement the RTAS services in QEMU itself. The actual RTAS
|
||||
"firmware" blob in the guest is a small stub of a few instructions which
|
||||
calls our private H_RTAS hypervisor call to pass the RTAS calls to QEMU.
|
||||
|
||||
Arguments:
|
||||
|
||||
``r3``: ``H_RTAS (0xf000)``
|
||||
|
||||
``r4``: Guest physical address of RTAS parameter block.
|
||||
|
||||
Returns:
|
||||
|
||||
``H_SUCCESS``: Successfully called the RTAS function (RTAS result will have
|
||||
been stored in the parameter block).
|
||||
|
||||
``H_PARAMETER``: Unknown token.
|
||||
|
||||
H_LOGICAL_MEMOP (0xf001)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When the guest runs in "real mode" (in powerpc terminology this means with MMU
|
||||
disabled, i.e. guest effective address equals to guest physical address), it
|
||||
only has access to a subset of memory and no I/Os.
|
||||
|
||||
PAPR and LoPAR provides a set of hypervisor calls to perform cacheable or
|
||||
non-cacheable accesses to any guest physical addresses that the
|
||||
guest can use in order to access IO devices while in real mode.
|
||||
|
||||
This is typically used by the firmware running in the guest.
|
||||
|
||||
However, doing a hypercall for each access is extremely inefficient
|
||||
(even more so when running KVM) when accessing the frame buffer. In
|
||||
that case, things like scrolling become unusably slow.
|
||||
|
||||
This hypercall allows the guest to request a "memory op" to be applied
|
||||
to memory. The supported memory ops at this point are to copy a range
|
||||
of memory (supports overlap of source and destination) and XOR which
|
||||
is used by our SLOF firmware to invert the screen.
|
||||
|
||||
Arguments:
|
||||
|
||||
``r3 ``: ``H_LOGICAL_MEMOP (0xf001)``
|
||||
|
||||
``r4``: Guest physical address of destination.
|
||||
|
||||
``r5``: Guest physical address of source.
|
||||
|
||||
``r6``: Individual element size, defined by the binary logarithm of the
|
||||
desired size. Supported values are:
|
||||
|
||||
``0`` = 1 byte
|
||||
|
||||
``1`` = 2 bytes
|
||||
|
||||
``2`` = 4 bytes
|
||||
|
||||
``3`` = 8 bytes
|
||||
|
||||
``r7``: Number of elements.
|
||||
|
||||
``r8``: Operation. Supported values are:
|
||||
|
||||
``0``: copy
|
||||
|
||||
``1``: xor
|
||||
|
||||
Returns:
|
||||
|
||||
``H_SUCCESS``: Success.
|
||||
|
||||
``H_PARAMETER``: Invalid argument.
|
@ -1,78 +0,0 @@
|
||||
When used with the "pseries" machine type, QEMU-system-ppc64 implements
|
||||
a set of hypervisor calls using a subset of the server "PAPR" specification
|
||||
(IBM internal at this point), which is also what IBM's proprietary hypervisor
|
||||
adheres too.
|
||||
|
||||
The subset is selected based on the requirements of Linux as a guest.
|
||||
|
||||
In addition to those calls, we have added our own private hypervisor
|
||||
calls which are mostly used as a private interface between the firmware
|
||||
running in the guest and QEMU.
|
||||
|
||||
All those hypercalls start at hcall number 0xf000 which correspond
|
||||
to an implementation specific range in PAPR.
|
||||
|
||||
- H_RTAS (0xf000)
|
||||
|
||||
RTAS is a set of runtime services generally provided by the firmware
|
||||
inside the guest to the operating system. It predates the existence
|
||||
of hypervisors (it was originally an extension to Open Firmware) and
|
||||
is still used by PAPR to provide various services that aren't performance
|
||||
sensitive.
|
||||
|
||||
We currently implement the RTAS services in QEMU itself. The actual RTAS
|
||||
"firmware" blob in the guest is a small stub of a few instructions which
|
||||
calls our private H_RTAS hypervisor call to pass the RTAS calls to QEMU.
|
||||
|
||||
Arguments:
|
||||
|
||||
r3 : H_RTAS (0xf000)
|
||||
r4 : Guest physical address of RTAS parameter block
|
||||
|
||||
Returns:
|
||||
|
||||
H_SUCCESS : Successfully called the RTAS function (RTAS result
|
||||
will have been stored in the parameter block)
|
||||
H_PARAMETER : Unknown token
|
||||
|
||||
- H_LOGICAL_MEMOP (0xf001)
|
||||
|
||||
When the guest runs in "real mode" (in powerpc lingua this means
|
||||
with MMU disabled, ie guest effective == guest physical), it only
|
||||
has access to a subset of memory and no IOs.
|
||||
|
||||
PAPR provides a set of hypervisor calls to perform cacheable or
|
||||
non-cacheable accesses to any guest physical addresses that the
|
||||
guest can use in order to access IO devices while in real mode.
|
||||
|
||||
This is typically used by the firmware running in the guest.
|
||||
|
||||
However, doing a hypercall for each access is extremely inefficient
|
||||
(even more so when running KVM) when accessing the frame buffer. In
|
||||
that case, things like scrolling become unusably slow.
|
||||
|
||||
This hypercall allows the guest to request a "memory op" to be applied
|
||||
to memory. The supported memory ops at this point are to copy a range
|
||||
of memory (supports overlap of source and destination) and XOR which
|
||||
is used by our SLOF firmware to invert the screen.
|
||||
|
||||
Arguments:
|
||||
|
||||
r3: H_LOGICAL_MEMOP (0xf001)
|
||||
r4: Guest physical address of destination
|
||||
r5: Guest physical address of source
|
||||
r6: Individual element size
|
||||
0 = 1 byte
|
||||
1 = 2 bytes
|
||||
2 = 4 bytes
|
||||
3 = 8 bytes
|
||||
r7: Number of elements
|
||||
r8: Operation
|
||||
0 = copy
|
||||
1 = xor
|
||||
|
||||
Returns:
|
||||
|
||||
H_SUCCESS : Success
|
||||
H_PARAMETER : Invalid argument
|
||||
|
@ -14,6 +14,7 @@ AST2400 SoC based machines :
|
||||
|
||||
- ``palmetto-bmc`` OpenPOWER Palmetto POWER8 BMC
|
||||
- ``quanta-q71l-bmc`` OpenBMC Quanta BMC
|
||||
- ``supermicrox11-bmc`` Supermicro X11 BMC
|
||||
|
||||
AST2500 SoC based machines :
|
||||
|
||||
@ -21,12 +22,16 @@ AST2500 SoC based machines :
|
||||
- ``romulus-bmc`` OpenPOWER Romulus POWER9 BMC
|
||||
- ``witherspoon-bmc`` OpenPOWER Witherspoon POWER9 BMC
|
||||
- ``sonorapass-bmc`` OCP SonoraPass BMC
|
||||
- ``swift-bmc`` OpenPOWER Swift BMC POWER9
|
||||
- ``swift-bmc`` OpenPOWER Swift BMC POWER9 (to be removed in v7.0)
|
||||
- ``fp5280g2-bmc`` Inspur FP5280G2 BMC
|
||||
- ``g220a-bmc`` Bytedance G220A BMC
|
||||
|
||||
AST2600 SoC based machines :
|
||||
|
||||
- ``ast2600-evb`` Aspeed AST2600 Evaluation board (Cortex-A7)
|
||||
- ``tacoma-bmc`` OpenPOWER Witherspoon POWER9 AST2600 BMC
|
||||
- ``rainier-bmc`` IBM Rainier POWER10 BMC
|
||||
- ``fuji-bmc`` Facebook Fuji BMC
|
||||
|
||||
Supported devices
|
||||
-----------------
|
||||
@ -51,13 +56,13 @@ Supported devices
|
||||
* Front LEDs (PCA9552 on I2C bus)
|
||||
* LPC Peripheral Controller (a subset of subdevices are supported)
|
||||
* Hash/Crypto Engine (HACE) - Hash support only. TODO: HMAC and RSA
|
||||
* ADC
|
||||
|
||||
|
||||
Missing devices
|
||||
---------------
|
||||
|
||||
* Coprocessor support
|
||||
* ADC (out of tree implementation)
|
||||
* PWM and Fan Controller
|
||||
* Slave GPIO Controller
|
||||
* Super I/O Controller
|
||||
@ -73,16 +78,25 @@ Missing devices
|
||||
Boot options
|
||||
------------
|
||||
|
||||
The Aspeed machines can be started using the ``-kernel`` option to
|
||||
load a Linux kernel or from a firmware. Images can be downloaded from
|
||||
the OpenBMC jenkins :
|
||||
The Aspeed machines can be started using the ``-kernel`` and ``-dtb`` options
|
||||
to load a Linux kernel or from a firmware. Images can be downloaded from the
|
||||
OpenBMC jenkins :
|
||||
|
||||
https://jenkins.openbmc.org/job/ci-openbmc/lastSuccessfulBuild/distro=ubuntu,label=docker-builder
|
||||
https://jenkins.openbmc.org/job/ci-openbmc/lastSuccessfulBuild/
|
||||
|
||||
or directly from the OpenBMC GitHub release repository :
|
||||
|
||||
https://github.com/openbmc/openbmc/releases
|
||||
|
||||
To boot a kernel directly from a Linux build tree:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ qemu-system-arm -M ast2600-evb -nographic \
|
||||
-kernel arch/arm/boot/zImage \
|
||||
-dtb arch/arm/boot/dts/aspeed-ast2600-evb.dtb \
|
||||
-initrd rootfs.cpio
|
||||
|
||||
The image should be attached as an MTD drive. Run :
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -141,8 +141,7 @@ To launch a SGX guest:
|
||||
|qemu_system_x86| \\
|
||||
-cpu host,+sgx-provisionkey \\
|
||||
-object memory-backend-epc,id=mem1,size=64M,prealloc=on \\
|
||||
-object memory-backend-epc,id=mem2,size=28M \\
|
||||
-M sgx-epc.0.memdev=mem1,sgx-epc.1.memdev=mem2
|
||||
-M sgx-epc.0.memdev=mem1,sgx-epc.0.node=0
|
||||
|
||||
Utilizing SGX in the guest requires a kernel/OS with SGX support.
|
||||
The support can be determined in guest by::
|
||||
@ -152,8 +151,32 @@ The support can be determined in guest by::
|
||||
and SGX epc info by::
|
||||
|
||||
$ dmesg | grep sgx
|
||||
[ 1.242142] sgx: EPC section 0x180000000-0x181bfffff
|
||||
[ 1.242319] sgx: EPC section 0x181c00000-0x1837fffff
|
||||
[ 0.182807] sgx: EPC section 0x140000000-0x143ffffff
|
||||
[ 0.183695] sgx: [Firmware Bug]: Unable to map EPC section to online node. Fallback to the NUMA node 0.
|
||||
|
||||
To launch a SGX numa guest:
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
|qemu_system_x86| \\
|
||||
-cpu host,+sgx-provisionkey \\
|
||||
-object memory-backend-ram,size=2G,host-nodes=0,policy=bind,id=node0 \\
|
||||
-object memory-backend-epc,id=mem0,size=64M,prealloc=on,host-nodes=0,policy=bind \\
|
||||
-numa node,nodeid=0,cpus=0-1,memdev=node0 \\
|
||||
-object memory-backend-ram,size=2G,host-nodes=1,policy=bind,id=node1 \\
|
||||
-object memory-backend-epc,id=mem1,size=28M,prealloc=on,host-nodes=1,policy=bind \\
|
||||
-numa node,nodeid=1,cpus=2-3,memdev=node1 \\
|
||||
-M sgx-epc.0.memdev=mem0,sgx-epc.0.node=0,sgx-epc.1.memdev=mem1,sgx-epc.1.node=1
|
||||
|
||||
and SGX epc numa info by::
|
||||
|
||||
$ dmesg | grep sgx
|
||||
[ 0.369937] sgx: EPC section 0x180000000-0x183ffffff
|
||||
[ 0.370259] sgx: EPC section 0x184000000-0x185bfffff
|
||||
|
||||
$ dmesg | grep SRAT
|
||||
[ 0.009981] ACPI: SRAT: Node 0 PXM 0 [mem 0x180000000-0x183ffffff]
|
||||
[ 0.009982] ACPI: SRAT: Node 1 PXM 1 [mem 0x184000000-0x185bfffff]
|
||||
|
||||
References
|
||||
----------
|
||||
|
@ -1,7 +1,7 @@
|
||||
PowerNV family boards (``powernv8``, ``powernv9``)
|
||||
PowerNV family boards (``powernv8``, ``powernv9``, ``powernv10``)
|
||||
==================================================================
|
||||
|
||||
PowerNV (as Non-Virtualized) is the "baremetal" platform using the
|
||||
PowerNV (as Non-Virtualized) is the "bare metal" platform using the
|
||||
OPAL firmware. It runs Linux on IBM and OpenPOWER systems and it can
|
||||
be used as an hypervisor OS, running KVM guests, or simply as a host
|
||||
OS.
|
||||
@ -16,16 +16,14 @@ Supported devices
|
||||
-----------------
|
||||
|
||||
* Multi processor support for POWER8, POWER8NVL and POWER9.
|
||||
* XSCOM, serial communication sideband bus to configure chiplets
|
||||
* Simple LPC Controller
|
||||
* Processor Service Interface (PSI) Controller
|
||||
* Interrupt Controller, XICS (POWER8) and XIVE (POWER9)
|
||||
* POWER8 PHB3 PCIe Host bridge and POWER9 PHB4 PCIe Host bridge
|
||||
* Simple OCC is an on-chip microcontroller used for power management
|
||||
tasks
|
||||
* iBT device to handle BMC communication, with the internal BMC
|
||||
simulator provided by QEMU or an external BMC such as an Aspeed
|
||||
QEMU machine.
|
||||
* XSCOM, serial communication sideband bus to configure chiplets.
|
||||
* Simple LPC Controller.
|
||||
* Processor Service Interface (PSI) Controller.
|
||||
* Interrupt Controller, XICS (POWER8) and XIVE (POWER9) and XIVE2 (Power10).
|
||||
* POWER8 PHB3 PCIe Host bridge and POWER9 PHB4 PCIe Host bridge.
|
||||
* Simple OCC is an on-chip micro-controller used for power management tasks.
|
||||
* iBT device to handle BMC communication, with the internal BMC simulator
|
||||
provided by QEMU or an external BMC such as an Aspeed QEMU machine.
|
||||
* PNOR containing the different firmware partitions.
|
||||
|
||||
Missing devices
|
||||
@ -33,31 +31,42 @@ Missing devices
|
||||
|
||||
A lot is missing, among which :
|
||||
|
||||
* POWER10 processor
|
||||
* XIVE2 (POWER10) interrupt controller
|
||||
* I2C controllers (yet to be merged)
|
||||
* NPU/NPU2/NPU3 controllers
|
||||
* EEH support for PCIe Host bridge controllers
|
||||
* NX controller
|
||||
* VAS controller
|
||||
* chipTOD (Time Of Day)
|
||||
* I2C controllers (yet to be merged).
|
||||
* NPU/NPU2/NPU3 controllers.
|
||||
* EEH support for PCIe Host bridge controllers.
|
||||
* NX controller.
|
||||
* VAS controller.
|
||||
* chipTOD (Time Of Day).
|
||||
* Self Boot Engine (SBE).
|
||||
* FSI bus
|
||||
* FSI bus.
|
||||
|
||||
Firmware
|
||||
--------
|
||||
|
||||
The OPAL firmware (OpenPower Abstraction Layer) for OpenPower systems
|
||||
includes the runtime services ``skiboot`` and the bootloader kernel and
|
||||
initramfs ``skiroot``. Source code can be found on GitHub:
|
||||
initramfs ``skiroot``. Source code can be found on the `OpenPOWER account at
|
||||
GitHub <https://github.com/open-power>`_.
|
||||
|
||||
https://github.com/open-power.
|
||||
|
||||
Prebuilt images of ``skiboot`` and ``skiroot`` are made available on the `OpenPOWER <https://github.com/open-power/op-build/releases/>`__ site.
|
||||
Prebuilt images of ``skiboot`` and ``skiroot`` are made available on the
|
||||
`OpenPOWER <https://github.com/open-power/op-build/releases/>`__ site.
|
||||
|
||||
QEMU includes a prebuilt image of ``skiboot`` which is updated when a
|
||||
more recent version is required by the models.
|
||||
|
||||
Current acceleration status
|
||||
---------------------------
|
||||
|
||||
KVM acceleration in Linux Power hosts is provided by the kvm-hv and
|
||||
kvm-pr modules. kvm-hv is adherent to PAPR and it's not compliant with
|
||||
powernv. kvm-pr in theory could be used as a valid accel option but
|
||||
this isn't supported by kvm-pr at this moment.
|
||||
|
||||
To spare users from dealing with not so informative errors when attempting
|
||||
to use accel=kvm, the powernv machine will throw an error informing that
|
||||
KVM is not supported. This can be revisited in the future if kvm-pr (or
|
||||
any other KVM alternative) is usable as KVM accel for this machine.
|
||||
|
||||
Boot options
|
||||
------------
|
||||
|
||||
@ -83,6 +92,7 @@ and a SATA disk :
|
||||
|
||||
Complex PCIe configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Six PHBs are defined per chip (POWER9) but no default PCI layout is
|
||||
provided (to be compatible with libvirt). One PCI device can be added
|
||||
on any of the available PCIe slots using command line options such as:
|
||||
@ -157,7 +167,7 @@ one on the command line :
|
||||
The files `palmetto-SDR.bin <http://www.kaod.org/qemu/powernv/palmetto-SDR.bin>`__
|
||||
and `palmetto-FRU.bin <http://www.kaod.org/qemu/powernv/palmetto-FRU.bin>`__
|
||||
define a Sensor Data Record repository and a Field Replaceable Unit
|
||||
inventory for a palmetto BMC. They can be used to extend the QEMU BMC
|
||||
inventory for a Palmetto BMC. They can be used to extend the QEMU BMC
|
||||
simulator.
|
||||
|
||||
.. code-block:: bash
|
||||
@ -189,4 +199,8 @@ CAVEATS
|
||||
-------
|
||||
|
||||
* No support for multiple HW threads (SMT=1). Same as pseries.
|
||||
* CPU can hang when doing intensive I/Os. Use ``-append powersave=off`` in that case.
|
||||
|
||||
Maintainer contact information
|
||||
------------------------------
|
||||
|
||||
Cédric Le Goater <clg@kaod.org>
|
||||
|
@ -1,12 +1,238 @@
|
||||
pSeries family boards (``pseries``)
|
||||
===================================
|
||||
|
||||
The Power machine para-virtualized environment described by the `Linux on Power
|
||||
Architecture Reference document (LoPAR)
|
||||
<https://openpowerfoundation.org/wp-content/uploads/2020/07/LoPAR-20200812.pdf>`_
|
||||
is called pSeries. This environment is also known as sPAPR, System p guests, or
|
||||
simply Power Linux guests (although it is capable of running other operating
|
||||
systems, such as AIX).
|
||||
|
||||
Even though pSeries is designed to behave as a guest environment, it is also
|
||||
capable of acting as a hypervisor OS, providing, on that role, nested
|
||||
virtualization capabilities.
|
||||
|
||||
Supported devices
|
||||
-----------------
|
||||
|
||||
* Multi processor support for many Power processors generations: POWER7,
|
||||
POWER7+, POWER8, POWER8NVL, POWER9, and Power10. Support for POWER5+ exists,
|
||||
but its state is unknown.
|
||||
* Interrupt Controller, XICS (POWER8) and XIVE (POWER9 and Power10)
|
||||
* vPHB PCIe Host bridge.
|
||||
* vscsi and vnet devices, compatible with the same devices available on a
|
||||
PowerVM hypervisor with VIOS managing LPARs.
|
||||
* Virtio based devices.
|
||||
* PCIe device pass through.
|
||||
|
||||
Missing devices
|
||||
---------------
|
||||
|
||||
* SPICE support.
|
||||
|
||||
Firmware
|
||||
--------
|
||||
|
||||
`SLOF <https://github.com/aik/SLOF>`_ (Slimline Open Firmware) is an
|
||||
implementation of the `IEEE 1275-1994, Standard for Boot (Initialization
|
||||
Configuration) Firmware: Core Requirements and Practices
|
||||
<https://standards.ieee.org/standard/1275-1994.html>`_.
|
||||
|
||||
QEMU includes a prebuilt image of SLOF which is updated when a more recent
|
||||
version is required.
|
||||
|
||||
Build directions
|
||||
----------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./configure --target-list=ppc64-softmmu && make
|
||||
|
||||
Running instructions
|
||||
--------------------
|
||||
|
||||
Someone can select the pSeries machine type by running QEMU with the following
|
||||
options:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
qemu-system-ppc64 -M pseries <other QEMU arguments>
|
||||
|
||||
sPAPR devices
|
||||
-------------
|
||||
|
||||
The sPAPR specification defines a set of para-virtualized devices, which are
|
||||
also supported by the pSeries machine in QEMU and can be instantiated with the
|
||||
``-device`` option:
|
||||
|
||||
* ``spapr-vlan`` : a virtual network interface.
|
||||
* ``spapr-vscsi`` : a virtual SCSI disk interface.
|
||||
* ``spapr-rng`` : a pseudo-device for passing random number generator data to the
|
||||
guest (see the `H_RANDOM hypercall feature
|
||||
<https://wiki.qemu.org/Features/HRandomHypercall>`_ for details).
|
||||
* ``spapr-vty``: a virtual teletype.
|
||||
* ``spapr-pci-host-bridge``: a PCI host bridge.
|
||||
* ``tpm-spapr``: a Trusted Platform Module (TPM).
|
||||
* ``spapr-tpm-proxy``: a TPM proxy.
|
||||
|
||||
These are compatible with the devices historically available for use when
|
||||
running the IBM PowerVM hypervisor with LPARs.
|
||||
|
||||
However, since these devices have originally been specified with another
|
||||
hypervisor and non-Linux guests in mind, you should use the virtio counterparts
|
||||
(virtio-net, virtio-blk/scsi and virtio-rng for instance) if possible instead,
|
||||
since they will most probably give you better performance with Linux guests in a
|
||||
QEMU environment.
|
||||
|
||||
The pSeries machine in QEMU is always instantiated with the following devices:
|
||||
|
||||
* A NVRAM device (``spapr-nvram``).
|
||||
* A virtual teletype (``spapr-vty``).
|
||||
* A PCI host bridge (``spapr-pci-host-bridge``).
|
||||
|
||||
Hence, it is not needed to add them manually, unless you use the ``-nodefaults``
|
||||
command line option in QEMU.
|
||||
|
||||
In the case of the default ``spapr-nvram`` device, if someone wants to make the
|
||||
contents of the NVRAM device persistent, they will need to specify a PFLASH
|
||||
device when starting QEMU, i.e. either use
|
||||
``-drive if=pflash,file=<filename>,format=raw`` to set the default PFLASH
|
||||
device, or specify one with an ID
|
||||
(``-drive if=none,file=<filename>,format=raw,id=pfid``) and pass that ID to the
|
||||
NVRAM device with ``-global spapr-nvram.drive=pfid``.
|
||||
|
||||
sPAPR specification
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The main source of documentation on the sPAPR standard is the `Linux on Power
|
||||
Architecture Reference document (LoPAR)
|
||||
<https://openpowerfoundation.org/wp-content/uploads/2020/07/LoPAR-20200812.pdf>`_.
|
||||
However, documentation specific to QEMU's implementation of the specification
|
||||
can also be found in QEMU documentation:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
../../specs/ppc-spapr-hcalls.rst
|
||||
../../specs/ppc-spapr-numa.rst
|
||||
../../specs/ppc-spapr-xive.rst
|
||||
|
||||
Other documentation available in QEMU docs directory:
|
||||
|
||||
* Hot plug (``/docs/specs/ppc-spapr-hotplug.txt``).
|
||||
* Hypervisor calls needed by the Ultravisor
|
||||
(``/docs/specs/ppc-spapr-uv-hcalls.txt``).
|
||||
|
||||
Switching between the KVM-PR and KVM-HV kernel module
|
||||
-----------------------------------------------------
|
||||
|
||||
Currently, there are two implementations of KVM on Power, ``kvm_hv.ko`` and
|
||||
``kvm_pr.ko``.
|
||||
|
||||
|
||||
If a host supports both KVM modes, and both KVM kernel modules are loaded, it is
|
||||
possible to switch between the two modes with the ``kvm-type`` parameter:
|
||||
|
||||
* Use ``qemu-system-ppc64 -M pseries,accel=kvm,kvm-type=PR`` to use the
|
||||
``kvm_pr.ko`` kernel module.
|
||||
* Use ``qemu-system-ppc64 -M pseries,accel=kvm,kvm-type=HV`` to use ``kvm_hv.ko``
|
||||
instead.
|
||||
|
||||
KVM-PR
|
||||
^^^^^^
|
||||
|
||||
KVM-PR uses the so-called **PR**\ oblem state of the PPC CPUs to run the guests,
|
||||
i.e. the virtual machine is run in user mode and all privileged instructions
|
||||
trap and have to be emulated by the host. That means you can run KVM-PR inside
|
||||
a pSeries guest (or a PowerVM LPAR for that matter), and that is where it has
|
||||
originated, as historically (prior to POWER7) it was not possible to run Linux
|
||||
on hypervisor mode on a Power processor (this function was restricted to
|
||||
PowerVM, the IBM proprietary hypervisor).
|
||||
|
||||
Because all privileged instructions are trapped, guests that use a lot of
|
||||
privileged instructions run quite slow with KVM-PR. On the other hand, because
|
||||
of that, this kernel module can run on pretty much every PPC hardware, and is
|
||||
able to emulate a lot of guests CPUs. This module can even be used to run other
|
||||
PowerPC guests like an emulated PowerMac.
|
||||
|
||||
As KVM-PR can be run inside a pSeries guest, it can also provide nested
|
||||
virtualization capabilities (i.e. running a guest from within a guest).
|
||||
|
||||
It is important to notice that, as KVM-HV provides a much better execution
|
||||
performance, maintenance work has been much more focused on it in the past
|
||||
years. Maintenance for KVM-PR has been minimal.
|
||||
|
||||
In order to run KVM-PR guests with POWER9 processors, someone will need to start
|
||||
QEMU with ``kernel_irqchip=off`` command line option.
|
||||
|
||||
KVM-HV
|
||||
^^^^^^
|
||||
|
||||
KVM-HV uses the hypervisor mode of more recent Power processors, that allow
|
||||
access to the bare metal hardware directly. Although POWER7 had this capability,
|
||||
it was only starting with POWER8 that this was officially supported by IBM.
|
||||
|
||||
Originally, KVM-HV was only available when running on a PowerNV platform (a.k.a.
|
||||
Power bare metal). Although it runs on a PowerNV platform, it can only be used
|
||||
to start pSeries guests. As the pSeries guest doesn't have access to the
|
||||
hypervisor mode of the Power CPU, it wasn't possible to run KVM-HV on a guest.
|
||||
This limitation has been lifted, and now it is possible to run KVM-HV inside
|
||||
pSeries guests as well, making nested virtualization possible with KVM-HV.
|
||||
|
||||
As KVM-HV has access to privileged instructions, guests that use a lot of these
|
||||
can run much faster than with KVM-PR. On the other hand, the guest CPU has to be
|
||||
of the same type as the host CPU this way, e.g. it is not possible to specify an
|
||||
embedded PPC CPU for the guest with KVM-HV. However, there is at least the
|
||||
possibility to run the guest in a backward-compatibility mode of the previous
|
||||
CPUs generations, e.g. you can run a POWER7 guest on a POWER8 host by using
|
||||
``-cpu POWER8,compat=power7`` as parameter to QEMU.
|
||||
|
||||
Modules support
|
||||
---------------
|
||||
|
||||
As noticed in the sections above, each module can run in a different
|
||||
environment. The following table shows with which environment each module can
|
||||
run. As long as you are in a supported environment, you can run KVM-PR or KVM-HV
|
||||
nested. Combinations not shown in the table are not available.
|
||||
|
||||
+--------------+------------+------+-------------------+----------+--------+
|
||||
| Platform | Host type | Bits | Page table format | KVM-HV | KVM-PR |
|
||||
+==============+============+======+===================+==========+========+
|
||||
| PowerNV | bare metal | 32 | hash | no | yes |
|
||||
| | | +-------------------+----------+--------+
|
||||
| | | | radix | N/A | N/A |
|
||||
| | +------+-------------------+----------+--------+
|
||||
| | | 64 | hash | yes | yes |
|
||||
| | | +-------------------+----------+--------+
|
||||
| | | | radix | yes | no |
|
||||
+--------------+------------+------+-------------------+----------+--------+
|
||||
| pSeries [1]_ | PowerNV | 32 | hash | no | yes |
|
||||
| | | +-------------------+----------+--------+
|
||||
| | | | radix | N/A | N/A |
|
||||
| | +------+-------------------+----------+--------+
|
||||
| | | 64 | hash | no | yes |
|
||||
| | | +-------------------+----------+--------+
|
||||
| | | | radix | yes [2]_ | no |
|
||||
| +------------+------+-------------------+----------+--------+
|
||||
| | PowerVM | 32 | hash | no | yes |
|
||||
| | | +-------------------+----------+--------+
|
||||
| | | | radix | N/A | N/A |
|
||||
| | +------+-------------------+----------+--------+
|
||||
| | | 64 | hash | no | yes |
|
||||
| | | +-------------------+----------+--------+
|
||||
| | | | radix [3]_ | no | yes |
|
||||
+--------------+------------+------+-------------------+----------+--------+
|
||||
|
||||
.. [1] On POWER9 DD2.1 processors, the page table format on the host and guest
|
||||
must be the same.
|
||||
|
||||
.. [2] KVM-HV cannot run nested on POWER8 machines.
|
||||
|
||||
.. [3] Introduced on Power10 machines.
|
||||
|
||||
Maintainer contact information
|
||||
------------------------------
|
||||
|
||||
Cédric Le Goater <clg@kaod.org>
|
||||
|
||||
Daniel Henrique Barboza <danielhb413@gmail.com>
|
||||
|
10
dump/dump.c
10
dump/dump.c
@ -1293,14 +1293,6 @@ static size_t get_len_buf_out(size_t page_size, uint32_t flag_compress)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* check if the page is all 0
|
||||
*/
|
||||
static inline bool is_zero_page(const uint8_t *buf, size_t page_size)
|
||||
{
|
||||
return buffer_is_zero(buf, page_size);
|
||||
}
|
||||
|
||||
static void write_dump_pages(DumpState *s, Error **errp)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -1357,7 +1349,7 @@ static void write_dump_pages(DumpState *s, Error **errp)
|
||||
*/
|
||||
while (get_next_page(&block_iter, &pfn_iter, &buf, s)) {
|
||||
/* check zero page */
|
||||
if (is_zero_page(buf, s->dump_info.page_size)) {
|
||||
if (buffer_is_zero(buf, s->dump_info.page_size)) {
|
||||
ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor),
|
||||
false);
|
||||
if (ret < 0) {
|
||||
|
@ -19,7 +19,7 @@ static void partsN(return_nan)(FloatPartsN *a, float_status *s)
|
||||
{
|
||||
switch (a->cls) {
|
||||
case float_class_snan:
|
||||
float_raise(float_flag_invalid, s);
|
||||
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
|
||||
if (s->default_nan_mode) {
|
||||
parts_default_nan(a, s);
|
||||
} else {
|
||||
@ -40,7 +40,7 @@ static FloatPartsN *partsN(pick_nan)(FloatPartsN *a, FloatPartsN *b,
|
||||
float_status *s)
|
||||
{
|
||||
if (is_snan(a->cls) || is_snan(b->cls)) {
|
||||
float_raise(float_flag_invalid, s);
|
||||
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
|
||||
}
|
||||
|
||||
if (s->default_nan_mode) {
|
||||
@ -68,7 +68,7 @@ static FloatPartsN *partsN(pick_nan_muladd)(FloatPartsN *a, FloatPartsN *b,
|
||||
int which;
|
||||
|
||||
if (unlikely(abc_mask & float_cmask_snan)) {
|
||||
float_raise(float_flag_invalid, s);
|
||||
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
|
||||
}
|
||||
|
||||
which = pickNaNMulAdd(a->cls, b->cls, c->cls,
|
||||
@ -354,7 +354,7 @@ static FloatPartsN *partsN(addsub)(FloatPartsN *a, FloatPartsN *b,
|
||||
return a;
|
||||
}
|
||||
/* Inf - Inf */
|
||||
float_raise(float_flag_invalid, s);
|
||||
float_raise(float_flag_invalid | float_flag_invalid_isi, s);
|
||||
parts_default_nan(a, s);
|
||||
return a;
|
||||
}
|
||||
@ -423,7 +423,7 @@ static FloatPartsN *partsN(mul)(FloatPartsN *a, FloatPartsN *b,
|
||||
|
||||
/* Inf * Zero == NaN */
|
||||
if (unlikely(ab_mask == float_cmask_infzero)) {
|
||||
float_raise(float_flag_invalid, s);
|
||||
float_raise(float_flag_invalid | float_flag_invalid_imz, s);
|
||||
parts_default_nan(a, s);
|
||||
return a;
|
||||
}
|
||||
@ -489,11 +489,13 @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b,
|
||||
|
||||
if (unlikely(ab_mask != float_cmask_normal)) {
|
||||
if (unlikely(ab_mask == float_cmask_infzero)) {
|
||||
float_raise(float_flag_invalid | float_flag_invalid_imz, s);
|
||||
goto d_nan;
|
||||
}
|
||||
|
||||
if (ab_mask & float_cmask_inf) {
|
||||
if (c->cls == float_class_inf && a->sign != c->sign) {
|
||||
float_raise(float_flag_invalid | float_flag_invalid_isi, s);
|
||||
goto d_nan;
|
||||
}
|
||||
goto return_inf;
|
||||
@ -566,7 +568,6 @@ static FloatPartsN *partsN(muladd)(FloatPartsN *a, FloatPartsN *b,
|
||||
goto finish_sign;
|
||||
|
||||
d_nan:
|
||||
float_raise(float_flag_invalid, s);
|
||||
parts_default_nan(a, s);
|
||||
return a;
|
||||
}
|
||||
@ -589,11 +590,13 @@ static FloatPartsN *partsN(div)(FloatPartsN *a, FloatPartsN *b,
|
||||
}
|
||||
|
||||
/* 0/0 or Inf/Inf => NaN */
|
||||
if (unlikely(ab_mask == float_cmask_zero) ||
|
||||
unlikely(ab_mask == float_cmask_inf)) {
|
||||
float_raise(float_flag_invalid, s);
|
||||
parts_default_nan(a, s);
|
||||
return a;
|
||||
if (unlikely(ab_mask == float_cmask_zero)) {
|
||||
float_raise(float_flag_invalid | float_flag_invalid_zdz, s);
|
||||
goto d_nan;
|
||||
}
|
||||
if (unlikely(ab_mask == float_cmask_inf)) {
|
||||
float_raise(float_flag_invalid | float_flag_invalid_idi, s);
|
||||
goto d_nan;
|
||||
}
|
||||
|
||||
/* All the NaN cases */
|
||||
@ -624,6 +627,10 @@ static FloatPartsN *partsN(div)(FloatPartsN *a, FloatPartsN *b,
|
||||
float_raise(float_flag_divbyzero, s);
|
||||
a->cls = float_class_inf;
|
||||
return a;
|
||||
|
||||
d_nan:
|
||||
parts_default_nan(a, s);
|
||||
return a;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -862,7 +869,7 @@ static void partsN(sqrt)(FloatPartsN *a, float_status *status,
|
||||
return;
|
||||
|
||||
d_nan:
|
||||
float_raise(float_flag_invalid, status);
|
||||
float_raise(float_flag_invalid | float_flag_invalid_sqrt, status);
|
||||
parts_default_nan(a, status);
|
||||
}
|
||||
|
||||
@ -1042,13 +1049,15 @@ static int64_t partsN(float_to_sint)(FloatPartsN *p, FloatRoundMode rmode,
|
||||
|
||||
switch (p->cls) {
|
||||
case float_class_snan:
|
||||
flags |= float_flag_invalid_snan;
|
||||
/* fall through */
|
||||
case float_class_qnan:
|
||||
flags = float_flag_invalid;
|
||||
flags |= float_flag_invalid;
|
||||
r = max;
|
||||
break;
|
||||
|
||||
case float_class_inf:
|
||||
flags = float_flag_invalid;
|
||||
flags = float_flag_invalid | float_flag_invalid_cvti;
|
||||
r = p->sign ? min : max;
|
||||
break;
|
||||
|
||||
@ -1070,11 +1079,11 @@ static int64_t partsN(float_to_sint)(FloatPartsN *p, FloatRoundMode rmode,
|
||||
if (r <= -(uint64_t)min) {
|
||||
r = -r;
|
||||
} else {
|
||||
flags = float_flag_invalid;
|
||||
flags = float_flag_invalid | float_flag_invalid_cvti;
|
||||
r = min;
|
||||
}
|
||||
} else if (r > max) {
|
||||
flags = float_flag_invalid;
|
||||
flags = float_flag_invalid | float_flag_invalid_cvti;
|
||||
r = max;
|
||||
}
|
||||
break;
|
||||
@ -1107,13 +1116,15 @@ static uint64_t partsN(float_to_uint)(FloatPartsN *p, FloatRoundMode rmode,
|
||||
|
||||
switch (p->cls) {
|
||||
case float_class_snan:
|
||||
flags |= float_flag_invalid_snan;
|
||||
/* fall through */
|
||||
case float_class_qnan:
|
||||
flags = float_flag_invalid;
|
||||
flags |= float_flag_invalid;
|
||||
r = max;
|
||||
break;
|
||||
|
||||
case float_class_inf:
|
||||
flags = float_flag_invalid;
|
||||
flags = float_flag_invalid | float_flag_invalid_cvti;
|
||||
r = p->sign ? 0 : max;
|
||||
break;
|
||||
|
||||
@ -1131,15 +1142,15 @@ static uint64_t partsN(float_to_uint)(FloatPartsN *p, FloatRoundMode rmode,
|
||||
}
|
||||
|
||||
if (p->sign) {
|
||||
flags = float_flag_invalid;
|
||||
flags = float_flag_invalid | float_flag_invalid_cvti;
|
||||
r = 0;
|
||||
} else if (p->exp > DECOMPOSED_BINARY_POINT) {
|
||||
flags = float_flag_invalid;
|
||||
flags = float_flag_invalid | float_flag_invalid_cvti;
|
||||
r = max;
|
||||
} else {
|
||||
r = p->frac_hi >> (DECOMPOSED_BINARY_POINT - p->exp);
|
||||
if (r > max) {
|
||||
flags = float_flag_invalid;
|
||||
flags = float_flag_invalid | float_flag_invalid_cvti;
|
||||
r = max;
|
||||
}
|
||||
}
|
||||
@ -1334,7 +1345,9 @@ static FloatRelation partsN(compare)(FloatPartsN *a, FloatPartsN *b,
|
||||
}
|
||||
|
||||
if (unlikely(ab_mask & float_cmask_anynan)) {
|
||||
if (!is_quiet || (ab_mask & float_cmask_snan)) {
|
||||
if (ab_mask & float_cmask_snan) {
|
||||
float_raise(float_flag_invalid | float_flag_invalid_snan, s);
|
||||
} else if (!is_quiet) {
|
||||
float_raise(float_flag_invalid, s);
|
||||
}
|
||||
return float_relation_unordered;
|
||||
|
@ -506,7 +506,7 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
|
||||
* the default NaN
|
||||
*/
|
||||
if (infzero && is_qnan(c_cls)) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
float_raise(float_flag_invalid | float_flag_invalid_imz, status);
|
||||
return 3;
|
||||
}
|
||||
|
||||
@ -533,7 +533,7 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
|
||||
* case sets InvalidOp and returns the default NaN
|
||||
*/
|
||||
if (infzero) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
float_raise(float_flag_invalid | float_flag_invalid_imz, status);
|
||||
return 3;
|
||||
}
|
||||
/* Prefer sNaN over qNaN, in the a, b, c order. */
|
||||
@ -556,7 +556,7 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
|
||||
* case sets InvalidOp and returns the input value 'c'
|
||||
*/
|
||||
if (infzero) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
float_raise(float_flag_invalid | float_flag_invalid_imz, status);
|
||||
return 2;
|
||||
}
|
||||
/* Prefer sNaN over qNaN, in the c, a, b order. */
|
||||
@ -580,7 +580,7 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
|
||||
* a default NaN
|
||||
*/
|
||||
if (infzero) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
float_raise(float_flag_invalid | float_flag_invalid_imz, status);
|
||||
return 2;
|
||||
}
|
||||
|
||||
@ -597,7 +597,7 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
|
||||
#elif defined(TARGET_RISCV)
|
||||
/* For RISC-V, InvalidOp is set when multiplicands are Inf and zero */
|
||||
if (infzero) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
float_raise(float_flag_invalid | float_flag_invalid_imz, status);
|
||||
}
|
||||
return 3; /* default NaN */
|
||||
#elif defined(TARGET_XTENSA)
|
||||
@ -606,7 +606,7 @@ static int pickNaNMulAdd(FloatClass a_cls, FloatClass b_cls, FloatClass c_cls,
|
||||
* an input NaN if we have one (ie c).
|
||||
*/
|
||||
if (infzero) {
|
||||
float_raise(float_flag_invalid, status);
|
||||
float_raise(float_flag_invalid | float_flag_invalid_imz, status);
|
||||
return 2;
|
||||
}
|
||||
if (status->use_first_nan) {
|
||||
|
114
fpu/softfloat.c
114
fpu/softfloat.c
@ -1693,6 +1693,50 @@ static float64 float64_round_pack_canonical(FloatParts64 *p,
|
||||
return float64_pack_raw(p);
|
||||
}
|
||||
|
||||
static float64 float64r32_round_pack_canonical(FloatParts64 *p,
|
||||
float_status *s)
|
||||
{
|
||||
parts_uncanon(p, s, &float32_params);
|
||||
|
||||
/*
|
||||
* In parts_uncanon, we placed the fraction for float32 at the lsb.
|
||||
* We need to adjust the fraction higher so that the least N bits are
|
||||
* zero, and the fraction is adjacent to the float64 implicit bit.
|
||||
*/
|
||||
switch (p->cls) {
|
||||
case float_class_normal:
|
||||
if (unlikely(p->exp == 0)) {
|
||||
/*
|
||||
* The result is denormal for float32, but can be represented
|
||||
* in normalized form for float64. Adjust, per canonicalize.
|
||||
*/
|
||||
int shift = frac_normalize(p);
|
||||
p->exp = (float32_params.frac_shift -
|
||||
float32_params.exp_bias - shift + 1 +
|
||||
float64_params.exp_bias);
|
||||
frac_shr(p, float64_params.frac_shift);
|
||||
} else {
|
||||
frac_shl(p, float32_params.frac_shift - float64_params.frac_shift);
|
||||
p->exp += float64_params.exp_bias - float32_params.exp_bias;
|
||||
}
|
||||
break;
|
||||
case float_class_snan:
|
||||
case float_class_qnan:
|
||||
frac_shl(p, float32_params.frac_shift - float64_params.frac_shift);
|
||||
p->exp = float64_params.exp_max;
|
||||
break;
|
||||
case float_class_inf:
|
||||
p->exp = float64_params.exp_max;
|
||||
break;
|
||||
case float_class_zero:
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
return float64_pack_raw(p);
|
||||
}
|
||||
|
||||
static void float128_unpack_canonical(FloatParts128 *p, float128 f,
|
||||
float_status *s)
|
||||
{
|
||||
@ -1938,6 +1982,28 @@ float64_sub(float64 a, float64 b, float_status *s)
|
||||
return float64_addsub(a, b, s, hard_f64_sub, soft_f64_sub);
|
||||
}
|
||||
|
||||
static float64 float64r32_addsub(float64 a, float64 b, float_status *status,
|
||||
bool subtract)
|
||||
{
|
||||
FloatParts64 pa, pb, *pr;
|
||||
|
||||
float64_unpack_canonical(&pa, a, status);
|
||||
float64_unpack_canonical(&pb, b, status);
|
||||
pr = parts_addsub(&pa, &pb, status, subtract);
|
||||
|
||||
return float64r32_round_pack_canonical(pr, status);
|
||||
}
|
||||
|
||||
float64 float64r32_add(float64 a, float64 b, float_status *status)
|
||||
{
|
||||
return float64r32_addsub(a, b, status, false);
|
||||
}
|
||||
|
||||
float64 float64r32_sub(float64 a, float64 b, float_status *status)
|
||||
{
|
||||
return float64r32_addsub(a, b, status, true);
|
||||
}
|
||||
|
||||
static bfloat16 QEMU_FLATTEN
|
||||
bfloat16_addsub(bfloat16 a, bfloat16 b, float_status *status, bool subtract)
|
||||
{
|
||||
@ -2069,6 +2135,17 @@ float64_mul(float64 a, float64 b, float_status *s)
|
||||
f64_is_zon2, f64_addsubmul_post);
|
||||
}
|
||||
|
||||
float64 float64r32_mul(float64 a, float64 b, float_status *status)
|
||||
{
|
||||
FloatParts64 pa, pb, *pr;
|
||||
|
||||
float64_unpack_canonical(&pa, a, status);
|
||||
float64_unpack_canonical(&pb, b, status);
|
||||
pr = parts_mul(&pa, &pb, status);
|
||||
|
||||
return float64r32_round_pack_canonical(pr, status);
|
||||
}
|
||||
|
||||
bfloat16 QEMU_FLATTEN
|
||||
bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status)
|
||||
{
|
||||
@ -2296,6 +2373,19 @@ float64_muladd(float64 xa, float64 xb, float64 xc, int flags, float_status *s)
|
||||
return soft_f64_muladd(ua.s, ub.s, uc.s, flags, s);
|
||||
}
|
||||
|
||||
float64 float64r32_muladd(float64 a, float64 b, float64 c,
|
||||
int flags, float_status *status)
|
||||
{
|
||||
FloatParts64 pa, pb, pc, *pr;
|
||||
|
||||
float64_unpack_canonical(&pa, a, status);
|
||||
float64_unpack_canonical(&pb, b, status);
|
||||
float64_unpack_canonical(&pc, c, status);
|
||||
pr = parts_muladd(&pa, &pb, &pc, flags, status);
|
||||
|
||||
return float64r32_round_pack_canonical(pr, status);
|
||||
}
|
||||
|
||||
bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c,
|
||||
int flags, float_status *status)
|
||||
{
|
||||
@ -2419,6 +2509,17 @@ float64_div(float64 a, float64 b, float_status *s)
|
||||
f64_div_pre, f64_div_post);
|
||||
}
|
||||
|
||||
float64 float64r32_div(float64 a, float64 b, float_status *status)
|
||||
{
|
||||
FloatParts64 pa, pb, *pr;
|
||||
|
||||
float64_unpack_canonical(&pa, a, status);
|
||||
float64_unpack_canonical(&pb, b, status);
|
||||
pr = parts_div(&pa, &pb, status);
|
||||
|
||||
return float64r32_round_pack_canonical(pr, status);
|
||||
}
|
||||
|
||||
bfloat16 QEMU_FLATTEN
|
||||
bfloat16_div(bfloat16 a, bfloat16 b, float_status *status)
|
||||
{
|
||||
@ -2543,8 +2644,10 @@ floatx80 floatx80_mod(floatx80 a, floatx80 b, float_status *status)
|
||||
static void parts_float_to_ahp(FloatParts64 *a, float_status *s)
|
||||
{
|
||||
switch (a->cls) {
|
||||
case float_class_qnan:
|
||||
case float_class_snan:
|
||||
float_raise(float_flag_invalid_snan, s);
|
||||
/* fall through */
|
||||
case float_class_qnan:
|
||||
/*
|
||||
* There is no NaN in the destination format. Raise Invalid
|
||||
* and return a zero with the sign of the input NaN.
|
||||
@ -4283,6 +4386,15 @@ float64 QEMU_FLATTEN float64_sqrt(float64 xa, float_status *s)
|
||||
return soft_f64_sqrt(ua.s, s);
|
||||
}
|
||||
|
||||
float64 float64r32_sqrt(float64 a, float_status *status)
|
||||
{
|
||||
FloatParts64 p;
|
||||
|
||||
float64_unpack_canonical(&p, a, status);
|
||||
parts_sqrt(&p, status, &float64_params);
|
||||
return float64r32_round_pack_canonical(&p, status);
|
||||
}
|
||||
|
||||
bfloat16 QEMU_FLATTEN bfloat16_sqrt(bfloat16 a, float_status *status)
|
||||
{
|
||||
FloatParts64 p;
|
||||
|
83
gdbstub.c
83
gdbstub.c
@ -368,27 +368,10 @@ typedef struct GDBState {
|
||||
gdb_syscall_complete_cb current_syscall_cb;
|
||||
GString *str_buf;
|
||||
GByteArray *mem_buf;
|
||||
int sstep_flags;
|
||||
int supported_sstep_flags;
|
||||
} GDBState;
|
||||
|
||||
/* By default use no IRQs and no timers while single stepping so as to
|
||||
* make single stepping like an ICE HW step.
|
||||
*/
|
||||
static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER;
|
||||
|
||||
/* Retrieves flags for single step mode. */
|
||||
static int get_sstep_flags(void)
|
||||
{
|
||||
/*
|
||||
* In replay mode all events written into the log should be replayed.
|
||||
* That is why NOIRQ flag is removed in this mode.
|
||||
*/
|
||||
if (replay_mode != REPLAY_MODE_NONE) {
|
||||
return SSTEP_ENABLE;
|
||||
} else {
|
||||
return sstep_flags;
|
||||
}
|
||||
}
|
||||
|
||||
static GDBState gdbserver_state;
|
||||
|
||||
static void init_gdbserver_state(void)
|
||||
@ -399,6 +382,29 @@ static void init_gdbserver_state(void)
|
||||
gdbserver_state.str_buf = g_string_new(NULL);
|
||||
gdbserver_state.mem_buf = g_byte_array_sized_new(MAX_PACKET_LENGTH);
|
||||
gdbserver_state.last_packet = g_byte_array_sized_new(MAX_PACKET_LENGTH + 4);
|
||||
|
||||
/*
|
||||
* In replay mode all events will come from the log and can't be
|
||||
* suppressed otherwise we would break determinism. However as those
|
||||
* events are tied to the number of executed instructions we won't see
|
||||
* them occurring every time we single step.
|
||||
*/
|
||||
if (replay_mode != REPLAY_MODE_NONE) {
|
||||
gdbserver_state.supported_sstep_flags = SSTEP_ENABLE;
|
||||
} else if (kvm_enabled()) {
|
||||
gdbserver_state.supported_sstep_flags = kvm_get_supported_sstep_flags();
|
||||
} else {
|
||||
gdbserver_state.supported_sstep_flags =
|
||||
SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER;
|
||||
}
|
||||
|
||||
/*
|
||||
* By default use no IRQs and no timers while single stepping so as to
|
||||
* make single stepping like an ICE HW step.
|
||||
*/
|
||||
gdbserver_state.sstep_flags = SSTEP_ENABLE | SSTEP_NOIRQ | SSTEP_NOTIMER;
|
||||
gdbserver_state.sstep_flags &= gdbserver_state.supported_sstep_flags;
|
||||
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
@ -505,7 +511,7 @@ static int gdb_continue_partial(char *newstates)
|
||||
CPU_FOREACH(cpu) {
|
||||
if (newstates[cpu->cpu_index] == 's') {
|
||||
trace_gdbstub_op_stepping(cpu->cpu_index);
|
||||
cpu_single_step(cpu, sstep_flags);
|
||||
cpu_single_step(cpu, gdbserver_state.sstep_flags);
|
||||
}
|
||||
}
|
||||
gdbserver_state.running_state = 1;
|
||||
@ -524,7 +530,7 @@ static int gdb_continue_partial(char *newstates)
|
||||
break; /* nothing to do here */
|
||||
case 's':
|
||||
trace_gdbstub_op_stepping(cpu->cpu_index);
|
||||
cpu_single_step(cpu, get_sstep_flags());
|
||||
cpu_single_step(cpu, gdbserver_state.sstep_flags);
|
||||
cpu_resume(cpu);
|
||||
flag = 1;
|
||||
break;
|
||||
@ -1883,7 +1889,7 @@ static void handle_step(GArray *params, void *user_ctx)
|
||||
gdb_set_cpu_pc((target_ulong)get_param(params, 0)->val_ull);
|
||||
}
|
||||
|
||||
cpu_single_step(gdbserver_state.c_cpu, get_sstep_flags());
|
||||
cpu_single_step(gdbserver_state.c_cpu, gdbserver_state.sstep_flags);
|
||||
gdb_continue();
|
||||
}
|
||||
|
||||
@ -2017,24 +2023,44 @@ static void handle_v_commands(GArray *params, void *user_ctx)
|
||||
|
||||
static void handle_query_qemu_sstepbits(GArray *params, void *user_ctx)
|
||||
{
|
||||
g_string_printf(gdbserver_state.str_buf, "ENABLE=%x,NOIRQ=%x,NOTIMER=%x",
|
||||
SSTEP_ENABLE, SSTEP_NOIRQ, SSTEP_NOTIMER);
|
||||
g_string_printf(gdbserver_state.str_buf, "ENABLE=%x", SSTEP_ENABLE);
|
||||
|
||||
if (gdbserver_state.supported_sstep_flags & SSTEP_NOIRQ) {
|
||||
g_string_append_printf(gdbserver_state.str_buf, ",NOIRQ=%x",
|
||||
SSTEP_NOIRQ);
|
||||
}
|
||||
|
||||
if (gdbserver_state.supported_sstep_flags & SSTEP_NOTIMER) {
|
||||
g_string_append_printf(gdbserver_state.str_buf, ",NOTIMER=%x",
|
||||
SSTEP_NOTIMER);
|
||||
}
|
||||
|
||||
put_strbuf();
|
||||
}
|
||||
|
||||
static void handle_set_qemu_sstep(GArray *params, void *user_ctx)
|
||||
{
|
||||
int new_sstep_flags;
|
||||
|
||||
if (!params->len) {
|
||||
return;
|
||||
}
|
||||
|
||||
sstep_flags = get_param(params, 0)->val_ul;
|
||||
new_sstep_flags = get_param(params, 0)->val_ul;
|
||||
|
||||
if (new_sstep_flags & ~gdbserver_state.supported_sstep_flags) {
|
||||
put_packet("E22");
|
||||
return;
|
||||
}
|
||||
|
||||
gdbserver_state.sstep_flags = new_sstep_flags;
|
||||
put_packet("OK");
|
||||
}
|
||||
|
||||
static void handle_query_qemu_sstep(GArray *params, void *user_ctx)
|
||||
{
|
||||
g_string_printf(gdbserver_state.str_buf, "0x%x", sstep_flags);
|
||||
g_string_printf(gdbserver_state.str_buf, "0x%x",
|
||||
gdbserver_state.sstep_flags);
|
||||
put_strbuf();
|
||||
}
|
||||
|
||||
@ -3497,6 +3523,11 @@ int gdbserver_start(const char *device)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (kvm_enabled() && !kvm_supports_guest_debug()) {
|
||||
error_report("gdbstub: KVM doesn't support guest debugging");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!device)
|
||||
return -1;
|
||||
if (strcmp(device, "none") != 0) {
|
||||
|
@ -27,6 +27,7 @@ config ARM_VIRT
|
||||
select DIMM
|
||||
select ACPI_HW_REDUCED
|
||||
select ACPI_APEI
|
||||
select ACPI_VIOT
|
||||
|
||||
config CHEETAH
|
||||
bool
|
||||
|
@ -284,12 +284,13 @@ static void write_boot_rom(DriveInfo *dinfo, hwaddr addr, size_t rom_size,
|
||||
}
|
||||
|
||||
static void aspeed_board_init_flashes(AspeedSMCState *s,
|
||||
const char *flashtype)
|
||||
const char *flashtype,
|
||||
int unit0)
|
||||
{
|
||||
int i ;
|
||||
|
||||
for (i = 0; i < s->num_cs; ++i) {
|
||||
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||
DriveInfo *dinfo = drive_get(IF_MTD, 0, unit0 + i);
|
||||
qemu_irq cs_line;
|
||||
DeviceState *dev;
|
||||
|
||||
@ -382,10 +383,12 @@ static void aspeed_machine_init(MachineState *machine)
|
||||
"max_ram", max_ram_size - machine->ram_size);
|
||||
memory_region_add_subregion(&bmc->ram_container, machine->ram_size, &bmc->max_ram);
|
||||
|
||||
aspeed_board_init_flashes(&bmc->soc.fmc, bmc->fmc_model ?
|
||||
bmc->fmc_model : amc->fmc_model);
|
||||
aspeed_board_init_flashes(&bmc->soc.spi[0], bmc->spi_model ?
|
||||
bmc->spi_model : amc->spi_model);
|
||||
aspeed_board_init_flashes(&bmc->soc.fmc,
|
||||
bmc->fmc_model ? bmc->fmc_model : amc->fmc_model,
|
||||
0);
|
||||
aspeed_board_init_flashes(&bmc->soc.spi[0],
|
||||
bmc->spi_model ? bmc->spi_model : amc->spi_model,
|
||||
bmc->soc.fmc.num_cs);
|
||||
|
||||
/* Install first FMC flash content as a boot rom. */
|
||||
if (drive0) {
|
||||
@ -435,11 +438,13 @@ static void aspeed_machine_init(MachineState *machine)
|
||||
}
|
||||
|
||||
for (i = 0; i < bmc->soc.sdhci.num_slots; i++) {
|
||||
sdhci_attach_drive(&bmc->soc.sdhci.slots[i], drive_get_next(IF_SD));
|
||||
sdhci_attach_drive(&bmc->soc.sdhci.slots[i],
|
||||
drive_get(IF_SD, 0, i));
|
||||
}
|
||||
|
||||
if (bmc->soc.emmc.num_slots) {
|
||||
sdhci_attach_drive(&bmc->soc.emmc.slots[0], drive_get_next(IF_SD));
|
||||
sdhci_attach_drive(&bmc->soc.emmc.slots[0],
|
||||
drive_get(IF_SD, 0, bmc->soc.sdhci.num_slots));
|
||||
}
|
||||
|
||||
arm_load_kernel(ARM_CPU(first_cpu), machine, &aspeed_board_binfo);
|
||||
|
@ -8,7 +8,6 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
|
@ -81,7 +81,7 @@ static void cubieboard_init(MachineState *machine)
|
||||
}
|
||||
|
||||
/* Retrieve SD bus */
|
||||
di = drive_get_next(IF_SD);
|
||||
di = drive_get(IF_SD, 0, 0);
|
||||
blk = di ? blk_by_legacy_dinfo(di) : NULL;
|
||||
bus = qdev_get_child_bus(DEVICE(a10), "sd-bus");
|
||||
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
@ -18,7 +18,6 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/sysbus.h"
|
||||
|
@ -123,7 +123,7 @@ static void imx25_pdk_init(MachineState *machine)
|
||||
DriveInfo *di;
|
||||
BlockBackend *blk;
|
||||
|
||||
di = drive_get_next(IF_SD);
|
||||
di = drive_get(IF_SD, 0, i);
|
||||
blk = di ? blk_by_legacy_dinfo(di) : NULL;
|
||||
bus = qdev_get_child_bus(DEVICE(&s->soc.esdhc[i]), "sd-bus");
|
||||
carddev = qdev_new(TYPE_SD_CARD);
|
||||
|
@ -649,7 +649,7 @@ static void integratorcp_init(MachineState *machine)
|
||||
qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_WPROT, 0));
|
||||
qdev_connect_gpio_out_named(dev, "card-inserted", 0,
|
||||
qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_CARDIN, 0));
|
||||
dinfo = drive_get_next(IF_SD);
|
||||
dinfo = drive_get(IF_SD, 0, 0);
|
||||
if (dinfo) {
|
||||
DeviceState *card;
|
||||
|
||||
|
@ -52,7 +52,7 @@ static void mcimx6ul_evk_init(MachineState *machine)
|
||||
DriveInfo *di;
|
||||
BlockBackend *blk;
|
||||
|
||||
di = drive_get_next(IF_SD);
|
||||
di = drive_get(IF_SD, 0, i);
|
||||
blk = di ? blk_by_legacy_dinfo(di) : NULL;
|
||||
bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus");
|
||||
carddev = qdev_new(TYPE_SD_CARD);
|
||||
|
@ -52,7 +52,7 @@ static void mcimx7d_sabre_init(MachineState *machine)
|
||||
DriveInfo *di;
|
||||
BlockBackend *blk;
|
||||
|
||||
di = drive_get_next(IF_SD);
|
||||
di = drive_get(IF_SD, 0, i);
|
||||
blk = di ? blk_by_legacy_dinfo(di) : NULL;
|
||||
bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus");
|
||||
carddev = qdev_new(TYPE_SD_CARD);
|
||||
|
@ -45,7 +45,7 @@ static void emcraft_sf2_s2s010_init(MachineState *machine)
|
||||
DeviceState *spi_flash;
|
||||
MSF2State *soc;
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||
DriveInfo *dinfo = drive_get(IF_MTD, 0, 0);
|
||||
qemu_irq cs_line;
|
||||
BusState *spi_bus;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "hw/qdev-core.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "qemu/units.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
@ -84,9 +83,9 @@ static void npcm7xx_connect_dram(NPCM7xxState *soc, MemoryRegion *dram)
|
||||
&error_abort);
|
||||
}
|
||||
|
||||
static void sdhci_attach_drive(SDHCIState *sdhci)
|
||||
static void sdhci_attach_drive(SDHCIState *sdhci, int unit)
|
||||
{
|
||||
DriveInfo *di = drive_get_next(IF_SD);
|
||||
DriveInfo *di = drive_get(IF_SD, 0, unit);
|
||||
BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL;
|
||||
|
||||
BusState *bus = qdev_get_child_bus(DEVICE(sdhci), "sd-bus");
|
||||
@ -374,7 +373,7 @@ static void quanta_gbs_init(MachineState *machine)
|
||||
drive_get(IF_MTD, 0, 0));
|
||||
|
||||
quanta_gbs_i2c_init(soc);
|
||||
sdhci_attach_drive(&soc->mmc.sdhci);
|
||||
sdhci_attach_drive(&soc->mmc.sdhci, 0);
|
||||
npcm7xx_load_kernel(machine, soc);
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ static void orangepi_init(MachineState *machine)
|
||||
qdev_realize(DEVICE(h3), NULL, &error_abort);
|
||||
|
||||
/* Retrieve SD bus */
|
||||
di = drive_get_next(IF_SD);
|
||||
di = drive_get(IF_SD, 0, 0);
|
||||
blk = di ? blk_by_legacy_dinfo(di) : NULL;
|
||||
bus = qdev_get_child_bus(DEVICE(h3), "sd-bus");
|
||||
|
||||
|
@ -284,7 +284,7 @@ static void raspi_machine_init(MachineState *machine)
|
||||
qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
|
||||
|
||||
/* Create and plug in the SD cards */
|
||||
di = drive_get_next(IF_SD);
|
||||
di = drive_get(IF_SD, 0, 0);
|
||||
blk = di ? blk_by_legacy_dinfo(di) : NULL;
|
||||
bus = qdev_get_child_bus(DEVICE(&s->soc), "sd-bus");
|
||||
if (bus == NULL) {
|
||||
|
@ -237,7 +237,7 @@ static void realview_init(MachineState *machine,
|
||||
qemu_irq_invert(qdev_get_gpio_in(gpio2, 0)));
|
||||
qdev_connect_gpio_out_named(dev, "card-read-only", 0, mmc_irq[0]);
|
||||
qdev_connect_gpio_out_named(dev, "card-inserted", 0, mmc_irq[1]);
|
||||
dinfo = drive_get_next(IF_SD);
|
||||
dinfo = drive_get(IF_SD, 0, 0);
|
||||
if (dinfo) {
|
||||
DeviceState *card;
|
||||
|
||||
|
@ -76,7 +76,7 @@ static void sabrelite_init(MachineState *machine)
|
||||
if (spi_bus) {
|
||||
DeviceState *flash_dev;
|
||||
qemu_irq cs_line;
|
||||
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||
DriveInfo *dinfo = drive_get(IF_MTD, 0, 0);
|
||||
|
||||
flash_dev = qdev_new("sst25vf016b");
|
||||
if (dinfo) {
|
||||
|
@ -18,7 +18,6 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/sd/sd.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "hw/arm/boot.h"
|
||||
#include "qemu/timer.h"
|
||||
@ -1157,6 +1158,9 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
|
||||
void *bus;
|
||||
DeviceState *sddev;
|
||||
DeviceState *ssddev;
|
||||
DriveInfo *dinfo;
|
||||
DeviceState *carddev;
|
||||
BlockBackend *blk;
|
||||
|
||||
/*
|
||||
* Some boards have both an OLED controller and SD card connected to
|
||||
@ -1221,8 +1225,17 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
|
||||
* - Make the ssd0323 OLED controller chipselect active-low
|
||||
*/
|
||||
bus = qdev_get_child_bus(dev, "ssi");
|
||||
|
||||
sddev = ssi_create_peripheral(bus, "ssi-sd");
|
||||
|
||||
dinfo = drive_get(IF_SD, 0, 0);
|
||||
blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
|
||||
carddev = qdev_new(TYPE_SD_CARD);
|
||||
qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
|
||||
qdev_prop_set_bit(carddev, "spi", true);
|
||||
qdev_realize_and_unref(carddev,
|
||||
qdev_get_child_bus(sddev, "sd-bus"),
|
||||
&error_fatal);
|
||||
|
||||
ssddev = ssi_create_peripheral(bus, "ssd0323");
|
||||
gpio_out[GPIO_D][0] = qemu_irq_split(
|
||||
qdev_get_gpio_in_named(sddev, SSI_GPIO_CS, 0),
|
||||
|
@ -24,7 +24,6 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/arm/stm32f405_soc.h"
|
||||
|
@ -310,7 +310,7 @@ static void versatile_init(MachineState *machine, int board_id)
|
||||
qdev_connect_gpio_out(sysctl, 0, qdev_get_gpio_in(dev, 0));
|
||||
|
||||
dev = sysbus_create_varargs("pl181", 0x10005000, sic[22], sic[1], NULL);
|
||||
dinfo = drive_get_next(IF_SD);
|
||||
dinfo = drive_get(IF_SD, 0, 0);
|
||||
if (dinfo) {
|
||||
DeviceState *card;
|
||||
|
||||
@ -322,7 +322,7 @@ static void versatile_init(MachineState *machine, int board_id)
|
||||
}
|
||||
|
||||
dev = sysbus_create_varargs("pl181", 0x1000b000, sic[23], sic[2], NULL);
|
||||
dinfo = drive_get_next(IF_SD);
|
||||
dinfo = drive_get(IF_SD, 0, 1);
|
||||
if (dinfo) {
|
||||
DeviceState *card;
|
||||
|
||||
|
@ -23,7 +23,6 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/sysbus.h"
|
||||
@ -625,7 +624,7 @@ static void vexpress_common_init(MachineState *machine)
|
||||
qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_WPROT));
|
||||
qdev_connect_gpio_out_named(dev, "card-inserted", 0,
|
||||
qdev_get_gpio_in(sysctl, ARM_SYSCTL_GPIO_MMC_CARDIN));
|
||||
dinfo = drive_get_next(IF_SD);
|
||||
dinfo = drive_get(IF_SD, 0, 0);
|
||||
if (dinfo) {
|
||||
DeviceState *card;
|
||||
|
||||
@ -657,7 +656,7 @@ static void vexpress_common_init(MachineState *machine)
|
||||
|
||||
sysbus_create_simple("pl111", map[VE_CLCD], pic[14]);
|
||||
|
||||
dinfo = drive_get_next(IF_PFLASH);
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
pflash0 = ve_pflash_cfi01_register(map[VE_NORFLASH0], "vexpress.flash0",
|
||||
dinfo);
|
||||
if (!pflash0) {
|
||||
@ -673,7 +672,7 @@ static void vexpress_common_init(MachineState *machine)
|
||||
memory_region_add_subregion(sysmem, map[VE_NORFLASHALIAS], flashalias);
|
||||
}
|
||||
|
||||
dinfo = drive_get_next(IF_PFLASH);
|
||||
dinfo = drive_get(IF_PFLASH, 0, 1);
|
||||
if (!ve_pflash_cfi01_register(map[VE_NORFLASH1], "vexpress.flash1",
|
||||
dinfo)) {
|
||||
error_report("vexpress: error registering flash 1");
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "kvm_arm.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/acpi/ghes.h"
|
||||
#include "hw/acpi/viot.h"
|
||||
|
||||
#define ARM_SPI_BASE 32
|
||||
|
||||
@ -1011,6 +1012,12 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vms->iommu == VIRT_IOMMU_VIRTIO) {
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_viot(ms, tables_blob, tables->linker, vms->virtio_iommu_bdf,
|
||||
vms->oem_id, vms->oem_table_id);
|
||||
}
|
||||
|
||||
/* XSDT is pointed to by RSDP */
|
||||
xsdt = tables_blob->len;
|
||||
build_xsdt(tables_blob, tables->linker, table_offsets, vms->oem_id,
|
||||
|
@ -29,7 +29,6 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/option.h"
|
||||
@ -2494,6 +2493,11 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
|
||||
hwaddr db_start = 0, db_end = 0;
|
||||
char *resv_prop_str;
|
||||
|
||||
if (vms->iommu != VIRT_IOMMU_NONE) {
|
||||
error_setg(errp, "virt machine does not support multiple IOMMUs");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (vms->msi_controller) {
|
||||
case VIRT_MSI_CTRL_NONE:
|
||||
return;
|
||||
@ -2513,8 +2517,9 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
|
||||
db_start, db_end,
|
||||
VIRTIO_IOMMU_RESV_MEM_T_MSI);
|
||||
|
||||
qdev_prop_set_uint32(dev, "len-reserved-regions", 1);
|
||||
qdev_prop_set_string(dev, "reserved-regions[0]", resv_prop_str);
|
||||
object_property_set_uint(OBJECT(dev), "len-reserved-regions", 1, errp);
|
||||
object_property_set_str(OBJECT(dev), "reserved-regions[0]",
|
||||
resv_prop_str, errp);
|
||||
g_free(resv_prop_str);
|
||||
}
|
||||
}
|
||||
@ -2614,16 +2619,10 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
|
||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||
|
||||
if (device_is_dynamic_sysbus(mc, dev) ||
|
||||
(object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM))) {
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) {
|
||||
return HOTPLUG_HANDLER(machine);
|
||||
}
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI)) {
|
||||
VirtMachineState *vms = VIRT_MACHINE(machine);
|
||||
|
||||
if (!vms->bootinfo.firmware_loaded || !virt_is_acpi_enabled(vms)) {
|
||||
return HOTPLUG_HANDLER(machine);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -125,9 +125,10 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
|
||||
sysbus_connect_irq(s, 0, irq);
|
||||
}
|
||||
|
||||
static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
|
||||
bool is_qspi)
|
||||
static inline int zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
|
||||
bool is_qspi, int unit0)
|
||||
{
|
||||
int unit = unit0;
|
||||
DeviceState *dev;
|
||||
SysBusDevice *busdev;
|
||||
SSIBus *spi;
|
||||
@ -156,7 +157,7 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
|
||||
spi = (SSIBus *)qdev_get_child_bus(dev, bus_name);
|
||||
|
||||
for (j = 0; j < num_ss; ++j) {
|
||||
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||
DriveInfo *dinfo = drive_get(IF_MTD, 0, unit++);
|
||||
flash_dev = qdev_new("n25q128");
|
||||
if (dinfo) {
|
||||
qdev_prop_set_drive_err(flash_dev, "drive",
|
||||
@ -170,6 +171,7 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
|
||||
}
|
||||
}
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
static void zynq_init(MachineState *machine)
|
||||
@ -247,9 +249,9 @@ static void zynq_init(MachineState *machine)
|
||||
pic[n] = qdev_get_gpio_in(dev, n);
|
||||
}
|
||||
|
||||
zynq_init_spi_flashes(0xE0006000, pic[58-IRQ_OFFSET], false);
|
||||
zynq_init_spi_flashes(0xE0007000, pic[81-IRQ_OFFSET], false);
|
||||
zynq_init_spi_flashes(0xE000D000, pic[51-IRQ_OFFSET], true);
|
||||
n = zynq_init_spi_flashes(0xE0006000, pic[58 - IRQ_OFFSET], false, 0);
|
||||
n = zynq_init_spi_flashes(0xE0007000, pic[81 - IRQ_OFFSET], false, n);
|
||||
n = zynq_init_spi_flashes(0xE000D000, pic[51 - IRQ_OFFSET], true, n);
|
||||
|
||||
sysbus_create_simple(TYPE_CHIPIDEA, 0xE0002000, pic[53 - IRQ_OFFSET]);
|
||||
sysbus_create_simple(TYPE_CHIPIDEA, 0xE0003000, pic[76 - IRQ_OFFSET]);
|
||||
@ -298,7 +300,7 @@ static void zynq_init(MachineState *machine)
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, hci_addr);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[hci_irq - IRQ_OFFSET]);
|
||||
|
||||
di = drive_get_next(IF_SD);
|
||||
di = drive_get(IF_SD, 0, n);
|
||||
blk = di ? blk_by_legacy_dinfo(di) : NULL;
|
||||
carddev = qdev_new(TYPE_SD_CARD);
|
||||
qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
|
||||
|
@ -669,7 +669,8 @@ static void versal_virt_init(MachineState *machine)
|
||||
|
||||
/* Plugin SD cards. */
|
||||
for (i = 0; i < ARRAY_SIZE(s->soc.pmc.iou.sd); i++) {
|
||||
sd_plugin_card(&s->soc.pmc.iou.sd[i], drive_get_next(IF_SD));
|
||||
sd_plugin_card(&s->soc.pmc.iou.sd[i],
|
||||
drive_get(IF_SD, 0, i));
|
||||
}
|
||||
|
||||
s->binfo.ram_size = machine->ram_size;
|
||||
|
@ -169,7 +169,7 @@ static void xlnx_zcu102_init(MachineState *machine)
|
||||
/* Create and plug in the SD cards */
|
||||
for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) {
|
||||
BusState *bus;
|
||||
DriveInfo *di = drive_get_next(IF_SD);
|
||||
DriveInfo *di = drive_get(IF_SD, 0, i);
|
||||
BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL;
|
||||
DeviceState *carddev;
|
||||
char *bus_name;
|
||||
@ -190,7 +190,7 @@ static void xlnx_zcu102_init(MachineState *machine)
|
||||
BusState *spi_bus;
|
||||
DeviceState *flash_dev;
|
||||
qemu_irq cs_line;
|
||||
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||
DriveInfo *dinfo = drive_get(IF_MTD, 0, i);
|
||||
gchar *bus_name = g_strdup_printf("spi%d", i);
|
||||
|
||||
spi_bus = qdev_get_child_bus(DEVICE(&s->soc), bus_name);
|
||||
@ -212,7 +212,7 @@ static void xlnx_zcu102_init(MachineState *machine)
|
||||
BusState *spi_bus;
|
||||
DeviceState *flash_dev;
|
||||
qemu_irq cs_line;
|
||||
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||
DriveInfo *dinfo = drive_get(IF_MTD, 0, XLNX_ZYNQMP_NUM_SPIS + i);
|
||||
int bus = i / XLNX_ZYNQMP_NUM_QSPI_BUS_CS;
|
||||
gchar *bus_name = g_strdup_printf("qspi%d", bus);
|
||||
|
||||
|
@ -233,7 +233,7 @@ static void atmega_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
/* CPU */
|
||||
object_initialize_child(OBJECT(dev), "cpu", &s->cpu, mc->cpu_type);
|
||||
object_property_set_bool(OBJECT(&s->cpu), "realized", true, &error_abort);
|
||||
qdev_realize(DEVICE(&s->cpu), NULL, &error_abort);
|
||||
cpudev = DEVICE(&s->cpu);
|
||||
|
||||
/* SRAM */
|
||||
|
@ -222,7 +222,7 @@ int virtio_blk_data_plane_start(VirtIODevice *vdev)
|
||||
memory_region_transaction_commit();
|
||||
|
||||
while (j--) {
|
||||
virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), i);
|
||||
virtio_bus_cleanup_host_notifier(VIRTIO_BUS(qbus), j);
|
||||
}
|
||||
goto fail_host_notifiers;
|
||||
}
|
||||
|
@ -103,10 +103,11 @@ static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr,
|
||||
return retvalue;
|
||||
case USART_DR:
|
||||
DB_PRINT("Value: 0x%" PRIx32 ", %c\n", s->usart_dr, (char) s->usart_dr);
|
||||
retvalue = s->usart_dr & 0x3FF;
|
||||
s->usart_sr &= ~USART_SR_RXNE;
|
||||
qemu_chr_fe_accept_input(&s->chr);
|
||||
qemu_set_irq(s->irq, 0);
|
||||
return s->usart_dr & 0x3FF;
|
||||
return retvalue;
|
||||
case USART_BRR:
|
||||
return s->usart_brr;
|
||||
case USART_CR1:
|
||||
|
@ -784,9 +784,8 @@ static void numa_stat_memory_devices(NumaNodeMem node_mem[])
|
||||
break;
|
||||
case MEMORY_DEVICE_INFO_KIND_SGX_EPC:
|
||||
se = value->u.sgx_epc.data;
|
||||
/* TODO: once we support numa, assign to right node */
|
||||
node_mem[0].node_mem += se->size;
|
||||
node_mem[0].node_plugged_mem += se->size;
|
||||
node_mem[se->node].node_mem += se->size;
|
||||
node_mem[se->node].node_plugged_mem = 0;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include "hw/loader.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qom/object.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#define TYPE_ISA_VGA "isa-vga"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(ISAVGAState, ISA_VGA)
|
||||
@ -62,15 +61,6 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp)
|
||||
MemoryRegion *vga_io_memory;
|
||||
const MemoryRegionPortio *vga_ports, *vbe_ports;
|
||||
|
||||
/*
|
||||
* make sure this device is not being added twice, if so
|
||||
* exit without crashing qemu
|
||||
*/
|
||||
if (object_resolve_path_type("", TYPE_ISA_VGA, NULL)) {
|
||||
error_setg(errp, "at most one %s device is permitted", TYPE_ISA_VGA);
|
||||
return;
|
||||
}
|
||||
|
||||
s->global_vmstate = true;
|
||||
vga_common_init(s, OBJECT(dev));
|
||||
s->legacy_address_space = isa_address_space(isadev);
|
||||
|
@ -2068,6 +2068,8 @@ build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
|
||||
nvdimm_build_srat(table_data);
|
||||
}
|
||||
|
||||
sgx_epc_build_srat(table_data);
|
||||
|
||||
/*
|
||||
* TODO: this part is not in ACPI spec and current linux kernel boots fine
|
||||
* without these entries. But I recall there were issues the last time I
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
static Property sgx_epc_properties[] = {
|
||||
DEFINE_PROP_UINT64(SGX_EPC_ADDR_PROP, SGXEPCDevice, addr, 0),
|
||||
DEFINE_PROP_UINT32(SGX_EPC_NUMA_NODE_PROP, SGXEPCDevice, node, 0),
|
||||
DEFINE_PROP_LINK(SGX_EPC_MEMDEV_PROP, SGXEPCDevice, hostmem,
|
||||
TYPE_MEMORY_BACKEND_EPC, HostMemoryBackendEpc *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
@ -139,6 +140,8 @@ static void sgx_epc_md_fill_device_info(const MemoryDeviceState *md,
|
||||
se->memaddr = epc->addr;
|
||||
se->size = object_property_get_uint(OBJECT(epc), SGX_EPC_SIZE_PROP,
|
||||
NULL);
|
||||
se->node = object_property_get_uint(OBJECT(epc), SGX_EPC_NUMA_NODE_PROP,
|
||||
NULL);
|
||||
se->memdev = object_get_canonical_path(OBJECT(epc->hostmem));
|
||||
|
||||
info->u.sgx_epc.data = se;
|
||||
|
@ -6,6 +6,10 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-misc-target.h"
|
||||
|
||||
void sgx_epc_build_srat(GArray *table_data)
|
||||
{
|
||||
}
|
||||
|
||||
SGXInfo *qmp_query_sgx(Error **errp)
|
||||
{
|
||||
error_setg(errp, "SGX support is not compiled in");
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include <sys/ioctl.h>
|
||||
#include "hw/acpi/aml-build.h"
|
||||
|
||||
#define SGX_MAX_EPC_SECTIONS 8
|
||||
#define SGX_CPUID_EPC_INVALID 0x0
|
||||
@ -36,17 +37,59 @@
|
||||
|
||||
#define RETRY_NUM 2
|
||||
|
||||
static int sgx_epc_device_list(Object *obj, void *opaque)
|
||||
{
|
||||
GSList **list = opaque;
|
||||
|
||||
if (object_dynamic_cast(obj, TYPE_SGX_EPC)) {
|
||||
*list = g_slist_append(*list, DEVICE(obj));
|
||||
}
|
||||
|
||||
object_child_foreach(obj, sgx_epc_device_list, opaque);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static GSList *sgx_epc_get_device_list(void)
|
||||
{
|
||||
GSList *list = NULL;
|
||||
|
||||
object_child_foreach(qdev_get_machine(), sgx_epc_device_list, &list);
|
||||
return list;
|
||||
}
|
||||
|
||||
void sgx_epc_build_srat(GArray *table_data)
|
||||
{
|
||||
GSList *device_list = sgx_epc_get_device_list();
|
||||
|
||||
for (; device_list; device_list = device_list->next) {
|
||||
DeviceState *dev = device_list->data;
|
||||
Object *obj = OBJECT(dev);
|
||||
uint64_t addr, size;
|
||||
int node;
|
||||
|
||||
node = object_property_get_uint(obj, SGX_EPC_NUMA_NODE_PROP,
|
||||
&error_abort);
|
||||
addr = object_property_get_uint(obj, SGX_EPC_ADDR_PROP, &error_abort);
|
||||
size = object_property_get_uint(obj, SGX_EPC_SIZE_PROP, &error_abort);
|
||||
|
||||
build_srat_memory(table_data, addr, size, node, MEM_AFFINITY_ENABLED);
|
||||
}
|
||||
g_slist_free(device_list);
|
||||
}
|
||||
|
||||
static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high)
|
||||
{
|
||||
return (low & MAKE_64BIT_MASK(12, 20)) +
|
||||
((high & MAKE_64BIT_MASK(0, 20)) << 32);
|
||||
}
|
||||
|
||||
static uint64_t sgx_calc_host_epc_section_size(void)
|
||||
static SGXEPCSectionList *sgx_calc_host_epc_sections(void)
|
||||
{
|
||||
SGXEPCSectionList *head = NULL, **tail = &head;
|
||||
SGXEPCSection *section;
|
||||
uint32_t i, type;
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
uint64_t size = 0;
|
||||
uint32_t j = 0;
|
||||
|
||||
for (i = 0; i < SGX_MAX_EPC_SECTIONS; i++) {
|
||||
host_cpuid(0x12, i + 2, &eax, &ebx, &ecx, &edx);
|
||||
@ -60,10 +103,13 @@ static uint64_t sgx_calc_host_epc_section_size(void)
|
||||
break;
|
||||
}
|
||||
|
||||
size += sgx_calc_section_metric(ecx, edx);
|
||||
section = g_new0(SGXEPCSection, 1);
|
||||
section->node = j++;
|
||||
section->size = sgx_calc_section_metric(ecx, edx);
|
||||
QAPI_LIST_APPEND(tail, section);
|
||||
}
|
||||
|
||||
return size;
|
||||
return head;
|
||||
}
|
||||
|
||||
static void sgx_epc_reset(void *opaque)
|
||||
@ -127,13 +173,35 @@ SGXInfo *qmp_query_sgx_capabilities(Error **errp)
|
||||
info->sgx1 = eax & (1U << 0) ? true : false;
|
||||
info->sgx2 = eax & (1U << 1) ? true : false;
|
||||
|
||||
info->section_size = sgx_calc_host_epc_section_size();
|
||||
info->sections = sgx_calc_host_epc_sections();
|
||||
|
||||
close(fd);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static SGXEPCSectionList *sgx_get_epc_sections_list(void)
|
||||
{
|
||||
GSList *device_list = sgx_epc_get_device_list();
|
||||
SGXEPCSectionList *head = NULL, **tail = &head;
|
||||
SGXEPCSection *section;
|
||||
|
||||
for (; device_list; device_list = device_list->next) {
|
||||
DeviceState *dev = device_list->data;
|
||||
Object *obj = OBJECT(dev);
|
||||
|
||||
section = g_new0(SGXEPCSection, 1);
|
||||
section->node = object_property_get_uint(obj, SGX_EPC_NUMA_NODE_PROP,
|
||||
&error_abort);
|
||||
section->size = object_property_get_uint(obj, SGX_EPC_SIZE_PROP,
|
||||
&error_abort);
|
||||
QAPI_LIST_APPEND(tail, section);
|
||||
}
|
||||
g_slist_free(device_list);
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
SGXInfo *qmp_query_sgx(Error **errp)
|
||||
{
|
||||
SGXInfo *info = NULL;
|
||||
@ -152,14 +220,13 @@ SGXInfo *qmp_query_sgx(Error **errp)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SGXEPCState *sgx_epc = &pcms->sgx_epc;
|
||||
info = g_new0(SGXInfo, 1);
|
||||
|
||||
info->sgx = true;
|
||||
info->sgx1 = true;
|
||||
info->sgx2 = true;
|
||||
info->flc = true;
|
||||
info->section_size = sgx_epc->size;
|
||||
info->sections = sgx_get_epc_sections_list();
|
||||
|
||||
return info;
|
||||
}
|
||||
@ -167,6 +234,7 @@ SGXInfo *qmp_query_sgx(Error **errp)
|
||||
void hmp_info_sgx(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
Error *err = NULL;
|
||||
SGXEPCSectionList *section_list, *section;
|
||||
g_autoptr(SGXInfo) info = qmp_query_sgx(&err);
|
||||
|
||||
if (err) {
|
||||
@ -181,8 +249,14 @@ void hmp_info_sgx(Monitor *mon, const QDict *qdict)
|
||||
info->sgx2 ? "enabled" : "disabled");
|
||||
monitor_printf(mon, "FLC support: %s\n",
|
||||
info->flc ? "enabled" : "disabled");
|
||||
monitor_printf(mon, "size: %" PRIu64 "\n",
|
||||
info->section_size);
|
||||
|
||||
section_list = info->sections;
|
||||
for (section = section_list; section; section = section->next) {
|
||||
monitor_printf(mon, "NUMA node #%" PRId64 ": ",
|
||||
section->value->node);
|
||||
monitor_printf(mon, "size=%" PRIu64 "\n",
|
||||
section->value->size);
|
||||
}
|
||||
}
|
||||
|
||||
bool sgx_epc_get_section(int section_nr, uint64_t *addr, uint64_t *size)
|
||||
@ -226,6 +300,9 @@ void pc_machine_init_sgx_epc(PCMachineState *pcms)
|
||||
/* set the memdev link with memory backend */
|
||||
object_property_parse(obj, SGX_EPC_MEMDEV_PROP, list->value->memdev,
|
||||
&error_fatal);
|
||||
/* set the numa node property for sgx epc object */
|
||||
object_property_set_uint(obj, SGX_EPC_NUMA_NODE_PROP, list->value->node,
|
||||
&error_fatal);
|
||||
object_property_set_bool(obj, "realized", true, &error_fatal);
|
||||
object_unref(obj);
|
||||
}
|
||||
|
@ -286,6 +286,10 @@ static void vmmouse_realizefn(DeviceState *dev, Error **errp)
|
||||
|
||||
DPRINTF("vmmouse_init\n");
|
||||
|
||||
if (!s->i8042) {
|
||||
error_setg(errp, "'i8042' link is not set");
|
||||
return;
|
||||
}
|
||||
if (!object_resolve_path_type("", TYPE_VMPORT, NULL)) {
|
||||
error_setg(errp, "vmmouse needs a machine with vmport");
|
||||
return;
|
||||
|
@ -25,6 +25,11 @@ config APIC
|
||||
select MSI_NONBROKEN
|
||||
select I8259
|
||||
|
||||
config ARM_GIC_TCG
|
||||
bool
|
||||
default y
|
||||
depends on ARM_GIC && TCG
|
||||
|
||||
config ARM_GIC_KVM
|
||||
bool
|
||||
default y
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* ARM Generic Interrupt Controller v3
|
||||
* ARM Generic Interrupt Controller v3 (emulation)
|
||||
*
|
||||
* Copyright (c) 2015 Huawei.
|
||||
* Copyright (c) 2016 Linaro Limited
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* ARM Generic Interrupt Controller v3
|
||||
* ARM Generic Interrupt Controller v3 (emulation)
|
||||
*
|
||||
* Copyright (c) 2016 Linaro Limited
|
||||
* Written by Peter Maydell
|
||||
@ -21,14 +21,6 @@
|
||||
#include "hw/irq.h"
|
||||
#include "cpu.h"
|
||||
|
||||
void gicv3_set_gicv3state(CPUState *cpu, GICv3CPUState *s)
|
||||
{
|
||||
ARMCPU *arm_cpu = ARM_CPU(cpu);
|
||||
CPUARMState *env = &arm_cpu->env;
|
||||
|
||||
env->gicv3state = (void *)s;
|
||||
};
|
||||
|
||||
static GICv3CPUState *icc_cs_from_env(CPUARMState *env)
|
||||
{
|
||||
return env->gicv3state;
|
||||
@ -351,7 +343,8 @@ static uint32_t maintenance_interrupt_state(GICv3CPUState *cs)
|
||||
/* Scan list registers and fill in the U, NP and EOI bits */
|
||||
eoi_maintenance_interrupt_state(cs, &value);
|
||||
|
||||
if (cs->ich_hcr_el2 & (ICH_HCR_EL2_LRENPIE | ICH_HCR_EL2_EOICOUNT_MASK)) {
|
||||
if ((cs->ich_hcr_el2 & ICH_HCR_EL2_LRENPIE) &&
|
||||
(cs->ich_hcr_el2 & ICH_HCR_EL2_EOICOUNT_MASK)) {
|
||||
value |= ICH_MISR_EL2_LRENP;
|
||||
}
|
||||
|
||||
|
22
hw/intc/arm_gicv3_cpuif_common.c
Normal file
22
hw/intc/arm_gicv3_cpuif_common.c
Normal file
@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* ARM Generic Interrupt Controller v3
|
||||
*
|
||||
* Copyright (c) 2016 Linaro Limited
|
||||
* Written by Peter Maydell
|
||||
*
|
||||
* This code is licensed under the GPL, version 2 or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "gicv3_internal.h"
|
||||
#include "cpu.h"
|
||||
|
||||
void gicv3_set_gicv3state(CPUState *cpu, GICv3CPUState *s)
|
||||
{
|
||||
ARMCPU *arm_cpu = ARM_CPU(cpu);
|
||||
CPUARMState *env = &arm_cpu->env;
|
||||
|
||||
env->gicv3state = (void *)s;
|
||||
};
|
@ -274,21 +274,36 @@ static bool process_its_cmd(GICv3ITSState *s, uint64_t value, uint32_t offset,
|
||||
if (res != MEMTX_OK) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid command attributes: "
|
||||
"invalid dte: %"PRIx64" for %d (MEM_TX: %d)\n",
|
||||
__func__, dte, devid, res);
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((devid > s->dt.maxids.max_devids) || !dte_valid || !ite_valid ||
|
||||
!cte_valid || (eventid > max_eventid)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid command attributes "
|
||||
"devid %d or eventid %d or invalid dte %d or"
|
||||
"invalid cte %d or invalid ite %d\n",
|
||||
__func__, devid, eventid, dte_valid, cte_valid,
|
||||
ite_valid);
|
||||
|
||||
/*
|
||||
* in this implementation, in case of error
|
||||
* we ignore this command and move onto the next
|
||||
* command in the queue
|
||||
* In this implementation, in case of guest errors we ignore the
|
||||
* command and move onto the next command in the queue.
|
||||
*/
|
||||
if (devid > s->dt.maxids.max_devids) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid command attributes: devid %d>%d",
|
||||
__func__, devid, s->dt.maxids.max_devids);
|
||||
|
||||
} else if (!dte_valid || !ite_valid || !cte_valid) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid command attributes: "
|
||||
"dte: %s, ite: %s, cte: %s\n",
|
||||
__func__,
|
||||
dte_valid ? "valid" : "invalid",
|
||||
ite_valid ? "valid" : "invalid",
|
||||
cte_valid ? "valid" : "invalid");
|
||||
} else if (eventid > max_eventid) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid command attributes: eventid %d > %d\n",
|
||||
__func__, eventid, max_eventid);
|
||||
} else {
|
||||
/*
|
||||
* Current implementation only supports rdbase == procnum
|
||||
|
@ -3,12 +3,14 @@ softmmu_ss.add(when: 'CONFIG_ARM_GIC', if_true: files(
|
||||
'arm_gic.c',
|
||||
'arm_gic_common.c',
|
||||
'arm_gicv2m.c',
|
||||
'arm_gicv3.c',
|
||||
'arm_gicv3_common.c',
|
||||
'arm_gicv3_dist.c',
|
||||
'arm_gicv3_its_common.c',
|
||||
'arm_gicv3_redist.c',
|
||||
))
|
||||
softmmu_ss.add(when: 'CONFIG_ARM_GIC_TCG', if_true: files(
|
||||
'arm_gicv3.c',
|
||||
'arm_gicv3_dist.c',
|
||||
'arm_gicv3_its.c',
|
||||
'arm_gicv3_redist.c',
|
||||
))
|
||||
softmmu_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_HEATHROW_PIC', if_true: files('heathrow_pic.c'))
|
||||
@ -25,7 +27,8 @@ softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_PMU', if_true: files('xlnx-pmu-iomod-in
|
||||
|
||||
specific_ss.add(when: 'CONFIG_ALLWINNER_A10_PIC', if_true: files('allwinner-a10-pic.c'))
|
||||
specific_ss.add(when: 'CONFIG_APIC', if_true: files('apic.c', 'apic_common.c'))
|
||||
specific_ss.add(when: 'CONFIG_ARM_GIC', if_true: files('arm_gicv3_cpuif.c'))
|
||||
specific_ss.add(when: 'CONFIG_ARM_GIC', if_true: files('arm_gicv3_cpuif_common.c'))
|
||||
specific_ss.add(when: 'CONFIG_ARM_GIC_TCG', if_true: files('arm_gicv3_cpuif.c'))
|
||||
specific_ss.add(when: 'CONFIG_ARM_GIC_KVM', if_true: files('arm_gic_kvm.c'))
|
||||
specific_ss.add(when: ['CONFIG_ARM_GIC_KVM', 'TARGET_AARCH64'], if_true: files('arm_gicv3_kvm.c', 'arm_gicv3_its_kvm.c'))
|
||||
specific_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_nvic.c'))
|
||||
|
@ -183,7 +183,7 @@ petalogix_ml605_init(MachineState *machine)
|
||||
spi = (SSIBus *)qdev_get_child_bus(dev, "spi");
|
||||
|
||||
for (i = 0; i < NUM_SPI_FLASHES; i++) {
|
||||
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||
DriveInfo *dinfo = drive_get(IF_MTD, 0, i);
|
||||
qemu_irq cs_line;
|
||||
|
||||
dev = qdev_new("n25q128");
|
||||
|
@ -182,7 +182,11 @@ void bl_gen_write_ulong(uint32_t **p, target_ulong addr, target_ulong val)
|
||||
{
|
||||
bl_gen_load_ulong(p, BL_REG_K0, val);
|
||||
bl_gen_load_ulong(p, BL_REG_K1, addr);
|
||||
if (bootcpu_supports_isa(ISA_MIPS3)) {
|
||||
bl_gen_sd(p, BL_REG_K0, BL_REG_K1, 0x0);
|
||||
} else {
|
||||
bl_gen_sw(p, BL_REG_K0, BL_REG_K1, 0x0);
|
||||
}
|
||||
}
|
||||
|
||||
void bl_gen_write_u32(uint32_t **p, target_ulong addr, uint32_t val)
|
||||
|
@ -777,14 +777,15 @@ static void boston_mach_init(MachineState *machine)
|
||||
exit(1);
|
||||
}
|
||||
} else if (machine->kernel_filename) {
|
||||
uint64_t kernel_entry, kernel_high, kernel_size;
|
||||
uint64_t kernel_entry, kernel_high;
|
||||
ssize_t kernel_size;
|
||||
|
||||
kernel_size = load_elf(machine->kernel_filename, NULL,
|
||||
cpu_mips_kseg0_to_phys, NULL,
|
||||
&kernel_entry, NULL, &kernel_high,
|
||||
NULL, 0, EM_MIPS, 1, 0);
|
||||
|
||||
if (kernel_size) {
|
||||
if (kernel_size > 0) {
|
||||
int dt_size;
|
||||
g_autofree const void *dtb_file_data, *dtb_load_data;
|
||||
hwaddr dtb_paddr = QEMU_ALIGN_UP(kernel_high, 64 * KiB);
|
||||
|
@ -243,7 +243,7 @@ static uint64_t ivshmem_io_read(void *opaque, hwaddr addr,
|
||||
static const MemoryRegionOps ivshmem_mmio_ops = {
|
||||
.read = ivshmem_io_read,
|
||||
.write = ivshmem_io_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
|
@ -209,9 +209,9 @@ static void sifive_u_otp_realize(DeviceState *dev, Error **errp)
|
||||
TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
|
||||
|
||||
dinfo = drive_get_next(IF_PFLASH);
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
if (!dinfo) {
|
||||
dinfo = drive_get_next(IF_NONE);
|
||||
dinfo = drive_get(IF_NONE, 0, 0);
|
||||
if (dinfo) {
|
||||
warn_report("using \"-drive if=none\" for the OTP is deprecated, "
|
||||
"use \"-drive if=pflash\" instead.");
|
||||
|
@ -284,6 +284,12 @@ static void emc_halt_rx(NPCM7xxEMCState *emc, uint32_t mista_flag)
|
||||
emc_set_mista(emc, mista_flag);
|
||||
}
|
||||
|
||||
static void emc_enable_rx_and_flush(NPCM7xxEMCState *emc)
|
||||
{
|
||||
emc->rx_active = true;
|
||||
qemu_flush_queued_packets(qemu_get_queue(emc->nic));
|
||||
}
|
||||
|
||||
static void emc_set_next_tx_descriptor(NPCM7xxEMCState *emc,
|
||||
const NPCM7xxEMCTxDesc *tx_desc,
|
||||
uint32_t desc_addr)
|
||||
@ -581,13 +587,6 @@ static ssize_t emc_receive(NetClientState *nc, const uint8_t *buf, size_t len1)
|
||||
return len;
|
||||
}
|
||||
|
||||
static void emc_try_receive_next_packet(NPCM7xxEMCState *emc)
|
||||
{
|
||||
if (emc_can_receive(qemu_get_queue(emc->nic))) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(emc->nic));
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t npcm7xx_emc_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
NPCM7xxEMCState *emc = opaque;
|
||||
@ -703,7 +702,7 @@ static void npcm7xx_emc_write(void *opaque, hwaddr offset,
|
||||
emc->regs[REG_MGSTA] |= REG_MGSTA_RXHA;
|
||||
}
|
||||
if (value & REG_MCMDR_RXON) {
|
||||
emc->rx_active = true;
|
||||
emc_enable_rx_and_flush(emc);
|
||||
} else {
|
||||
emc_halt_rx(emc, 0);
|
||||
}
|
||||
@ -739,8 +738,7 @@ static void npcm7xx_emc_write(void *opaque, hwaddr offset,
|
||||
break;
|
||||
case REG_RSDR:
|
||||
if (emc->regs[REG_MCMDR] & REG_MCMDR_RXON) {
|
||||
emc->rx_active = true;
|
||||
emc_try_receive_next_packet(emc);
|
||||
emc_enable_rx_and_flush(emc);
|
||||
}
|
||||
break;
|
||||
case REG_MIIDA:
|
||||
|
@ -993,7 +993,7 @@ static void pnv_phb3_realize(DeviceState *dev, Error **errp)
|
||||
PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
|
||||
int i;
|
||||
|
||||
if (phb->phb_id >= PNV8_CHIP_PHB3_MAX) {
|
||||
if (phb->phb_id >= PNV_CHIP_GET_CLASS(phb->chip)->num_phbs) {
|
||||
error_setg(errp, "invalid PHB index: %d", phb->phb_id);
|
||||
return;
|
||||
}
|
||||
@ -1092,6 +1092,7 @@ static const char *pnv_phb3_root_bus_path(PCIHostState *host_bridge,
|
||||
static Property pnv_phb3_properties[] = {
|
||||
DEFINE_PROP_UINT32("index", PnvPHB3, phb_id, 0),
|
||||
DEFINE_PROP_UINT32("chip-id", PnvPHB3, chip_id, 0),
|
||||
DEFINE_PROP_LINK("chip", PnvPHB3, chip, TYPE_PNV_CHIP, PnvChip *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
@ -284,6 +284,17 @@ static void pnv_pbcq_realize(DeviceState *dev, Error **errp)
|
||||
pnv_xscom_region_init(&pbcq->xscom_spci_regs, OBJECT(dev),
|
||||
&pnv_pbcq_spci_xscom_ops, pbcq, name,
|
||||
PNV_XSCOM_PBCQ_SPCI_SIZE);
|
||||
|
||||
/* Populate the XSCOM address space. */
|
||||
pnv_xscom_add_subregion(phb->chip,
|
||||
PNV_XSCOM_PBCQ_NEST_BASE + 0x400 * phb->phb_id,
|
||||
&pbcq->xscom_nest_regs);
|
||||
pnv_xscom_add_subregion(phb->chip,
|
||||
PNV_XSCOM_PBCQ_PCI_BASE + 0x400 * phb->phb_id,
|
||||
&pbcq->xscom_pci_regs);
|
||||
pnv_xscom_add_subregion(phb->chip,
|
||||
PNV_XSCOM_PBCQ_SPCI_BASE + 0x040 * phb->phb_id,
|
||||
&pbcq->xscom_spci_regs);
|
||||
}
|
||||
|
||||
static int pnv_pbcq_dt_xscom(PnvXScomInterface *dev, void *fdt,
|
||||
|
@ -1205,6 +1205,7 @@ static void pnv_phb4_realize(DeviceState *dev, Error **errp)
|
||||
&phb->pci_mmio, &phb->pci_io,
|
||||
0, 4, TYPE_PNV_PHB4_ROOT_BUS);
|
||||
pci_setup_iommu(pci->bus, pnv_phb4_dma_iommu, phb);
|
||||
pci->bus->flags |= PCI_BUS_EXTENDED_CONFIG_SPACE;
|
||||
|
||||
/* Add a single Root port */
|
||||
qdev_prop_set_uint8(DEVICE(&phb->root), "chassis", phb->chip_id);
|
||||
|
@ -124,7 +124,7 @@ static uint64_t pnv_pec_stk_nest_xscom_read(void *opaque, hwaddr addr,
|
||||
static void pnv_pec_stk_update_map(PnvPhb4PecStack *stack)
|
||||
{
|
||||
PnvPhb4PecState *pec = stack->pec;
|
||||
MemoryRegion *sysmem = pec->system_memory;
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
uint64_t bar_en = stack->nest_regs[PEC_NEST_STK_BAR_EN];
|
||||
uint64_t bar, mask, size;
|
||||
char name[64];
|
||||
@ -374,20 +374,41 @@ static void pnv_pec_instance_init(Object *obj)
|
||||
}
|
||||
}
|
||||
|
||||
static int pnv_pec_phb_offset(PnvPhb4PecState *pec)
|
||||
{
|
||||
PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
|
||||
int index = pec->index;
|
||||
int offset = 0;
|
||||
|
||||
while (index--) {
|
||||
offset += pecc->num_stacks[index];
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static void pnv_pec_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PnvPhb4PecState *pec = PNV_PHB4_PEC(dev);
|
||||
PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
|
||||
char name[64];
|
||||
int i;
|
||||
|
||||
assert(pec->system_memory);
|
||||
if (pec->index >= PNV_CHIP_GET_CLASS(pec->chip)->num_pecs) {
|
||||
error_setg(errp, "invalid PEC index: %d", pec->index);
|
||||
return;
|
||||
}
|
||||
|
||||
pec->num_stacks = pecc->num_stacks[pec->index];
|
||||
|
||||
/* Create stacks */
|
||||
for (i = 0; i < pec->num_stacks; i++) {
|
||||
PnvPhb4PecStack *stack = &pec->stacks[i];
|
||||
Object *stk_obj = OBJECT(stack);
|
||||
int phb_id = pnv_pec_phb_offset(pec) + i;
|
||||
|
||||
object_property_set_int(stk_obj, "stack-no", i, &error_abort);
|
||||
object_property_set_int(stk_obj, "phb-id", phb_id, &error_abort);
|
||||
object_property_set_link(stk_obj, "pec", OBJECT(pec), &error_abort);
|
||||
if (!qdev_realize(DEVICE(stk_obj), NULL, errp)) {
|
||||
return;
|
||||
@ -460,10 +481,9 @@ static int pnv_pec_dt_xscom(PnvXScomInterface *dev, void *fdt,
|
||||
|
||||
static Property pnv_pec_properties[] = {
|
||||
DEFINE_PROP_UINT32("index", PnvPhb4PecState, index, 0),
|
||||
DEFINE_PROP_UINT32("num-stacks", PnvPhb4PecState, num_stacks, 0),
|
||||
DEFINE_PROP_UINT32("chip-id", PnvPhb4PecState, chip_id, 0),
|
||||
DEFINE_PROP_LINK("system-memory", PnvPhb4PecState, system_memory,
|
||||
TYPE_MEMORY_REGION, MemoryRegion *),
|
||||
DEFINE_PROP_LINK("chip", PnvPhb4PecState, chip, TYPE_PNV_CHIP,
|
||||
PnvChip *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@ -477,6 +497,13 @@ static uint32_t pnv_pec_xscom_nest_base(PnvPhb4PecState *pec)
|
||||
return PNV9_XSCOM_PEC_NEST_BASE + 0x400 * pec->index;
|
||||
}
|
||||
|
||||
/*
|
||||
* PEC0 -> 1 stack
|
||||
* PEC1 -> 2 stacks
|
||||
* PEC2 -> 3 stacks
|
||||
*/
|
||||
static const uint32_t pnv_pec_num_stacks[] = { 1, 2, 3 };
|
||||
|
||||
static void pnv_pec_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
@ -499,6 +526,9 @@ static void pnv_pec_class_init(ObjectClass *klass, void *data)
|
||||
pecc->compat_size = sizeof(compat);
|
||||
pecc->stk_compat = stk_compat;
|
||||
pecc->stk_compat_size = sizeof(stk_compat);
|
||||
pecc->version = PNV_PHB4_VERSION;
|
||||
pecc->device_id = PNV_PHB4_DEVICE_ID;
|
||||
pecc->num_stacks = pnv_pec_num_stacks;
|
||||
}
|
||||
|
||||
static const TypeInfo pnv_pec_type_info = {
|
||||
@ -519,12 +549,17 @@ static void pnv_pec_stk_instance_init(Object *obj)
|
||||
PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(obj);
|
||||
|
||||
object_initialize_child(obj, "phb", &stack->phb, TYPE_PNV_PHB4);
|
||||
object_property_add_alias(obj, "phb-id", OBJECT(&stack->phb), "index");
|
||||
}
|
||||
|
||||
static void pnv_pec_stk_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
PnvPhb4PecStack *stack = PNV_PHB4_PEC_STACK(dev);
|
||||
PnvPhb4PecState *pec = stack->pec;
|
||||
PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
|
||||
PnvChip *chip = pec->chip;
|
||||
uint32_t pec_nest_base;
|
||||
uint32_t pec_pci_base;
|
||||
char name[64];
|
||||
|
||||
assert(pec);
|
||||
@ -548,10 +583,32 @@ static void pnv_pec_stk_realize(DeviceState *dev, Error **errp)
|
||||
pnv_xscom_region_init(&stack->phb_regs_mr, OBJECT(&stack->phb),
|
||||
&pnv_phb4_xscom_ops, &stack->phb, name, 0x40);
|
||||
|
||||
/*
|
||||
* Let the machine/chip realize the PHB object to customize more
|
||||
* easily some fields
|
||||
*/
|
||||
object_property_set_int(OBJECT(&stack->phb), "chip-id", pec->chip_id,
|
||||
&error_fatal);
|
||||
object_property_set_int(OBJECT(&stack->phb), "version", pecc->version,
|
||||
&error_fatal);
|
||||
object_property_set_int(OBJECT(&stack->phb), "device-id", pecc->device_id,
|
||||
&error_fatal);
|
||||
object_property_set_link(OBJECT(&stack->phb), "stack", OBJECT(stack),
|
||||
&error_abort);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&stack->phb), errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
pec_nest_base = pecc->xscom_nest_base(pec);
|
||||
pec_pci_base = pecc->xscom_pci_base(pec);
|
||||
|
||||
/* Populate the XSCOM address space. */
|
||||
pnv_xscom_add_subregion(chip,
|
||||
pec_nest_base + 0x40 * (stack->stack_no + 1),
|
||||
&stack->nest_regs_mr);
|
||||
pnv_xscom_add_subregion(chip,
|
||||
pec_pci_base + 0x40 * (stack->stack_no + 1),
|
||||
&stack->pci_regs_mr);
|
||||
pnv_xscom_add_subregion(chip,
|
||||
pec_pci_base + PNV9_XSCOM_PEC_PCI_STK0 +
|
||||
0x40 * stack->stack_no,
|
||||
&stack->phb_regs_mr);
|
||||
}
|
||||
|
||||
static Property pnv_pec_stk_properties[] = {
|
||||
|
@ -36,9 +36,6 @@
|
||||
#include "hw/pci-host/uninorth.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
/* SMP is not enabled, for now */
|
||||
#define MAX_CPUS 1
|
||||
|
||||
#define NVRAM_SIZE 0x2000
|
||||
#define PROM_FILENAME "openbios-ppc"
|
||||
|
||||
|
@ -581,7 +581,8 @@ static void core99_machine_class_init(ObjectClass *oc, void *data)
|
||||
mc->desc = "Mac99 based PowerMAC";
|
||||
mc->init = ppc_core99_init;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->max_cpus = MAX_CPUS;
|
||||
/* SMP is not supported currently */
|
||||
mc->max_cpus = 1;
|
||||
mc->default_boot_order = "cd";
|
||||
mc->default_display = "std";
|
||||
mc->kvm_type = core99_kvm_type;
|
||||
|
@ -423,7 +423,8 @@ static void heathrow_class_init(ObjectClass *oc, void *data)
|
||||
mc->desc = "Heathrow based PowerMAC";
|
||||
mc->init = ppc_heathrow_init;
|
||||
mc->block_default_type = IF_IDE;
|
||||
mc->max_cpus = MAX_CPUS;
|
||||
/* SMP is not supported currently */
|
||||
mc->max_cpus = 1;
|
||||
#ifndef TARGET_PPC64
|
||||
mc->is_default = true;
|
||||
#endif
|
||||
|
177
hw/ppc/pnv.c
177
hw/ppc/pnv.c
@ -522,7 +522,7 @@ static void *pnv_dt_create(MachineState *machine)
|
||||
buf = qemu_uuid_unparse_strdup(&qemu_uuid);
|
||||
_FDT((fdt_setprop_string(fdt, 0, "vm,uuid", buf)));
|
||||
if (qemu_uuid_set) {
|
||||
_FDT((fdt_property_string(fdt, "system-id", buf)));
|
||||
_FDT((fdt_setprop_string(fdt, 0, "system-id", buf)));
|
||||
}
|
||||
g_free(buf);
|
||||
|
||||
@ -638,32 +638,47 @@ static ISABus *pnv_isa_create(PnvChip *chip, Error **errp)
|
||||
return PNV_CHIP_GET_CLASS(chip)->isa_create(chip, errp);
|
||||
}
|
||||
|
||||
static int pnv_chip_power8_pic_print_info_child(Object *child, void *opaque)
|
||||
{
|
||||
Monitor *mon = opaque;
|
||||
PnvPHB3 *phb3 = (PnvPHB3 *) object_dynamic_cast(child, TYPE_PNV_PHB3);
|
||||
|
||||
if (phb3) {
|
||||
pnv_phb3_msi_pic_print_info(&phb3->msis, mon);
|
||||
ics_pic_print_info(&phb3->lsis, mon);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pnv_chip_power8_pic_print_info(PnvChip *chip, Monitor *mon)
|
||||
{
|
||||
Pnv8Chip *chip8 = PNV8_CHIP(chip);
|
||||
int i;
|
||||
|
||||
ics_pic_print_info(&chip8->psi.ics, mon);
|
||||
for (i = 0; i < chip->num_phbs; i++) {
|
||||
pnv_phb3_msi_pic_print_info(&chip8->phbs[i].msis, mon);
|
||||
ics_pic_print_info(&chip8->phbs[i].lsis, mon);
|
||||
object_child_foreach(OBJECT(chip),
|
||||
pnv_chip_power8_pic_print_info_child, mon);
|
||||
}
|
||||
|
||||
static int pnv_chip_power9_pic_print_info_child(Object *child, void *opaque)
|
||||
{
|
||||
Monitor *mon = opaque;
|
||||
PnvPHB4 *phb4 = (PnvPHB4 *) object_dynamic_cast(child, TYPE_PNV_PHB4);
|
||||
|
||||
if (phb4) {
|
||||
pnv_phb4_pic_print_info(phb4, mon);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pnv_chip_power9_pic_print_info(PnvChip *chip, Monitor *mon)
|
||||
{
|
||||
Pnv9Chip *chip9 = PNV9_CHIP(chip);
|
||||
int i, j;
|
||||
|
||||
pnv_xive_pic_print_info(&chip9->xive, mon);
|
||||
pnv_psi_pic_print_info(&chip9->psi, mon);
|
||||
|
||||
for (i = 0; i < PNV9_CHIP_MAX_PEC; i++) {
|
||||
PnvPhb4PecState *pec = &chip9->pecs[i];
|
||||
for (j = 0; j < pec->num_stacks; j++) {
|
||||
pnv_phb4_pic_print_info(&pec->stacks[j].phb, mon);
|
||||
}
|
||||
}
|
||||
object_child_foreach_recursive(OBJECT(chip),
|
||||
pnv_chip_power9_pic_print_info_child, mon);
|
||||
}
|
||||
|
||||
static uint64_t pnv_chip_power8_xscom_core_base(PnvChip *chip,
|
||||
@ -742,6 +757,11 @@ static void pnv_init(MachineState *machine)
|
||||
DriveInfo *pnor = drive_get(IF_MTD, 0, 0);
|
||||
DeviceState *dev;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
error_report("The powernv machine does not work with KVM acceleration");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* allocate RAM */
|
||||
if (machine->ram_size < mc->default_ram_size) {
|
||||
char *sz = size_to_str(mc->default_ram_size);
|
||||
@ -1221,25 +1241,15 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
|
||||
/* PHB3 controllers */
|
||||
for (i = 0; i < chip->num_phbs; i++) {
|
||||
PnvPHB3 *phb = &chip8->phbs[i];
|
||||
PnvPBCQState *pbcq = &phb->pbcq;
|
||||
|
||||
object_property_set_int(OBJECT(phb), "index", i, &error_fatal);
|
||||
object_property_set_int(OBJECT(phb), "chip-id", chip->chip_id,
|
||||
&error_fatal);
|
||||
object_property_set_link(OBJECT(phb), "chip", OBJECT(chip),
|
||||
&error_fatal);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(phb), errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Populate the XSCOM address space. */
|
||||
pnv_xscom_add_subregion(chip,
|
||||
PNV_XSCOM_PBCQ_NEST_BASE + 0x400 * phb->phb_id,
|
||||
&pbcq->xscom_nest_regs);
|
||||
pnv_xscom_add_subregion(chip,
|
||||
PNV_XSCOM_PBCQ_PCI_BASE + 0x400 * phb->phb_id,
|
||||
&pbcq->xscom_pci_regs);
|
||||
pnv_xscom_add_subregion(chip,
|
||||
PNV_XSCOM_PBCQ_SPCI_BASE + 0x040 * phb->phb_id,
|
||||
&pbcq->xscom_spci_regs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1340,15 +1350,13 @@ static void pnv_chip_power9_instance_init(Object *obj)
|
||||
|
||||
object_initialize_child(obj, "homer", &chip9->homer, TYPE_PNV9_HOMER);
|
||||
|
||||
for (i = 0; i < PNV9_CHIP_MAX_PEC; i++) {
|
||||
/* Number of PECs is the chip default */
|
||||
chip->num_pecs = pcc->num_pecs;
|
||||
|
||||
for (i = 0; i < chip->num_pecs; i++) {
|
||||
object_initialize_child(obj, "pec[*]", &chip9->pecs[i],
|
||||
TYPE_PNV_PHB4_PEC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Number of PHBs is the chip default
|
||||
*/
|
||||
chip->num_phbs = pcc->num_phbs;
|
||||
}
|
||||
|
||||
static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp)
|
||||
@ -1378,30 +1386,22 @@ static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static void pnv_chip_power9_phb_realize(PnvChip *chip, Error **errp)
|
||||
static void pnv_chip_power9_pec_realize(PnvChip *chip, Error **errp)
|
||||
{
|
||||
Pnv9Chip *chip9 = PNV9_CHIP(chip);
|
||||
int i, j;
|
||||
int phb_id = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < PNV9_CHIP_MAX_PEC; i++) {
|
||||
for (i = 0; i < chip->num_pecs; i++) {
|
||||
PnvPhb4PecState *pec = &chip9->pecs[i];
|
||||
PnvPhb4PecClass *pecc = PNV_PHB4_PEC_GET_CLASS(pec);
|
||||
uint32_t pec_nest_base;
|
||||
uint32_t pec_pci_base;
|
||||
|
||||
object_property_set_int(OBJECT(pec), "index", i, &error_fatal);
|
||||
/*
|
||||
* PEC0 -> 1 stack
|
||||
* PEC1 -> 2 stacks
|
||||
* PEC2 -> 3 stacks
|
||||
*/
|
||||
object_property_set_int(OBJECT(pec), "num-stacks", i + 1,
|
||||
&error_fatal);
|
||||
object_property_set_int(OBJECT(pec), "chip-id", chip->chip_id,
|
||||
&error_fatal);
|
||||
object_property_set_link(OBJECT(pec), "system-memory",
|
||||
OBJECT(get_system_memory()), &error_abort);
|
||||
object_property_set_link(OBJECT(pec), "chip", OBJECT(chip),
|
||||
&error_fatal);
|
||||
if (!qdev_realize(DEVICE(pec), NULL, errp)) {
|
||||
return;
|
||||
}
|
||||
@ -1411,37 +1411,6 @@ static void pnv_chip_power9_phb_realize(PnvChip *chip, Error **errp)
|
||||
|
||||
pnv_xscom_add_subregion(chip, pec_nest_base, &pec->nest_regs_mr);
|
||||
pnv_xscom_add_subregion(chip, pec_pci_base, &pec->pci_regs_mr);
|
||||
|
||||
for (j = 0; j < pec->num_stacks && phb_id < chip->num_phbs;
|
||||
j++, phb_id++) {
|
||||
PnvPhb4PecStack *stack = &pec->stacks[j];
|
||||
Object *obj = OBJECT(&stack->phb);
|
||||
|
||||
object_property_set_int(obj, "index", phb_id, &error_fatal);
|
||||
object_property_set_int(obj, "chip-id", chip->chip_id,
|
||||
&error_fatal);
|
||||
object_property_set_int(obj, "version", PNV_PHB4_VERSION,
|
||||
&error_fatal);
|
||||
object_property_set_int(obj, "device-id", PNV_PHB4_DEVICE_ID,
|
||||
&error_fatal);
|
||||
object_property_set_link(obj, "stack", OBJECT(stack),
|
||||
&error_abort);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(obj), errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Populate the XSCOM address space. */
|
||||
pnv_xscom_add_subregion(chip,
|
||||
pec_nest_base + 0x40 * (stack->stack_no + 1),
|
||||
&stack->nest_regs_mr);
|
||||
pnv_xscom_add_subregion(chip,
|
||||
pec_pci_base + 0x40 * (stack->stack_no + 1),
|
||||
&stack->pci_regs_mr);
|
||||
pnv_xscom_add_subregion(chip,
|
||||
pec_pci_base + PNV9_XSCOM_PEC_PCI_STK0 +
|
||||
0x40 * stack->stack_no,
|
||||
&stack->phb_regs_mr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1537,8 +1506,8 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
|
||||
memory_region_add_subregion(get_system_memory(), PNV9_HOMER_BASE(chip),
|
||||
&chip9->homer.regs);
|
||||
|
||||
/* PHBs */
|
||||
pnv_chip_power9_phb_realize(chip, &local_err);
|
||||
/* PEC PHBs */
|
||||
pnv_chip_power9_pec_realize(chip, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
@ -1569,7 +1538,7 @@ static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
|
||||
k->xscom_core_base = pnv_chip_power9_xscom_core_base;
|
||||
k->xscom_pcba = pnv_chip_power9_xscom_pcba;
|
||||
dc->desc = "PowerNV Chip POWER9";
|
||||
k->num_phbs = 6;
|
||||
k->num_pecs = PNV9_CHIP_MAX_PEC;
|
||||
|
||||
device_class_set_parent_realize(dc, pnv_chip_power9_realize,
|
||||
&k->parent_realize);
|
||||
@ -1764,7 +1733,6 @@ static Property pnv_chip_properties[] = {
|
||||
DEFINE_PROP_UINT32("nr-cores", PnvChip, nr_cores, 1),
|
||||
DEFINE_PROP_UINT64("cores-mask", PnvChip, cores_mask, 0x0),
|
||||
DEFINE_PROP_UINT32("nr-threads", PnvChip, nr_threads, 1),
|
||||
DEFINE_PROP_UINT32("num-phbs", PnvChip, num_phbs, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@ -1795,10 +1763,32 @@ PowerPCCPU *pnv_chip_find_cpu(PnvChip *chip, uint32_t pir)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct ForeachPhb3Args {
|
||||
int irq;
|
||||
ICSState *ics;
|
||||
} ForeachPhb3Args;
|
||||
|
||||
static int pnv_ics_get_child(Object *child, void *opaque)
|
||||
{
|
||||
ForeachPhb3Args *args = opaque;
|
||||
PnvPHB3 *phb3 = (PnvPHB3 *) object_dynamic_cast(child, TYPE_PNV_PHB3);
|
||||
|
||||
if (phb3) {
|
||||
if (ics_valid_irq(&phb3->lsis, args->irq)) {
|
||||
args->ics = &phb3->lsis;
|
||||
}
|
||||
if (ics_valid_irq(ICS(&phb3->msis), args->irq)) {
|
||||
args->ics = ICS(&phb3->msis);
|
||||
}
|
||||
}
|
||||
return args->ics ? 1 : 0;
|
||||
}
|
||||
|
||||
static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
|
||||
{
|
||||
PnvMachineState *pnv = PNV_MACHINE(xi);
|
||||
int i, j;
|
||||
ForeachPhb3Args args = { irq, NULL };
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pnv->num_chips; i++) {
|
||||
PnvChip *chip = pnv->chips[i];
|
||||
@ -1807,32 +1797,37 @@ static ICSState *pnv_ics_get(XICSFabric *xi, int irq)
|
||||
if (ics_valid_irq(&chip8->psi.ics, irq)) {
|
||||
return &chip8->psi.ics;
|
||||
}
|
||||
for (j = 0; j < chip->num_phbs; j++) {
|
||||
if (ics_valid_irq(&chip8->phbs[j].lsis, irq)) {
|
||||
return &chip8->phbs[j].lsis;
|
||||
}
|
||||
if (ics_valid_irq(ICS(&chip8->phbs[j].msis), irq)) {
|
||||
return ICS(&chip8->phbs[j].msis);
|
||||
}
|
||||
|
||||
object_child_foreach(OBJECT(chip), pnv_ics_get_child, &args);
|
||||
if (args.ics) {
|
||||
return args.ics;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int pnv_ics_resend_child(Object *child, void *opaque)
|
||||
{
|
||||
PnvPHB3 *phb3 = (PnvPHB3 *) object_dynamic_cast(child, TYPE_PNV_PHB3);
|
||||
|
||||
if (phb3) {
|
||||
ics_resend(&phb3->lsis);
|
||||
ics_resend(ICS(&phb3->msis));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pnv_ics_resend(XICSFabric *xi)
|
||||
{
|
||||
PnvMachineState *pnv = PNV_MACHINE(xi);
|
||||
int i, j;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pnv->num_chips; i++) {
|
||||
PnvChip *chip = pnv->chips[i];
|
||||
Pnv8Chip *chip8 = PNV8_CHIP(pnv->chips[i]);
|
||||
|
||||
ics_resend(&chip8->psi.ics);
|
||||
for (j = 0; j < chip->num_phbs; j++) {
|
||||
ics_resend(&chip8->phbs[j].lsis);
|
||||
ics_resend(ICS(&chip8->phbs[j].msis));
|
||||
}
|
||||
object_child_foreach(OBJECT(chip), pnv_ics_resend_child, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1367,6 +1367,7 @@ int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
|
||||
if (dcr->dcr_read == NULL)
|
||||
goto error;
|
||||
*valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
|
||||
trace_ppc_dcr_read(dcrn, *valp);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1386,6 +1387,7 @@ int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val)
|
||||
dcr = &dcr_env->dcrn[dcrn];
|
||||
if (dcr->dcr_write == NULL)
|
||||
goto error;
|
||||
trace_ppc_dcr_write(dcrn, val);
|
||||
(*dcr->dcr_write)(dcr->opaque, dcrn, val);
|
||||
|
||||
return 0;
|
||||
|
@ -27,6 +27,13 @@
|
||||
|
||||
#include "hw/ppc/ppc4xx.h"
|
||||
|
||||
#define PPC405EP_SDRAM_BASE 0x00000000
|
||||
#define PPC405EP_NVRAM_BASE 0xF0000000
|
||||
#define PPC405EP_FPGA_BASE 0xF0300000
|
||||
#define PPC405EP_SRAM_BASE 0xFFF00000
|
||||
#define PPC405EP_SRAM_SIZE (512 * KiB)
|
||||
#define PPC405EP_FLASH_BASE 0xFFF80000
|
||||
|
||||
/* Bootinfo as set-up by u-boot */
|
||||
typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t;
|
||||
struct ppc4xx_bd_info_t {
|
||||
@ -50,19 +57,18 @@ struct ppc4xx_bd_info_t {
|
||||
uint32_t bi_plb_busfreq;
|
||||
uint32_t bi_pci_busfreq;
|
||||
uint8_t bi_pci_enetaddr[6];
|
||||
uint32_t bi_pci_enetaddr2[6];
|
||||
uint8_t bi_pci_enetaddr2[6]; /* PPC405EP specific */
|
||||
uint32_t bi_opbfreq;
|
||||
uint32_t bi_iic_fast[2];
|
||||
};
|
||||
|
||||
/* PowerPC 405 core */
|
||||
ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,
|
||||
uint32_t flags);
|
||||
ram_addr_t ppc405_set_bootinfo(CPUPPCState *env, ram_addr_t ram_size);
|
||||
|
||||
void ppc4xx_plb_init(CPUPPCState *env);
|
||||
void ppc405_ebc_init(CPUPPCState *env);
|
||||
|
||||
CPUPPCState *ppc405ep_init(MemoryRegion *address_space_mem,
|
||||
PowerPCCPU *ppc405ep_init(MemoryRegion *address_space_mem,
|
||||
MemoryRegion ram_memories[2],
|
||||
hwaddr ram_bases[2],
|
||||
hwaddr ram_sizes[2],
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user