Compare commits
11 Commits
v8.1.2
...
migration-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12b4a9c05e | ||
|
|
69f57525d2 | ||
|
|
e00d1a4213 | ||
|
|
afa710ea20 | ||
|
|
6f4e4392d0 | ||
|
|
7670030d45 | ||
|
|
879822f1e7 | ||
|
|
28f7429b27 | ||
|
|
4f34243b94 | ||
|
|
f6d4af8ec4 | ||
|
|
aa86afaa1a |
@@ -25,7 +25,6 @@
|
||||
# rebuilding all the object files we skip in the artifacts
|
||||
.native_build_artifact_template:
|
||||
artifacts:
|
||||
when: on_success
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build
|
||||
@@ -54,7 +53,6 @@
|
||||
extends: .common_test_job_template
|
||||
artifacts:
|
||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
||||
when: always
|
||||
expire_in: 7 days
|
||||
paths:
|
||||
- build/meson-logs/testlog.txt
|
||||
@@ -70,7 +68,7 @@
|
||||
policy: pull-push
|
||||
artifacts:
|
||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
||||
when: always
|
||||
when: on_failure
|
||||
expire_in: 7 days
|
||||
paths:
|
||||
- build/tests/results/latest/results.xml
|
||||
|
||||
@@ -454,7 +454,7 @@ gcov:
|
||||
IMAGE: ubuntu2204
|
||||
CONFIGURE_ARGS: --enable-gcov
|
||||
TARGETS: aarch64-softmmu ppc64-softmmu s390x-softmmu x86_64-softmmu
|
||||
MAKE_CHECK_ARGS: check-unit check-softfloat
|
||||
MAKE_CHECK_ARGS: check
|
||||
after_script:
|
||||
- cd build
|
||||
- gcovr --xml-pretty --exclude-unreachable-branches --print-summary
|
||||
@@ -462,12 +462,8 @@ gcov:
|
||||
coverage: /^\s*lines:\s*\d+.\d+\%/
|
||||
artifacts:
|
||||
name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA}
|
||||
when: always
|
||||
expire_in: 2 days
|
||||
paths:
|
||||
- build/meson-logs/testlog.txt
|
||||
reports:
|
||||
junit: build/meson-logs/testlog.junit.xml
|
||||
coverage_report:
|
||||
coverage_format: cobertura
|
||||
path: build/coverage.xml
|
||||
@@ -591,7 +587,6 @@ pages:
|
||||
- make -C build install DESTDIR=$(pwd)/temp-install
|
||||
- mv temp-install/usr/local/share/doc/qemu/* public/
|
||||
artifacts:
|
||||
when: on_success
|
||||
paths:
|
||||
- public
|
||||
variables:
|
||||
|
||||
@@ -15,7 +15,7 @@ env:
|
||||
folder: $HOME/.cache/qemu-vm
|
||||
install_script:
|
||||
- dnf update -y
|
||||
- dnf install -y git make openssh-clients qemu-img qemu-system-x86 wget meson
|
||||
- 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"
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
.cross_test_artifacts:
|
||||
artifacts:
|
||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
||||
when: always
|
||||
expire_in: 7 days
|
||||
paths:
|
||||
- build/meson-logs/testlog.txt
|
||||
|
||||
@@ -169,7 +169,6 @@ cross-win32-system:
|
||||
CROSS_SKIP_TARGETS: alpha-softmmu avr-softmmu hppa-softmmu m68k-softmmu
|
||||
microblazeel-softmmu mips64el-softmmu nios2-softmmu
|
||||
artifacts:
|
||||
when: on_success
|
||||
paths:
|
||||
- build/qemu-setup*.exe
|
||||
|
||||
@@ -185,7 +184,6 @@ cross-win64-system:
|
||||
or1k-softmmu rx-softmmu sh4eb-softmmu sparc64-softmmu
|
||||
tricore-softmmu xtensaeb-softmmu
|
||||
artifacts:
|
||||
when: on_success
|
||||
paths:
|
||||
- build/qemu-setup*.exe
|
||||
|
||||
|
||||
@@ -63,7 +63,6 @@ build-opensbi:
|
||||
stage: build
|
||||
needs: ['docker-opensbi']
|
||||
artifacts:
|
||||
when: on_success
|
||||
paths: # 'artifacts.zip' will contains the following files:
|
||||
- pc-bios/opensbi-riscv32-generic-fw_dynamic.bin
|
||||
- pc-bios/opensbi-riscv64-generic-fw_dynamic.bin
|
||||
|
||||
@@ -7,15 +7,10 @@
|
||||
cache:
|
||||
key: "${CI_JOB_NAME}-cache"
|
||||
paths:
|
||||
- msys64/var/cache
|
||||
when: always
|
||||
- ${CI_PROJECT_DIR}/msys64/var/cache
|
||||
needs: []
|
||||
stage: build
|
||||
timeout: 80m
|
||||
variables:
|
||||
# This feature doesn't (currently) work with PowerShell, it stops
|
||||
# the echo'ing of commands being run and doesn't show any timing
|
||||
FF_SCRIPT_SECTIONS: 0
|
||||
artifacts:
|
||||
name: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
|
||||
expire_in: 7 days
|
||||
@@ -24,40 +19,14 @@
|
||||
reports:
|
||||
junit: "build/meson-logs/testlog.junit.xml"
|
||||
before_script:
|
||||
- Write-Output "Acquiring msys2.exe installer at $(Get-Date -Format u)"
|
||||
- If ( !(Test-Path -Path msys64\var\cache ) ) {
|
||||
mkdir msys64\var\cache
|
||||
}
|
||||
- Invoke-WebRequest
|
||||
"https://repo.msys2.org/distrib/msys2-x86_64-latest.sfx.exe.sig"
|
||||
-outfile "msys2.exe.sig"
|
||||
- if ( Test-Path -Path msys64\var\cache\msys2.exe.sig ) {
|
||||
Write-Output "Cached installer sig" ;
|
||||
if ( ((Get-FileHash msys2.exe.sig).Hash -ne (Get-FileHash msys64\var\cache\msys2.exe.sig).Hash) ) {
|
||||
Write-Output "Mis-matched installer sig, new installer download required" ;
|
||||
Remove-Item -Path msys64\var\cache\msys2.exe.sig ;
|
||||
if ( Test-Path -Path msys64\var\cache\msys2.exe ) {
|
||||
Remove-Item -Path msys64\var\cache\msys2.exe
|
||||
}
|
||||
} else {
|
||||
Write-Output "Matched installer sig, cached installer still valid"
|
||||
}
|
||||
} else {
|
||||
Write-Output "No cached installer sig, new installer download required" ;
|
||||
if ( Test-Path -Path msys64\var\cache\msys2.exe ) {
|
||||
Remove-Item -Path msys64\var\cache\msys2.exe
|
||||
}
|
||||
}
|
||||
- if ( !(Test-Path -Path msys64\var\cache\msys2.exe ) ) {
|
||||
Write-Output "Fetching latest installer" ;
|
||||
- If ( !(Test-Path -Path msys64\var\cache\msys2.exe ) ) {
|
||||
Invoke-WebRequest
|
||||
"https://repo.msys2.org/distrib/msys2-x86_64-latest.sfx.exe"
|
||||
-outfile "msys64\var\cache\msys2.exe" ;
|
||||
Copy-Item -Path msys2.exe.sig -Destination msys64\var\cache\msys2.exe.sig
|
||||
} else {
|
||||
Write-Output "Using cached installer"
|
||||
"https://github.com/msys2/msys2-installer/releases/download/2022-06-03/msys2-base-x86_64-20220603.sfx.exe"
|
||||
-outfile "msys64\var\cache\msys2.exe"
|
||||
}
|
||||
- Write-Output "Invoking msys2.exe installer at $(Get-Date -Format u)"
|
||||
- msys64\var\cache\msys2.exe -y
|
||||
- ((Get-Content -path .\msys64\etc\\post-install\\07-pacman-key.post -Raw)
|
||||
-replace '--refresh-keys', '--version') |
|
||||
@@ -66,66 +35,97 @@
|
||||
- .\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"
|
||||
script:
|
||||
- Write-Output "Installing mingw packages at $(Get-Date -Format u)"
|
||||
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
|
||||
bison diffutils flex
|
||||
git grep make sed
|
||||
$MINGW_TARGET-capstone
|
||||
$MINGW_TARGET-curl
|
||||
$MINGW_TARGET-cyrus-sasl
|
||||
$MINGW_TARGET-dtc
|
||||
$MINGW_TARGET-gcc
|
||||
$MINGW_TARGET-glib2
|
||||
$MINGW_TARGET-gnutls
|
||||
$MINGW_TARGET-gtk3
|
||||
$MINGW_TARGET-libgcrypt
|
||||
$MINGW_TARGET-libjpeg-turbo
|
||||
$MINGW_TARGET-libnfs
|
||||
$MINGW_TARGET-libpng
|
||||
$MINGW_TARGET-libssh
|
||||
$MINGW_TARGET-libtasn1
|
||||
$MINGW_TARGET-libusb
|
||||
$MINGW_TARGET-lzo2
|
||||
$MINGW_TARGET-nettle
|
||||
$MINGW_TARGET-ninja
|
||||
$MINGW_TARGET-pixman
|
||||
$MINGW_TARGET-pkgconf
|
||||
$MINGW_TARGET-python
|
||||
$MINGW_TARGET-SDL2
|
||||
$MINGW_TARGET-SDL2_image
|
||||
$MINGW_TARGET-snappy
|
||||
$MINGW_TARGET-spice
|
||||
$MINGW_TARGET-usbredir
|
||||
$MINGW_TARGET-zstd "
|
||||
- Write-Output "Running build at $(Get-Date -Format u)"
|
||||
- $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
|
||||
- $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ..\msys64\usr\bin\bash -lc "../configure --enable-fdt=system $CONFIGURE_ARGS"
|
||||
- ..\msys64\usr\bin\bash -lc "make"
|
||||
- ..\msys64\usr\bin\bash -lc "make check MTESTARGS='$TEST_ARGS' || { cat meson-logs/testlog.txt; exit 1; } ;"
|
||||
- Write-Output "Finished build at $(Get-Date -Format u)"
|
||||
|
||||
msys2-64bit:
|
||||
extends: .shared_msys2_builder
|
||||
variables:
|
||||
MINGW_TARGET: mingw-w64-x86_64
|
||||
MSYSTEM: MINGW64
|
||||
# do not remove "--without-default-devices"!
|
||||
# commit 9f8e6cad65a6 ("gitlab-ci: Speed up the msys2-64bit job by using --without-default-devices"
|
||||
# changed to compile QEMU with the --without-default-devices switch
|
||||
# for the msys2 64-bit job, due to the build could not complete within
|
||||
CONFIGURE_ARGS: --target-list=x86_64-softmmu --without-default-devices -Ddebug=false -Doptimization=0
|
||||
# qTests don't run successfully with "--without-default-devices",
|
||||
# so let's exclude the qtests from CI for now.
|
||||
TEST_ARGS: --no-suite qtest
|
||||
script:
|
||||
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
|
||||
bison diffutils flex
|
||||
git grep make sed
|
||||
mingw-w64-x86_64-capstone
|
||||
mingw-w64-x86_64-curl
|
||||
mingw-w64-x86_64-cyrus-sasl
|
||||
mingw-w64-x86_64-dtc
|
||||
mingw-w64-x86_64-gcc
|
||||
mingw-w64-x86_64-glib2
|
||||
mingw-w64-x86_64-gnutls
|
||||
mingw-w64-x86_64-gtk3
|
||||
mingw-w64-x86_64-libgcrypt
|
||||
mingw-w64-x86_64-libjpeg-turbo
|
||||
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-lzo2
|
||||
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-spice
|
||||
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
|
||||
- $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink
|
||||
- mkdir build
|
||||
- cd build
|
||||
# Note: do not remove "--without-default-devices"!
|
||||
# commit 9f8e6cad65a6 ("gitlab-ci: Speed up the msys2-64bit job by using --without-default-devices"
|
||||
# changed to compile QEMU with the --without-default-devices switch
|
||||
# for the msys2 64-bit job, due to the build could not complete within
|
||||
# the project timeout.
|
||||
- ..\msys64\usr\bin\bash -lc '../configure --target-list=x86_64-softmmu
|
||||
--without-default-devices --enable-fdt=system'
|
||||
- ..\msys64\usr\bin\bash -lc 'make'
|
||||
# qTests don't run successfully with "--without-default-devices",
|
||||
# so let's exclude the qtests from CI for now.
|
||||
- ..\msys64\usr\bin\bash -lc 'make check MTESTARGS=\"--no-suite qtest\" || { cat meson-logs/testlog.txt; exit 1; } ;'
|
||||
|
||||
msys2-32bit:
|
||||
extends: .shared_msys2_builder
|
||||
variables:
|
||||
MINGW_TARGET: mingw-w64-i686
|
||||
MSYSTEM: MINGW32
|
||||
CONFIGURE_ARGS: --target-list=ppc64-softmmu -Ddebug=false -Doptimization=0
|
||||
TEST_ARGS: --no-suite qtest
|
||||
script:
|
||||
- .\msys64\usr\bin\bash -lc "pacman -Sy --noconfirm --needed
|
||||
bison diffutils flex
|
||||
git grep make sed
|
||||
mingw-w64-i686-capstone
|
||||
mingw-w64-i686-curl
|
||||
mingw-w64-i686-cyrus-sasl
|
||||
mingw-w64-i686-dtc
|
||||
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-libnfs
|
||||
mingw-w64-i686-libpng
|
||||
mingw-w64-i686-libssh
|
||||
mingw-w64-i686-libtasn1
|
||||
mingw-w64-i686-libusb
|
||||
mingw-w64-i686-lzo2
|
||||
mingw-w64-i686-nettle
|
||||
mingw-w64-i686-ninja
|
||||
mingw-w64-i686-pixman
|
||||
mingw-w64-i686-pkgconf
|
||||
mingw-w64-i686-python
|
||||
mingw-w64-i686-SDL2
|
||||
mingw-w64-i686-SDL2_image
|
||||
mingw-w64-i686-snappy
|
||||
mingw-w64-i686-spice
|
||||
mingw-w64-i686-usbredir
|
||||
mingw-w64-i686-zstd "
|
||||
- $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
|
||||
- $env:MSYSTEM = 'MINGW32' # Start a 32-bit MinGW environment
|
||||
- $env:MSYS = 'winsymlinks:native' # Enable native Windows symlink
|
||||
- mkdir build
|
||||
- cd build
|
||||
- ..\msys64\usr\bin\bash -lc '../configure --target-list=ppc64-softmmu
|
||||
--enable-fdt=system'
|
||||
- ..\msys64\usr\bin\bash -lc 'make'
|
||||
- ..\msys64\usr\bin\bash -lc 'make check MTESTARGS=\"--no-suite qtest\" ||
|
||||
{ cat meson-logs/testlog.txt; exit 1; }'
|
||||
|
||||
38
MAINTAINERS
38
MAINTAINERS
@@ -452,6 +452,8 @@ S: Supported
|
||||
F: target/s390x/kvm/
|
||||
F: target/s390x/machine.c
|
||||
F: target/s390x/sigp.c
|
||||
F: hw/s390x/pv.c
|
||||
F: include/hw/s390x/pv.h
|
||||
F: gdb-xml/s390*.xml
|
||||
T: git https://github.com/borntraeger/qemu.git s390-next
|
||||
L: qemu-s390x@nongnu.org
|
||||
@@ -2118,24 +2120,17 @@ F: include/sysemu/balloon.h
|
||||
virtio-9p
|
||||
M: Greg Kurz <groug@kaod.org>
|
||||
M: Christian Schoenebeck <qemu_oss@crudebyte.com>
|
||||
S: Maintained
|
||||
S: Odd Fixes
|
||||
W: https://wiki.qemu.org/Documentation/9p
|
||||
F: hw/9pfs/
|
||||
X: hw/9pfs/xen-9p*
|
||||
X: hw/9pfs/9p-proxy*
|
||||
F: fsdev/
|
||||
X: fsdev/virtfs-proxy-helper.c
|
||||
F: docs/tools/virtfs-proxy-helper.rst
|
||||
F: tests/qtest/virtio-9p-test.c
|
||||
F: tests/qtest/libqos/virtio-9p*
|
||||
T: git https://gitlab.com/gkurz/qemu.git 9p-next
|
||||
T: git https://github.com/cschoenebeck/qemu.git 9p.next
|
||||
|
||||
virtio-9p-proxy
|
||||
F: hw/9pfs/9p-proxy*
|
||||
F: fsdev/virtfs-proxy-helper.c
|
||||
F: docs/tools/virtfs-proxy-helper.rst
|
||||
S: Obsolete
|
||||
|
||||
virtio-blk
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
L: qemu-block@nongnu.org
|
||||
@@ -2215,13 +2210,6 @@ F: hw/virtio/vhost-user-gpio*
|
||||
F: include/hw/virtio/vhost-user-gpio.h
|
||||
F: tests/qtest/libqos/virtio-gpio.*
|
||||
|
||||
vhost-user-scmi
|
||||
R: mzamazal@redhat.com
|
||||
S: Supported
|
||||
F: hw/virtio/vhost-user-scmi*
|
||||
F: include/hw/virtio/vhost-user-scmi.h
|
||||
F: tests/qtest/libqos/virtio-scmi.*
|
||||
|
||||
virtio-crypto
|
||||
M: Gonglei <arei.gonglei@huawei.com>
|
||||
S: Supported
|
||||
@@ -2229,13 +2217,6 @@ F: hw/virtio/virtio-crypto.c
|
||||
F: hw/virtio/virtio-crypto-pci.c
|
||||
F: include/hw/virtio/virtio-crypto.h
|
||||
|
||||
virtio based memory device
|
||||
M: David Hildenbrand <david@redhat.com>
|
||||
S: Supported
|
||||
F: hw/virtio/virtio-md-pci.c
|
||||
F: include/hw/virtio/virtio-md-pci.h
|
||||
F: stubs/virtio-md-pci.c
|
||||
|
||||
virtio-mem
|
||||
M: David Hildenbrand <david@redhat.com>
|
||||
S: Supported
|
||||
@@ -3125,7 +3106,6 @@ R: Qiuhao Li <Qiuhao.Li@outlook.com>
|
||||
S: Maintained
|
||||
F: tests/qtest/fuzz/
|
||||
F: tests/qtest/fuzz-*test.c
|
||||
F: tests/docker/test-fuzz
|
||||
F: scripts/oss-fuzz/
|
||||
F: hw/mem/sparse-mem.c
|
||||
F: docs/devel/fuzzing.rst
|
||||
@@ -3209,15 +3189,6 @@ F: qapi/migration.json
|
||||
F: tests/migration/
|
||||
F: util/userfaultfd.c
|
||||
|
||||
Migration dirty limit and dirty page rate
|
||||
M: Hyman Huang <yong.huang@smartx.com>
|
||||
S: Maintained
|
||||
F: softmmu/dirtylimit.c
|
||||
F: include/sysemu/dirtylimit.h
|
||||
F: migration/dirtyrate.c
|
||||
F: migration/dirtyrate.h
|
||||
F: include/sysemu/dirtyrate.h
|
||||
|
||||
D-Bus
|
||||
M: Marc-André Lureau <marcandre.lureau@redhat.com>
|
||||
S: Maintained
|
||||
@@ -3245,7 +3216,6 @@ M: Daniel P. Berrange <berrange@redhat.com>
|
||||
S: Maintained
|
||||
F: crypto/
|
||||
F: include/crypto/
|
||||
F: host/include/*/host/crypto/
|
||||
F: qapi/crypto.json
|
||||
F: tests/unit/test-crypto-*
|
||||
F: tests/bench/benchmark-crypto-*
|
||||
|
||||
2
Makefile
2
Makefile
@@ -28,7 +28,7 @@ quiet-command = $(quiet-@)$(call quiet-command-run,$1,$2,$3)
|
||||
|
||||
UNCHECKED_GOALS := TAGS gtags cscope ctags dist \
|
||||
help check-help print-% \
|
||||
docker docker-% lcitool-refresh vm-help vm-test vm-build-%
|
||||
docker docker-% vm-help vm-test vm-build-%
|
||||
|
||||
all:
|
||||
.PHONY: all clean distclean recurse-all dist msi FORCE
|
||||
|
||||
@@ -2458,7 +2458,7 @@ static int kvm_init(MachineState *ms)
|
||||
KVMState *s;
|
||||
const KVMCapabilityInfo *missing_cap;
|
||||
int ret;
|
||||
int type;
|
||||
int type = 0;
|
||||
uint64_t dirty_log_manual_caps;
|
||||
|
||||
qemu_mutex_init(&kml_slots_lock);
|
||||
@@ -2523,8 +2523,6 @@ static int kvm_init(MachineState *ms)
|
||||
type = mc->kvm_type(ms, kvm_type);
|
||||
} else if (mc->kvm_type) {
|
||||
type = mc->kvm_type(ms, NULL);
|
||||
} else {
|
||||
type = kvm_arch_get_default_type(ms);
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -2814,7 +2812,7 @@ void kvm_flush_coalesced_mmio_buffer(void)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
|
||||
if (!s || s->coalesced_flush_in_progress) {
|
||||
if (s->coalesced_flush_in_progress) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ CMPXCHG_HELPER(cmpxchgq_be, uint64_t)
|
||||
CMPXCHG_HELPER(cmpxchgq_le, uint64_t)
|
||||
#endif
|
||||
|
||||
#if HAVE_CMPXCHG128
|
||||
#ifdef CONFIG_CMPXCHG128
|
||||
CMPXCHG_HELPER(cmpxchgo_be, Int128)
|
||||
CMPXCHG_HELPER(cmpxchgo_le, Int128)
|
||||
#endif
|
||||
|
||||
@@ -33,6 +33,36 @@ void cpu_loop_exit_noexc(CPUState *cpu)
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SOFTMMU)
|
||||
void cpu_reloading_memory_map(void)
|
||||
{
|
||||
if (qemu_in_vcpu_thread() && current_cpu->running) {
|
||||
/* The guest can in theory prolong the RCU critical section as long
|
||||
* as it feels like. The major problem with this is that because it
|
||||
* can do multiple reconfigurations of the memory map within the
|
||||
* critical section, we could potentially accumulate an unbounded
|
||||
* collection of memory data structures awaiting reclamation.
|
||||
*
|
||||
* Because the only thing we're currently protecting with RCU is the
|
||||
* memory data structures, it's sufficient to break the critical section
|
||||
* in this callback, which we know will get called every time the
|
||||
* memory map is rearranged.
|
||||
*
|
||||
* (If we add anything else in the system that uses RCU to protect
|
||||
* its data structures, we will need to implement some other mechanism
|
||||
* to force TCG CPUs to exit the critical section, at which point this
|
||||
* part of this callback might become unnecessary.)
|
||||
*
|
||||
* This pair matches cpu_exec's rcu_read_lock()/rcu_read_unlock(), which
|
||||
* only protects cpu->as->dispatch. Since we know our caller is about
|
||||
* to reload it, it's safe to split the critical section.
|
||||
*/
|
||||
rcu_read_unlock();
|
||||
rcu_read_lock();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void cpu_loop_exit(CPUState *cpu)
|
||||
{
|
||||
/* Undo the setting in cpu_tb_exec. */
|
||||
|
||||
@@ -298,7 +298,7 @@ static void log_cpu_exec(vaddr pc, CPUState *cpu,
|
||||
if (qemu_log_in_addr_range(pc)) {
|
||||
qemu_log_mask(CPU_LOG_EXEC,
|
||||
"Trace %d: %p [%08" PRIx64
|
||||
"/%016" VADDR_PRIx "/%08x/%08x] %s\n",
|
||||
"/%" VADDR_PRIx "/%08x/%08x] %s\n",
|
||||
cpu->cpu_index, tb->tc.ptr, tb->cs_base, pc,
|
||||
tb->flags, tb->cflags, lookup_symbol(pc));
|
||||
|
||||
@@ -487,7 +487,7 @@ cpu_tb_exec(CPUState *cpu, TranslationBlock *itb, int *tb_exit)
|
||||
if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
|
||||
vaddr pc = log_pc(cpu, last_tb);
|
||||
if (qemu_log_in_addr_range(pc)) {
|
||||
qemu_log("Stopped execution of TB chain before %p [%016"
|
||||
qemu_log("Stopped execution of TB chain before %p [%"
|
||||
VADDR_PRIx "] %s\n",
|
||||
last_tb->tc.ptr, pc, lookup_symbol(pc));
|
||||
}
|
||||
@@ -526,43 +526,6 @@ static void cpu_exec_exit(CPUState *cpu)
|
||||
}
|
||||
}
|
||||
|
||||
static void cpu_exec_longjmp_cleanup(CPUState *cpu)
|
||||
{
|
||||
/* Non-buggy compilers preserve this; assert the correct value. */
|
||||
g_assert(cpu == current_cpu);
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
clear_helper_retaddr();
|
||||
if (have_mmap_lock()) {
|
||||
mmap_unlock();
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* For softmmu, a tlb_fill fault during translation will land here,
|
||||
* and we need to release any page locks held. In system mode we
|
||||
* have one tcg_ctx per thread, so we know it was this cpu doing
|
||||
* the translation.
|
||||
*
|
||||
* Alternative 1: Install a cleanup to be called via an exception
|
||||
* handling safe longjmp. It seems plausible that all our hosts
|
||||
* support such a thing. We'd have to properly register unwind info
|
||||
* for the JIT for EH, rather that just for GDB.
|
||||
*
|
||||
* Alternative 2: Set and restore cpu->jmp_env in tb_gen_code to
|
||||
* capture the cpu_loop_exit longjmp, perform the cleanup, and
|
||||
* jump again to arrive here.
|
||||
*/
|
||||
if (tcg_ctx->gen_tb) {
|
||||
tb_unlock_pages(tcg_ctx->gen_tb);
|
||||
tcg_ctx->gen_tb = NULL;
|
||||
}
|
||||
#endif
|
||||
if (qemu_mutex_iothread_locked()) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
assert_no_pages_locked();
|
||||
}
|
||||
|
||||
void cpu_exec_step_atomic(CPUState *cpu)
|
||||
{
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
@@ -605,7 +568,16 @@ void cpu_exec_step_atomic(CPUState *cpu)
|
||||
cpu_tb_exec(cpu, tb, &tb_exit);
|
||||
cpu_exec_exit(cpu);
|
||||
} else {
|
||||
cpu_exec_longjmp_cleanup(cpu);
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
clear_helper_retaddr();
|
||||
if (have_mmap_lock()) {
|
||||
mmap_unlock();
|
||||
}
|
||||
#endif
|
||||
if (qemu_mutex_iothread_locked()) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
assert_no_pages_locked();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -720,7 +692,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
||||
&& cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0) {
|
||||
/* Execute just one insn to trigger exception pending in the log */
|
||||
cpu->cflags_next_tb = (curr_cflags(cpu) & ~CF_USE_ICOUNT)
|
||||
| CF_LAST_IO | CF_NOIRQ | 1;
|
||||
| CF_NOIRQ | 1;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
@@ -1051,7 +1023,20 @@ static int cpu_exec_setjmp(CPUState *cpu, SyncClocks *sc)
|
||||
{
|
||||
/* Prepare setjmp context for exception handling. */
|
||||
if (unlikely(sigsetjmp(cpu->jmp_env, 0) != 0)) {
|
||||
cpu_exec_longjmp_cleanup(cpu);
|
||||
/* Non-buggy compilers preserve this; assert the correct value. */
|
||||
g_assert(cpu == current_cpu);
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
clear_helper_retaddr();
|
||||
if (have_mmap_lock()) {
|
||||
mmap_unlock();
|
||||
}
|
||||
#endif
|
||||
if (qemu_mutex_iothread_locked()) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
|
||||
assert_no_pages_locked();
|
||||
}
|
||||
|
||||
return cpu_exec_loop(cpu, sc);
|
||||
|
||||
@@ -497,8 +497,8 @@ static void tlb_flush_page_locked(CPUArchState *env, int midx, vaddr page)
|
||||
|
||||
/* Check if we need to flush due to large pages. */
|
||||
if ((page & lp_mask) == lp_addr) {
|
||||
tlb_debug("forcing full flush midx %d (%016"
|
||||
VADDR_PRIx "/%016" VADDR_PRIx ")\n",
|
||||
tlb_debug("forcing full flush midx %d (%"
|
||||
VADDR_PRIx "/%" VADDR_PRIx ")\n",
|
||||
midx, lp_addr, lp_mask);
|
||||
tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime());
|
||||
} else {
|
||||
@@ -527,7 +527,7 @@ static void tlb_flush_page_by_mmuidx_async_0(CPUState *cpu,
|
||||
|
||||
assert_cpu_is_self(cpu);
|
||||
|
||||
tlb_debug("page addr: %016" VADDR_PRIx " mmu_map:0x%x\n", addr, idxmap);
|
||||
tlb_debug("page addr: %" VADDR_PRIx " mmu_map:0x%x\n", addr, idxmap);
|
||||
|
||||
qemu_spin_lock(&env_tlb(env)->c.lock);
|
||||
for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
|
||||
@@ -591,7 +591,7 @@ static void tlb_flush_page_by_mmuidx_async_2(CPUState *cpu,
|
||||
|
||||
void tlb_flush_page_by_mmuidx(CPUState *cpu, vaddr addr, uint16_t idxmap)
|
||||
{
|
||||
tlb_debug("addr: %016" VADDR_PRIx " mmu_idx:%" PRIx16 "\n", addr, idxmap);
|
||||
tlb_debug("addr: %" VADDR_PRIx " mmu_idx:%" PRIx16 "\n", addr, idxmap);
|
||||
|
||||
/* This should already be page aligned */
|
||||
addr &= TARGET_PAGE_MASK;
|
||||
@@ -625,7 +625,7 @@ void tlb_flush_page(CPUState *cpu, vaddr addr)
|
||||
void tlb_flush_page_by_mmuidx_all_cpus(CPUState *src_cpu, vaddr addr,
|
||||
uint16_t idxmap)
|
||||
{
|
||||
tlb_debug("addr: %016" VADDR_PRIx " mmu_idx:%"PRIx16"\n", addr, idxmap);
|
||||
tlb_debug("addr: %" VADDR_PRIx " mmu_idx:%"PRIx16"\n", addr, idxmap);
|
||||
|
||||
/* This should already be page aligned */
|
||||
addr &= TARGET_PAGE_MASK;
|
||||
@@ -666,7 +666,7 @@ void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *src_cpu,
|
||||
vaddr addr,
|
||||
uint16_t idxmap)
|
||||
{
|
||||
tlb_debug("addr: %016" VADDR_PRIx " mmu_idx:%"PRIx16"\n", addr, idxmap);
|
||||
tlb_debug("addr: %" VADDR_PRIx " mmu_idx:%"PRIx16"\n", addr, idxmap);
|
||||
|
||||
/* This should already be page aligned */
|
||||
addr &= TARGET_PAGE_MASK;
|
||||
@@ -728,7 +728,7 @@ static void tlb_flush_range_locked(CPUArchState *env, int midx,
|
||||
*/
|
||||
if (mask < f->mask || len > f->mask) {
|
||||
tlb_debug("forcing full flush midx %d ("
|
||||
"%016" VADDR_PRIx "/%016" VADDR_PRIx "+%016" VADDR_PRIx ")\n",
|
||||
"%" VADDR_PRIx "/%" VADDR_PRIx "+%" VADDR_PRIx ")\n",
|
||||
midx, addr, mask, len);
|
||||
tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime());
|
||||
return;
|
||||
@@ -741,7 +741,7 @@ static void tlb_flush_range_locked(CPUArchState *env, int midx,
|
||||
*/
|
||||
if (((addr + len - 1) & d->large_page_mask) == d->large_page_addr) {
|
||||
tlb_debug("forcing full flush midx %d ("
|
||||
"%016" VADDR_PRIx "/%016" VADDR_PRIx ")\n",
|
||||
"%" VADDR_PRIx "/%" VADDR_PRIx ")\n",
|
||||
midx, d->large_page_addr, d->large_page_mask);
|
||||
tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime());
|
||||
return;
|
||||
@@ -773,7 +773,7 @@ static void tlb_flush_range_by_mmuidx_async_0(CPUState *cpu,
|
||||
|
||||
assert_cpu_is_self(cpu);
|
||||
|
||||
tlb_debug("range: %016" VADDR_PRIx "/%u+%016" VADDR_PRIx " mmu_map:0x%x\n",
|
||||
tlb_debug("range: %" VADDR_PRIx "/%u+%" VADDR_PRIx " mmu_map:0x%x\n",
|
||||
d.addr, d.bits, d.len, d.idxmap);
|
||||
|
||||
qemu_spin_lock(&env_tlb(env)->c.lock);
|
||||
@@ -1165,7 +1165,7 @@ void tlb_set_page_full(CPUState *cpu, int mmu_idx,
|
||||
&xlat, &sz, full->attrs, &prot);
|
||||
assert(sz >= TARGET_PAGE_SIZE);
|
||||
|
||||
tlb_debug("vaddr=%016" VADDR_PRIx " paddr=0x" HWADDR_FMT_plx
|
||||
tlb_debug("vaddr=%" VADDR_PRIx " paddr=0x" HWADDR_FMT_plx
|
||||
" prot=%x idx=%d\n",
|
||||
addr, full->phys_addr, prot, mmu_idx);
|
||||
|
||||
@@ -1363,21 +1363,6 @@ static inline void cpu_transaction_failed(CPUState *cpu, hwaddr physaddr,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Save a potentially trashed CPUTLBEntryFull for later lookup by plugin.
|
||||
* This is read by tlb_plugin_lookup if the fulltlb entry doesn't match
|
||||
* because of the side effect of io_writex changing memory layout.
|
||||
*/
|
||||
static void save_iotlb_data(CPUState *cs, MemoryRegionSection *section,
|
||||
hwaddr mr_offset)
|
||||
{
|
||||
#ifdef CONFIG_PLUGIN
|
||||
SavedIOTLB *saved = &cs->saved_iotlb;
|
||||
saved->section = section;
|
||||
saved->mr_offset = mr_offset;
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint64_t io_readx(CPUArchState *env, CPUTLBEntryFull *full,
|
||||
int mmu_idx, vaddr addr, uintptr_t retaddr,
|
||||
MMUAccessType access_type, MemOp op)
|
||||
@@ -1397,12 +1382,6 @@ static uint64_t io_readx(CPUArchState *env, CPUTLBEntryFull *full,
|
||||
cpu_io_recompile(cpu, retaddr);
|
||||
}
|
||||
|
||||
/*
|
||||
* The memory_region_dispatch may trigger a flush/resize
|
||||
* so for plugins we save the iotlb_data just in case.
|
||||
*/
|
||||
save_iotlb_data(cpu, section, mr_offset);
|
||||
|
||||
{
|
||||
QEMU_IOTHREAD_LOCK_GUARD();
|
||||
r = memory_region_dispatch_read(mr, mr_offset, &val, op, full->attrs);
|
||||
@@ -1419,6 +1398,21 @@ static uint64_t io_readx(CPUArchState *env, CPUTLBEntryFull *full,
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save a potentially trashed CPUTLBEntryFull for later lookup by plugin.
|
||||
* This is read by tlb_plugin_lookup if the fulltlb entry doesn't match
|
||||
* because of the side effect of io_writex changing memory layout.
|
||||
*/
|
||||
static void save_iotlb_data(CPUState *cs, MemoryRegionSection *section,
|
||||
hwaddr mr_offset)
|
||||
{
|
||||
#ifdef CONFIG_PLUGIN
|
||||
SavedIOTLB *saved = &cs->saved_iotlb;
|
||||
saved->section = section;
|
||||
saved->mr_offset = mr_offset;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void io_writex(CPUArchState *env, CPUTLBEntryFull *full,
|
||||
int mmu_idx, uint64_t val, vaddr addr,
|
||||
uintptr_t retaddr, MemOp op)
|
||||
@@ -1519,14 +1513,13 @@ static int probe_access_internal(CPUArchState *env, vaddr addr,
|
||||
int fault_size, MMUAccessType access_type,
|
||||
int mmu_idx, bool nonfault,
|
||||
void **phost, CPUTLBEntryFull **pfull,
|
||||
uintptr_t retaddr, bool check_mem_cbs)
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
uintptr_t index = tlb_index(env, mmu_idx, addr);
|
||||
CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr);
|
||||
uint64_t tlb_addr = tlb_read_idx(entry, access_type);
|
||||
vaddr page_addr = addr & TARGET_PAGE_MASK;
|
||||
int flags = TLB_FLAGS_MASK & ~TLB_FORCE_SLOW;
|
||||
bool force_mmio = check_mem_cbs && cpu_plugin_mem_cbs_enabled(env_cpu(env));
|
||||
CPUTLBEntryFull *full;
|
||||
|
||||
if (!tlb_hit_page(tlb_addr, page_addr)) {
|
||||
@@ -1560,9 +1553,7 @@ static int probe_access_internal(CPUArchState *env, vaddr addr,
|
||||
flags |= full->slow_flags[access_type];
|
||||
|
||||
/* Fold all "mmio-like" bits into TLB_MMIO. This is not RAM. */
|
||||
if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY))
|
||||
||
|
||||
(access_type != MMU_INST_FETCH && force_mmio)) {
|
||||
if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY))) {
|
||||
*phost = NULL;
|
||||
return TLB_MMIO;
|
||||
}
|
||||
@@ -1578,7 +1569,7 @@ int probe_access_full(CPUArchState *env, vaddr addr, int size,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
int flags = probe_access_internal(env, addr, size, access_type, mmu_idx,
|
||||
nonfault, phost, pfull, retaddr, true);
|
||||
nonfault, phost, pfull, retaddr);
|
||||
|
||||
/* Handle clean RAM pages. */
|
||||
if (unlikely(flags & TLB_NOTDIRTY)) {
|
||||
@@ -1589,29 +1580,6 @@ int probe_access_full(CPUArchState *env, vaddr addr, int size,
|
||||
return flags;
|
||||
}
|
||||
|
||||
int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
void **phost, CPUTLBEntryFull **pfull)
|
||||
{
|
||||
void *discard_phost;
|
||||
CPUTLBEntryFull *discard_tlb;
|
||||
|
||||
/* privately handle users that don't need full results */
|
||||
phost = phost ? phost : &discard_phost;
|
||||
pfull = pfull ? pfull : &discard_tlb;
|
||||
|
||||
int flags = probe_access_internal(env, addr, size, access_type, mmu_idx,
|
||||
true, phost, pfull, 0, false);
|
||||
|
||||
/* Handle clean RAM pages. */
|
||||
if (unlikely(flags & TLB_NOTDIRTY)) {
|
||||
notdirty_write(env_cpu(env), addr, 1, *pfull, 0);
|
||||
flags &= ~TLB_NOTDIRTY;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
int probe_access_flags(CPUArchState *env, vaddr addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool nonfault, void **phost, uintptr_t retaddr)
|
||||
@@ -1622,7 +1590,7 @@ int probe_access_flags(CPUArchState *env, vaddr addr, int size,
|
||||
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
|
||||
|
||||
flags = probe_access_internal(env, addr, size, access_type, mmu_idx,
|
||||
nonfault, phost, &full, retaddr, true);
|
||||
nonfault, phost, &full, retaddr);
|
||||
|
||||
/* Handle clean RAM pages. */
|
||||
if (unlikely(flags & TLB_NOTDIRTY)) {
|
||||
@@ -1643,7 +1611,7 @@ void *probe_access(CPUArchState *env, vaddr addr, int size,
|
||||
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
|
||||
|
||||
flags = probe_access_internal(env, addr, size, access_type, mmu_idx,
|
||||
false, &host, &full, retaddr, true);
|
||||
false, &host, &full, retaddr);
|
||||
|
||||
/* Per the interface, size == 0 merely faults the access. */
|
||||
if (size == 0) {
|
||||
@@ -1676,7 +1644,7 @@ void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr,
|
||||
int flags;
|
||||
|
||||
flags = probe_access_internal(env, addr, 0, access_type,
|
||||
mmu_idx, true, &host, &full, 0, false);
|
||||
mmu_idx, true, &host, &full, 0);
|
||||
|
||||
/* No combination of flags are expected by the caller. */
|
||||
return flags ? NULL : host;
|
||||
@@ -1699,8 +1667,7 @@ tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr,
|
||||
void *p;
|
||||
|
||||
(void)probe_access_internal(env, addr, 1, MMU_INST_FETCH,
|
||||
cpu_mmu_index(env, true), false,
|
||||
&p, &full, 0, false);
|
||||
cpu_mmu_index(env, true), false, &p, &full, 0);
|
||||
if (p == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -2072,55 +2039,27 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi,
|
||||
/**
|
||||
* do_ld_mmio_beN:
|
||||
* @env: cpu context
|
||||
* @full: page parameters
|
||||
* @p: translation parameters
|
||||
* @ret_be: accumulated data
|
||||
* @addr: virtual address
|
||||
* @size: number of bytes
|
||||
* @mmu_idx: virtual address context
|
||||
* @ra: return address into tcg generated code, or 0
|
||||
* Context: iothread lock held
|
||||
*
|
||||
* Load @size bytes from @addr, which is memory-mapped i/o.
|
||||
* Load @p->size bytes from @p->addr, which is memory-mapped i/o.
|
||||
* The bytes are concatenated in big-endian order with @ret_be.
|
||||
*/
|
||||
static uint64_t do_ld_mmio_beN(CPUArchState *env, CPUTLBEntryFull *full,
|
||||
uint64_t ret_be, vaddr addr, int size,
|
||||
int mmu_idx, MMUAccessType type, uintptr_t ra)
|
||||
static uint64_t do_ld_mmio_beN(CPUArchState *env, MMULookupPageData *p,
|
||||
uint64_t ret_be, int mmu_idx,
|
||||
MMUAccessType type, uintptr_t ra)
|
||||
{
|
||||
uint64_t t;
|
||||
CPUTLBEntryFull *full = p->full;
|
||||
vaddr addr = p->addr;
|
||||
int i, size = p->size;
|
||||
|
||||
tcg_debug_assert(size > 0 && size <= 8);
|
||||
do {
|
||||
/* Read aligned pieces up to 8 bytes. */
|
||||
switch ((size | (int)addr) & 7) {
|
||||
case 1:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
t = io_readx(env, full, mmu_idx, addr, ra, type, MO_UB);
|
||||
ret_be = (ret_be << 8) | t;
|
||||
size -= 1;
|
||||
addr += 1;
|
||||
break;
|
||||
case 2:
|
||||
case 6:
|
||||
t = io_readx(env, full, mmu_idx, addr, ra, type, MO_BEUW);
|
||||
ret_be = (ret_be << 16) | t;
|
||||
size -= 2;
|
||||
addr += 2;
|
||||
break;
|
||||
case 4:
|
||||
t = io_readx(env, full, mmu_idx, addr, ra, type, MO_BEUL);
|
||||
ret_be = (ret_be << 32) | t;
|
||||
size -= 4;
|
||||
addr += 4;
|
||||
break;
|
||||
case 0:
|
||||
return io_readx(env, full, mmu_idx, addr, ra, type, MO_BEUQ);
|
||||
default:
|
||||
qemu_build_not_reached();
|
||||
}
|
||||
} while (size);
|
||||
QEMU_IOTHREAD_LOCK_GUARD();
|
||||
for (i = 0; i < size; i++) {
|
||||
uint8_t x = io_readx(env, full, mmu_idx, addr + i, ra, type, MO_UB);
|
||||
ret_be = (ret_be << 8) | x;
|
||||
}
|
||||
return ret_be;
|
||||
}
|
||||
|
||||
@@ -2266,9 +2205,7 @@ static uint64_t do_ld_beN(CPUArchState *env, MMULookupPageData *p,
|
||||
unsigned tmp, half_size;
|
||||
|
||||
if (unlikely(p->flags & TLB_MMIO)) {
|
||||
QEMU_IOTHREAD_LOCK_GUARD();
|
||||
return do_ld_mmio_beN(env, p->full, ret_be, p->addr, p->size,
|
||||
mmu_idx, type, ra);
|
||||
return do_ld_mmio_beN(env, p, ret_be, mmu_idx, type, ra);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2317,11 +2254,11 @@ static Int128 do_ld16_beN(CPUArchState *env, MMULookupPageData *p,
|
||||
MemOp atom;
|
||||
|
||||
if (unlikely(p->flags & TLB_MMIO)) {
|
||||
QEMU_IOTHREAD_LOCK_GUARD();
|
||||
a = do_ld_mmio_beN(env, p->full, a, p->addr, size - 8,
|
||||
mmu_idx, MMU_DATA_LOAD, ra);
|
||||
b = do_ld_mmio_beN(env, p->full, 0, p->addr + 8, 8,
|
||||
mmu_idx, MMU_DATA_LOAD, ra);
|
||||
p->size = size - 8;
|
||||
a = do_ld_mmio_beN(env, p, a, mmu_idx, MMU_DATA_LOAD, ra);
|
||||
p->addr += p->size;
|
||||
p->size = 8;
|
||||
b = do_ld_mmio_beN(env, p, 0, mmu_idx, MMU_DATA_LOAD, ra);
|
||||
return int128_make128(b, a);
|
||||
}
|
||||
|
||||
@@ -2376,20 +2313,16 @@ static uint8_t do_ld_1(CPUArchState *env, MMULookupPageData *p, int mmu_idx,
|
||||
static uint16_t do_ld_2(CPUArchState *env, MMULookupPageData *p, int mmu_idx,
|
||||
MMUAccessType type, MemOp memop, uintptr_t ra)
|
||||
{
|
||||
uint16_t ret;
|
||||
uint64_t ret;
|
||||
|
||||
if (unlikely(p->flags & TLB_MMIO)) {
|
||||
QEMU_IOTHREAD_LOCK_GUARD();
|
||||
ret = do_ld_mmio_beN(env, p->full, 0, p->addr, 2, mmu_idx, type, ra);
|
||||
if ((memop & MO_BSWAP) == MO_LE) {
|
||||
ret = bswap16(ret);
|
||||
}
|
||||
} else {
|
||||
/* Perform the load host endian, then swap if necessary. */
|
||||
ret = load_atom_2(env, ra, p->haddr, memop);
|
||||
if (memop & MO_BSWAP) {
|
||||
ret = bswap16(ret);
|
||||
}
|
||||
return io_readx(env, p->full, mmu_idx, p->addr, ra, type, memop);
|
||||
}
|
||||
|
||||
/* Perform the load host endian, then swap if necessary. */
|
||||
ret = load_atom_2(env, ra, p->haddr, memop);
|
||||
if (memop & MO_BSWAP) {
|
||||
ret = bswap16(ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -2400,17 +2333,13 @@ static uint32_t do_ld_4(CPUArchState *env, MMULookupPageData *p, int mmu_idx,
|
||||
uint32_t ret;
|
||||
|
||||
if (unlikely(p->flags & TLB_MMIO)) {
|
||||
QEMU_IOTHREAD_LOCK_GUARD();
|
||||
ret = do_ld_mmio_beN(env, p->full, 0, p->addr, 4, mmu_idx, type, ra);
|
||||
if ((memop & MO_BSWAP) == MO_LE) {
|
||||
ret = bswap32(ret);
|
||||
}
|
||||
} else {
|
||||
/* Perform the load host endian. */
|
||||
ret = load_atom_4(env, ra, p->haddr, memop);
|
||||
if (memop & MO_BSWAP) {
|
||||
ret = bswap32(ret);
|
||||
}
|
||||
return io_readx(env, p->full, mmu_idx, p->addr, ra, type, memop);
|
||||
}
|
||||
|
||||
/* Perform the load host endian. */
|
||||
ret = load_atom_4(env, ra, p->haddr, memop);
|
||||
if (memop & MO_BSWAP) {
|
||||
ret = bswap32(ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -2421,17 +2350,13 @@ static uint64_t do_ld_8(CPUArchState *env, MMULookupPageData *p, int mmu_idx,
|
||||
uint64_t ret;
|
||||
|
||||
if (unlikely(p->flags & TLB_MMIO)) {
|
||||
QEMU_IOTHREAD_LOCK_GUARD();
|
||||
ret = do_ld_mmio_beN(env, p->full, 0, p->addr, 8, mmu_idx, type, ra);
|
||||
if ((memop & MO_BSWAP) == MO_LE) {
|
||||
ret = bswap64(ret);
|
||||
}
|
||||
} else {
|
||||
/* Perform the load host endian. */
|
||||
ret = load_atom_8(env, ra, p->haddr, memop);
|
||||
if (memop & MO_BSWAP) {
|
||||
ret = bswap64(ret);
|
||||
}
|
||||
return io_readx(env, p->full, mmu_idx, p->addr, ra, type, memop);
|
||||
}
|
||||
|
||||
/* Perform the load host endian. */
|
||||
ret = load_atom_8(env, ra, p->haddr, memop);
|
||||
if (memop & MO_BSWAP) {
|
||||
ret = bswap64(ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -2579,22 +2504,20 @@ static Int128 do_ld16_mmu(CPUArchState *env, vaddr addr,
|
||||
cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
|
||||
crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD, &l);
|
||||
if (likely(!crosspage)) {
|
||||
/* Perform the load host endian. */
|
||||
if (unlikely(l.page[0].flags & TLB_MMIO)) {
|
||||
QEMU_IOTHREAD_LOCK_GUARD();
|
||||
a = do_ld_mmio_beN(env, l.page[0].full, 0, addr, 8,
|
||||
l.mmu_idx, MMU_DATA_LOAD, ra);
|
||||
b = do_ld_mmio_beN(env, l.page[0].full, 0, addr + 8, 8,
|
||||
l.mmu_idx, MMU_DATA_LOAD, ra);
|
||||
ret = int128_make128(b, a);
|
||||
if ((l.memop & MO_BSWAP) == MO_LE) {
|
||||
ret = bswap128(ret);
|
||||
}
|
||||
a = io_readx(env, l.page[0].full, l.mmu_idx, addr,
|
||||
ra, MMU_DATA_LOAD, MO_64);
|
||||
b = io_readx(env, l.page[0].full, l.mmu_idx, addr + 8,
|
||||
ra, MMU_DATA_LOAD, MO_64);
|
||||
ret = int128_make128(HOST_BIG_ENDIAN ? b : a,
|
||||
HOST_BIG_ENDIAN ? a : b);
|
||||
} else {
|
||||
/* Perform the load host endian. */
|
||||
ret = load_atom_16(env, ra, l.page[0].haddr, l.memop);
|
||||
if (l.memop & MO_BSWAP) {
|
||||
ret = bswap128(ret);
|
||||
}
|
||||
}
|
||||
if (l.memop & MO_BSWAP) {
|
||||
ret = bswap128(ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -2714,57 +2637,26 @@ Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr,
|
||||
/**
|
||||
* do_st_mmio_leN:
|
||||
* @env: cpu context
|
||||
* @full: page parameters
|
||||
* @p: translation parameters
|
||||
* @val_le: data to store
|
||||
* @addr: virtual address
|
||||
* @size: number of bytes
|
||||
* @mmu_idx: virtual address context
|
||||
* @ra: return address into tcg generated code, or 0
|
||||
* Context: iothread lock held
|
||||
*
|
||||
* Store @size bytes at @addr, which is memory-mapped i/o.
|
||||
* Store @p->size bytes at @p->addr, which is memory-mapped i/o.
|
||||
* The bytes to store are extracted in little-endian order from @val_le;
|
||||
* return the bytes of @val_le beyond @p->size that have not been stored.
|
||||
*/
|
||||
static uint64_t do_st_mmio_leN(CPUArchState *env, CPUTLBEntryFull *full,
|
||||
uint64_t val_le, vaddr addr, int size,
|
||||
int mmu_idx, uintptr_t ra)
|
||||
static uint64_t do_st_mmio_leN(CPUArchState *env, MMULookupPageData *p,
|
||||
uint64_t val_le, int mmu_idx, uintptr_t ra)
|
||||
{
|
||||
tcg_debug_assert(size > 0 && size <= 8);
|
||||
|
||||
do {
|
||||
/* Store aligned pieces up to 8 bytes. */
|
||||
switch ((size | (int)addr) & 7) {
|
||||
case 1:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
io_writex(env, full, mmu_idx, val_le, addr, ra, MO_UB);
|
||||
val_le >>= 8;
|
||||
size -= 1;
|
||||
addr += 1;
|
||||
break;
|
||||
case 2:
|
||||
case 6:
|
||||
io_writex(env, full, mmu_idx, val_le, addr, ra, MO_LEUW);
|
||||
val_le >>= 16;
|
||||
size -= 2;
|
||||
addr += 2;
|
||||
break;
|
||||
case 4:
|
||||
io_writex(env, full, mmu_idx, val_le, addr, ra, MO_LEUL);
|
||||
val_le >>= 32;
|
||||
size -= 4;
|
||||
addr += 4;
|
||||
break;
|
||||
case 0:
|
||||
io_writex(env, full, mmu_idx, val_le, addr, ra, MO_LEUQ);
|
||||
return 0;
|
||||
default:
|
||||
qemu_build_not_reached();
|
||||
}
|
||||
} while (size);
|
||||
CPUTLBEntryFull *full = p->full;
|
||||
vaddr addr = p->addr;
|
||||
int i, size = p->size;
|
||||
|
||||
QEMU_IOTHREAD_LOCK_GUARD();
|
||||
for (i = 0; i < size; i++, val_le >>= 8) {
|
||||
io_writex(env, full, mmu_idx, val_le, addr + i, ra, MO_UB);
|
||||
}
|
||||
return val_le;
|
||||
}
|
||||
|
||||
@@ -2779,9 +2671,7 @@ static uint64_t do_st_leN(CPUArchState *env, MMULookupPageData *p,
|
||||
unsigned tmp, half_size;
|
||||
|
||||
if (unlikely(p->flags & TLB_MMIO)) {
|
||||
QEMU_IOTHREAD_LOCK_GUARD();
|
||||
return do_st_mmio_leN(env, p->full, val_le, p->addr,
|
||||
p->size, mmu_idx, ra);
|
||||
return do_st_mmio_leN(env, p, val_le, mmu_idx, ra);
|
||||
} else if (unlikely(p->flags & TLB_DISCARD_WRITE)) {
|
||||
return val_le >> (p->size * 8);
|
||||
}
|
||||
@@ -2834,11 +2724,11 @@ static uint64_t do_st16_leN(CPUArchState *env, MMULookupPageData *p,
|
||||
MemOp atom;
|
||||
|
||||
if (unlikely(p->flags & TLB_MMIO)) {
|
||||
QEMU_IOTHREAD_LOCK_GUARD();
|
||||
do_st_mmio_leN(env, p->full, int128_getlo(val_le),
|
||||
p->addr, 8, mmu_idx, ra);
|
||||
return do_st_mmio_leN(env, p->full, int128_gethi(val_le),
|
||||
p->addr + 8, size - 8, mmu_idx, ra);
|
||||
p->size = 8;
|
||||
do_st_mmio_leN(env, p, int128_getlo(val_le), mmu_idx, ra);
|
||||
p->size = size - 8;
|
||||
p->addr += 8;
|
||||
return do_st_mmio_leN(env, p, int128_gethi(val_le), mmu_idx, ra);
|
||||
} else if (unlikely(p->flags & TLB_DISCARD_WRITE)) {
|
||||
return int128_gethi(val_le) >> ((size - 8) * 8);
|
||||
}
|
||||
@@ -2894,11 +2784,7 @@ static void do_st_2(CPUArchState *env, MMULookupPageData *p, uint16_t val,
|
||||
int mmu_idx, MemOp memop, uintptr_t ra)
|
||||
{
|
||||
if (unlikely(p->flags & TLB_MMIO)) {
|
||||
if ((memop & MO_BSWAP) != MO_LE) {
|
||||
val = bswap16(val);
|
||||
}
|
||||
QEMU_IOTHREAD_LOCK_GUARD();
|
||||
do_st_mmio_leN(env, p->full, val, p->addr, 2, mmu_idx, ra);
|
||||
io_writex(env, p->full, mmu_idx, val, p->addr, ra, memop);
|
||||
} else if (unlikely(p->flags & TLB_DISCARD_WRITE)) {
|
||||
/* nothing */
|
||||
} else {
|
||||
@@ -2914,11 +2800,7 @@ static void do_st_4(CPUArchState *env, MMULookupPageData *p, uint32_t val,
|
||||
int mmu_idx, MemOp memop, uintptr_t ra)
|
||||
{
|
||||
if (unlikely(p->flags & TLB_MMIO)) {
|
||||
if ((memop & MO_BSWAP) != MO_LE) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
QEMU_IOTHREAD_LOCK_GUARD();
|
||||
do_st_mmio_leN(env, p->full, val, p->addr, 4, mmu_idx, ra);
|
||||
io_writex(env, p->full, mmu_idx, val, p->addr, ra, memop);
|
||||
} else if (unlikely(p->flags & TLB_DISCARD_WRITE)) {
|
||||
/* nothing */
|
||||
} else {
|
||||
@@ -2934,11 +2816,7 @@ static void do_st_8(CPUArchState *env, MMULookupPageData *p, uint64_t val,
|
||||
int mmu_idx, MemOp memop, uintptr_t ra)
|
||||
{
|
||||
if (unlikely(p->flags & TLB_MMIO)) {
|
||||
if ((memop & MO_BSWAP) != MO_LE) {
|
||||
val = bswap64(val);
|
||||
}
|
||||
QEMU_IOTHREAD_LOCK_GUARD();
|
||||
do_st_mmio_leN(env, p->full, val, p->addr, 8, mmu_idx, ra);
|
||||
io_writex(env, p->full, mmu_idx, val, p->addr, ra, memop);
|
||||
} else if (unlikely(p->flags & TLB_DISCARD_WRITE)) {
|
||||
/* nothing */
|
||||
} else {
|
||||
@@ -3061,22 +2939,22 @@ static void do_st16_mmu(CPUArchState *env, vaddr addr, Int128 val,
|
||||
cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
|
||||
crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l);
|
||||
if (likely(!crosspage)) {
|
||||
/* Swap to host endian if necessary, then store. */
|
||||
if (l.memop & MO_BSWAP) {
|
||||
val = bswap128(val);
|
||||
}
|
||||
if (unlikely(l.page[0].flags & TLB_MMIO)) {
|
||||
if ((l.memop & MO_BSWAP) != MO_LE) {
|
||||
val = bswap128(val);
|
||||
}
|
||||
a = int128_getlo(val);
|
||||
b = int128_gethi(val);
|
||||
QEMU_IOTHREAD_LOCK_GUARD();
|
||||
do_st_mmio_leN(env, l.page[0].full, a, addr, 8, l.mmu_idx, ra);
|
||||
do_st_mmio_leN(env, l.page[0].full, b, addr + 8, 8, l.mmu_idx, ra);
|
||||
if (HOST_BIG_ENDIAN) {
|
||||
b = int128_getlo(val), a = int128_gethi(val);
|
||||
} else {
|
||||
a = int128_getlo(val), b = int128_gethi(val);
|
||||
}
|
||||
io_writex(env, l.page[0].full, l.mmu_idx, a, addr, ra, MO_64);
|
||||
io_writex(env, l.page[0].full, l.mmu_idx, b, addr + 8, ra, MO_64);
|
||||
} else if (unlikely(l.page[0].flags & TLB_DISCARD_WRITE)) {
|
||||
/* nothing */
|
||||
} else {
|
||||
/* Swap to host endian if necessary, then store. */
|
||||
if (l.memop & MO_BSWAP) {
|
||||
val = bswap128(val);
|
||||
}
|
||||
store_atom_16(env, ra, l.page[0].haddr, l.memop, val);
|
||||
}
|
||||
return;
|
||||
@@ -3200,7 +3078,7 @@ void cpu_st16_mmu(CPUArchState *env, target_ulong addr, Int128 val,
|
||||
#include "atomic_template.h"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ATOMIC128) || HAVE_CMPXCHG128
|
||||
#if defined(CONFIG_ATOMIC128) || defined(CONFIG_CMPXCHG128)
|
||||
#define DATA_SIZE 16
|
||||
#include "atomic_template.h"
|
||||
#endif
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#define ACCEL_TCG_INTERNAL_H
|
||||
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/translate-all.h"
|
||||
|
||||
/*
|
||||
* Access to the various translations structures need to be serialised
|
||||
@@ -36,32 +35,6 @@ static inline void page_table_config_init(void) { }
|
||||
void page_table_config_init(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/*
|
||||
* For user-only, page_protect sets the page read-only.
|
||||
* Since most execution is already on read-only pages, and we'd need to
|
||||
* account for other TBs on the same page, defer undoing any page protection
|
||||
* until we receive the write fault.
|
||||
*/
|
||||
static inline void tb_lock_page0(tb_page_addr_t p0)
|
||||
{
|
||||
page_protect(p0);
|
||||
}
|
||||
|
||||
static inline void tb_lock_page1(tb_page_addr_t p0, tb_page_addr_t p1)
|
||||
{
|
||||
page_protect(p1);
|
||||
}
|
||||
|
||||
static inline void tb_unlock_page1(tb_page_addr_t p0, tb_page_addr_t p1) { }
|
||||
static inline void tb_unlock_pages(TranslationBlock *tb) { }
|
||||
#else
|
||||
void tb_lock_page0(tb_page_addr_t);
|
||||
void tb_lock_page1(tb_page_addr_t, tb_page_addr_t);
|
||||
void tb_unlock_page1(tb_page_addr_t, tb_page_addr_t);
|
||||
void tb_unlock_pages(TranslationBlock *);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
void tb_invalidate_phys_range_fast(ram_addr_t ram_addr,
|
||||
unsigned size,
|
||||
@@ -75,7 +48,8 @@ TranslationBlock *tb_gen_code(CPUState *cpu, vaddr pc,
|
||||
void page_init(void);
|
||||
void tb_htable_init(void);
|
||||
void tb_reset_jump(TranslationBlock *tb, int n);
|
||||
TranslationBlock *tb_link_page(TranslationBlock *tb);
|
||||
TranslationBlock *tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
|
||||
tb_page_addr_t phys_page2);
|
||||
bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc);
|
||||
void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
uintptr_t host_pc);
|
||||
|
||||
@@ -159,11 +159,9 @@ static uint64_t load_atomic8_or_exit(CPUArchState *env, uintptr_t ra, void *pv)
|
||||
* another process, because the fallback start_exclusive solution
|
||||
* provides no protection across processes.
|
||||
*/
|
||||
WITH_MMAP_LOCK_GUARD() {
|
||||
if (!page_check_range(h2g(pv), 8, PAGE_WRITE_ORG)) {
|
||||
uint64_t *p = __builtin_assume_aligned(pv, 8);
|
||||
return *p;
|
||||
}
|
||||
if (!page_check_range(h2g(pv), 8, PAGE_WRITE_ORG)) {
|
||||
uint64_t *p = __builtin_assume_aligned(pv, 8);
|
||||
return *p;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -188,27 +186,25 @@ static Int128 load_atomic16_or_exit(CPUArchState *env, uintptr_t ra, void *pv)
|
||||
return atomic16_read_ro(p);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/*
|
||||
* We can only use cmpxchg to emulate a load if the page is writable.
|
||||
* If the page is not writable, then assume the value is immutable
|
||||
* and requires no locking. This ignores the case of MAP_SHARED with
|
||||
* another process, because the fallback start_exclusive solution
|
||||
* provides no protection across processes.
|
||||
*
|
||||
* In system mode all guest pages are writable. For user mode,
|
||||
* we must take mmap_lock so that the query remains valid until
|
||||
* the write is complete -- tests/tcg/multiarch/munmap-pthread.c
|
||||
* is an example that can race.
|
||||
*/
|
||||
WITH_MMAP_LOCK_GUARD() {
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
if (!page_check_range(h2g(p), 16, PAGE_WRITE_ORG)) {
|
||||
return *p;
|
||||
}
|
||||
if (!page_check_range(h2g(p), 16, PAGE_WRITE_ORG)) {
|
||||
return *p;
|
||||
}
|
||||
#endif
|
||||
if (HAVE_ATOMIC128_RW) {
|
||||
return atomic16_read_rw(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* In system mode all guest pages are writable, and for user-only
|
||||
* we have just checked writability. Try cmpxchg.
|
||||
*/
|
||||
if (HAVE_ATOMIC128_RW) {
|
||||
return atomic16_read_rw(p);
|
||||
}
|
||||
|
||||
/* Ultimate fallback: re-execute in serial context. */
|
||||
@@ -404,10 +400,7 @@ static uint16_t load_atom_2(CPUArchState *env, uintptr_t ra,
|
||||
return load_atomic2(pv);
|
||||
}
|
||||
if (HAVE_ATOMIC128_RO) {
|
||||
intptr_t left_in_page = -(pi | TARGET_PAGE_MASK);
|
||||
if (likely(left_in_page > 8)) {
|
||||
return load_atom_extract_al16_or_al8(pv, 2);
|
||||
}
|
||||
return load_atom_extract_al16_or_al8(pv, 2);
|
||||
}
|
||||
|
||||
atmax = required_atomicity(env, pi, memop);
|
||||
@@ -446,10 +439,7 @@ static uint32_t load_atom_4(CPUArchState *env, uintptr_t ra,
|
||||
return load_atomic4(pv);
|
||||
}
|
||||
if (HAVE_ATOMIC128_RO) {
|
||||
intptr_t left_in_page = -(pi | TARGET_PAGE_MASK);
|
||||
if (likely(left_in_page > 8)) {
|
||||
return load_atom_extract_al16_or_al8(pv, 4);
|
||||
}
|
||||
return load_atom_extract_al16_or_al8(pv, 4);
|
||||
}
|
||||
|
||||
atmax = required_atomicity(env, pi, memop);
|
||||
|
||||
@@ -70,7 +70,17 @@ typedef struct PageDesc PageDesc;
|
||||
*/
|
||||
#define assert_page_locked(pd) tcg_debug_assert(have_mmap_lock())
|
||||
|
||||
static inline void tb_lock_pages(const TranslationBlock *tb) { }
|
||||
static inline void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1,
|
||||
PageDesc **ret_p2, tb_page_addr_t phys2,
|
||||
bool alloc)
|
||||
{
|
||||
*ret_p1 = NULL;
|
||||
*ret_p2 = NULL;
|
||||
}
|
||||
|
||||
static inline void page_unlock(PageDesc *pd) { }
|
||||
static inline void page_lock_tb(const TranslationBlock *tb) { }
|
||||
static inline void page_unlock_tb(const TranslationBlock *tb) { }
|
||||
|
||||
/*
|
||||
* For user-only, since we are protecting all of memory with a single lock,
|
||||
@@ -86,7 +96,7 @@ static void tb_remove_all(void)
|
||||
}
|
||||
|
||||
/* Call with mmap_lock held. */
|
||||
static void tb_record(TranslationBlock *tb)
|
||||
static void tb_record(TranslationBlock *tb, PageDesc *p1, PageDesc *p2)
|
||||
{
|
||||
vaddr addr;
|
||||
int flags;
|
||||
@@ -381,108 +391,12 @@ static void page_lock(PageDesc *pd)
|
||||
qemu_spin_lock(&pd->lock);
|
||||
}
|
||||
|
||||
/* Like qemu_spin_trylock, returns false on success */
|
||||
static bool page_trylock(PageDesc *pd)
|
||||
{
|
||||
bool busy = qemu_spin_trylock(&pd->lock);
|
||||
if (!busy) {
|
||||
page_lock__debug(pd);
|
||||
}
|
||||
return busy;
|
||||
}
|
||||
|
||||
static void page_unlock(PageDesc *pd)
|
||||
{
|
||||
qemu_spin_unlock(&pd->lock);
|
||||
page_unlock__debug(pd);
|
||||
}
|
||||
|
||||
void tb_lock_page0(tb_page_addr_t paddr)
|
||||
{
|
||||
page_lock(page_find_alloc(paddr >> TARGET_PAGE_BITS, true));
|
||||
}
|
||||
|
||||
void tb_lock_page1(tb_page_addr_t paddr0, tb_page_addr_t paddr1)
|
||||
{
|
||||
tb_page_addr_t pindex0 = paddr0 >> TARGET_PAGE_BITS;
|
||||
tb_page_addr_t pindex1 = paddr1 >> TARGET_PAGE_BITS;
|
||||
PageDesc *pd0, *pd1;
|
||||
|
||||
if (pindex0 == pindex1) {
|
||||
/* Identical pages, and the first page is already locked. */
|
||||
return;
|
||||
}
|
||||
|
||||
pd1 = page_find_alloc(pindex1, true);
|
||||
if (pindex0 < pindex1) {
|
||||
/* Correct locking order, we may block. */
|
||||
page_lock(pd1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Incorrect locking order, we cannot block lest we deadlock. */
|
||||
if (!page_trylock(pd1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Drop the lock on page0 and get both page locks in the right order.
|
||||
* Restart translation via longjmp.
|
||||
*/
|
||||
pd0 = page_find_alloc(pindex0, false);
|
||||
page_unlock(pd0);
|
||||
page_lock(pd1);
|
||||
page_lock(pd0);
|
||||
siglongjmp(tcg_ctx->jmp_trans, -3);
|
||||
}
|
||||
|
||||
void tb_unlock_page1(tb_page_addr_t paddr0, tb_page_addr_t paddr1)
|
||||
{
|
||||
tb_page_addr_t pindex0 = paddr0 >> TARGET_PAGE_BITS;
|
||||
tb_page_addr_t pindex1 = paddr1 >> TARGET_PAGE_BITS;
|
||||
|
||||
if (pindex0 != pindex1) {
|
||||
page_unlock(page_find_alloc(pindex1, false));
|
||||
}
|
||||
}
|
||||
|
||||
static void tb_lock_pages(TranslationBlock *tb)
|
||||
{
|
||||
tb_page_addr_t paddr0 = tb_page_addr0(tb);
|
||||
tb_page_addr_t paddr1 = tb_page_addr1(tb);
|
||||
tb_page_addr_t pindex0 = paddr0 >> TARGET_PAGE_BITS;
|
||||
tb_page_addr_t pindex1 = paddr1 >> TARGET_PAGE_BITS;
|
||||
|
||||
if (unlikely(paddr0 == -1)) {
|
||||
return;
|
||||
}
|
||||
if (unlikely(paddr1 != -1) && pindex0 != pindex1) {
|
||||
if (pindex0 < pindex1) {
|
||||
page_lock(page_find_alloc(pindex0, true));
|
||||
page_lock(page_find_alloc(pindex1, true));
|
||||
return;
|
||||
}
|
||||
page_lock(page_find_alloc(pindex1, true));
|
||||
}
|
||||
page_lock(page_find_alloc(pindex0, true));
|
||||
}
|
||||
|
||||
void tb_unlock_pages(TranslationBlock *tb)
|
||||
{
|
||||
tb_page_addr_t paddr0 = tb_page_addr0(tb);
|
||||
tb_page_addr_t paddr1 = tb_page_addr1(tb);
|
||||
tb_page_addr_t pindex0 = paddr0 >> TARGET_PAGE_BITS;
|
||||
tb_page_addr_t pindex1 = paddr1 >> TARGET_PAGE_BITS;
|
||||
|
||||
if (unlikely(paddr0 == -1)) {
|
||||
return;
|
||||
}
|
||||
if (unlikely(paddr1 != -1) && pindex0 != pindex1) {
|
||||
page_unlock(page_find_alloc(pindex1, false));
|
||||
}
|
||||
page_unlock(page_find_alloc(pindex0, false));
|
||||
}
|
||||
|
||||
static inline struct page_entry *
|
||||
page_entry_new(PageDesc *pd, tb_page_addr_t index)
|
||||
{
|
||||
@@ -506,10 +420,13 @@ static void page_entry_destroy(gpointer p)
|
||||
/* returns false on success */
|
||||
static bool page_entry_trylock(struct page_entry *pe)
|
||||
{
|
||||
bool busy = page_trylock(pe->pd);
|
||||
bool busy;
|
||||
|
||||
busy = qemu_spin_trylock(&pe->pd->lock);
|
||||
if (!busy) {
|
||||
g_assert(!pe->locked);
|
||||
pe->locked = true;
|
||||
page_lock__debug(pe->pd);
|
||||
}
|
||||
return busy;
|
||||
}
|
||||
@@ -687,7 +604,8 @@ static void tb_remove_all(void)
|
||||
* Add the tb in the target page and protect it if necessary.
|
||||
* Called with @p->lock held.
|
||||
*/
|
||||
static void tb_page_add(PageDesc *p, TranslationBlock *tb, unsigned int n)
|
||||
static inline void tb_page_add(PageDesc *p, TranslationBlock *tb,
|
||||
unsigned int n)
|
||||
{
|
||||
bool page_already_protected;
|
||||
|
||||
@@ -707,21 +625,15 @@ static void tb_page_add(PageDesc *p, TranslationBlock *tb, unsigned int n)
|
||||
}
|
||||
}
|
||||
|
||||
static void tb_record(TranslationBlock *tb)
|
||||
static void tb_record(TranslationBlock *tb, PageDesc *p1, PageDesc *p2)
|
||||
{
|
||||
tb_page_addr_t paddr0 = tb_page_addr0(tb);
|
||||
tb_page_addr_t paddr1 = tb_page_addr1(tb);
|
||||
tb_page_addr_t pindex0 = paddr0 >> TARGET_PAGE_BITS;
|
||||
tb_page_addr_t pindex1 = paddr0 >> TARGET_PAGE_BITS;
|
||||
|
||||
assert(paddr0 != -1);
|
||||
if (unlikely(paddr1 != -1) && pindex0 != pindex1) {
|
||||
tb_page_add(page_find_alloc(pindex1, false), tb, 1);
|
||||
tb_page_add(p1, tb, 0);
|
||||
if (unlikely(p2)) {
|
||||
tb_page_add(p2, tb, 1);
|
||||
}
|
||||
tb_page_add(page_find_alloc(pindex0, false), tb, 0);
|
||||
}
|
||||
|
||||
static void tb_page_remove(PageDesc *pd, TranslationBlock *tb)
|
||||
static inline void tb_page_remove(PageDesc *pd, TranslationBlock *tb)
|
||||
{
|
||||
TranslationBlock *tb1;
|
||||
uintptr_t *pprev;
|
||||
@@ -741,16 +653,74 @@ static void tb_page_remove(PageDesc *pd, TranslationBlock *tb)
|
||||
|
||||
static void tb_remove(TranslationBlock *tb)
|
||||
{
|
||||
tb_page_addr_t paddr0 = tb_page_addr0(tb);
|
||||
tb_page_addr_t paddr1 = tb_page_addr1(tb);
|
||||
tb_page_addr_t pindex0 = paddr0 >> TARGET_PAGE_BITS;
|
||||
tb_page_addr_t pindex1 = paddr0 >> TARGET_PAGE_BITS;
|
||||
PageDesc *pd;
|
||||
|
||||
assert(paddr0 != -1);
|
||||
if (unlikely(paddr1 != -1) && pindex0 != pindex1) {
|
||||
tb_page_remove(page_find_alloc(pindex1, false), tb);
|
||||
pd = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
|
||||
tb_page_remove(pd, tb);
|
||||
if (unlikely(tb->page_addr[1] != -1)) {
|
||||
pd = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
|
||||
tb_page_remove(pd, tb);
|
||||
}
|
||||
}
|
||||
|
||||
static void page_lock_pair(PageDesc **ret_p1, tb_page_addr_t phys1,
|
||||
PageDesc **ret_p2, tb_page_addr_t phys2, bool alloc)
|
||||
{
|
||||
PageDesc *p1, *p2;
|
||||
tb_page_addr_t page1;
|
||||
tb_page_addr_t page2;
|
||||
|
||||
assert_memory_lock();
|
||||
g_assert(phys1 != -1);
|
||||
|
||||
page1 = phys1 >> TARGET_PAGE_BITS;
|
||||
page2 = phys2 >> TARGET_PAGE_BITS;
|
||||
|
||||
p1 = page_find_alloc(page1, alloc);
|
||||
if (ret_p1) {
|
||||
*ret_p1 = p1;
|
||||
}
|
||||
if (likely(phys2 == -1)) {
|
||||
page_lock(p1);
|
||||
return;
|
||||
} else if (page1 == page2) {
|
||||
page_lock(p1);
|
||||
if (ret_p2) {
|
||||
*ret_p2 = p1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
p2 = page_find_alloc(page2, alloc);
|
||||
if (ret_p2) {
|
||||
*ret_p2 = p2;
|
||||
}
|
||||
if (page1 < page2) {
|
||||
page_lock(p1);
|
||||
page_lock(p2);
|
||||
} else {
|
||||
page_lock(p2);
|
||||
page_lock(p1);
|
||||
}
|
||||
}
|
||||
|
||||
/* lock the page(s) of a TB in the correct acquisition order */
|
||||
static void page_lock_tb(const TranslationBlock *tb)
|
||||
{
|
||||
page_lock_pair(NULL, tb_page_addr0(tb), NULL, tb_page_addr1(tb), false);
|
||||
}
|
||||
|
||||
static void page_unlock_tb(const TranslationBlock *tb)
|
||||
{
|
||||
PageDesc *p1 = page_find(tb_page_addr0(tb) >> TARGET_PAGE_BITS);
|
||||
|
||||
page_unlock(p1);
|
||||
if (unlikely(tb_page_addr1(tb) != -1)) {
|
||||
PageDesc *p2 = page_find(tb_page_addr1(tb) >> TARGET_PAGE_BITS);
|
||||
|
||||
if (p2 != p1) {
|
||||
page_unlock(p2);
|
||||
}
|
||||
}
|
||||
tb_page_remove(page_find_alloc(pindex0, false), tb);
|
||||
}
|
||||
#endif /* CONFIG_USER_ONLY */
|
||||
|
||||
@@ -955,16 +925,18 @@ static void tb_phys_invalidate__locked(TranslationBlock *tb)
|
||||
void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr)
|
||||
{
|
||||
if (page_addr == -1 && tb_page_addr0(tb) != -1) {
|
||||
tb_lock_pages(tb);
|
||||
page_lock_tb(tb);
|
||||
do_tb_phys_invalidate(tb, true);
|
||||
tb_unlock_pages(tb);
|
||||
page_unlock_tb(tb);
|
||||
} else {
|
||||
do_tb_phys_invalidate(tb, false);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a new TB and link it to the physical page tables.
|
||||
* Add a new TB and link it to the physical page tables. phys_page2 is
|
||||
* (-1) to indicate that only one page contains the TB.
|
||||
*
|
||||
* Called with mmap_lock held for user-mode emulation.
|
||||
*
|
||||
* Returns a pointer @tb, or a pointer to an existing TB that matches @tb.
|
||||
@@ -972,29 +944,43 @@ void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr)
|
||||
* for the same block of guest code that @tb corresponds to. In that case,
|
||||
* the caller should discard the original @tb, and use instead the returned TB.
|
||||
*/
|
||||
TranslationBlock *tb_link_page(TranslationBlock *tb)
|
||||
TranslationBlock *tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
|
||||
tb_page_addr_t phys_page2)
|
||||
{
|
||||
PageDesc *p;
|
||||
PageDesc *p2 = NULL;
|
||||
void *existing_tb = NULL;
|
||||
uint32_t h;
|
||||
|
||||
assert_memory_lock();
|
||||
tcg_debug_assert(!(tb->cflags & CF_INVALID));
|
||||
|
||||
tb_record(tb);
|
||||
/*
|
||||
* Add the TB to the page list, acquiring first the pages's locks.
|
||||
* We keep the locks held until after inserting the TB in the hash table,
|
||||
* so that if the insertion fails we know for sure that the TBs are still
|
||||
* in the page descriptors.
|
||||
* Note that inserting into the hash table first isn't an option, since
|
||||
* we can only insert TBs that are fully initialized.
|
||||
*/
|
||||
page_lock_pair(&p, phys_pc, &p2, phys_page2, true);
|
||||
tb_record(tb, p, p2);
|
||||
|
||||
/* add in the hash table */
|
||||
h = tb_hash_func(tb_page_addr0(tb), (tb->cflags & CF_PCREL ? 0 : tb->pc),
|
||||
h = tb_hash_func(phys_pc, (tb->cflags & CF_PCREL ? 0 : tb->pc),
|
||||
tb->flags, tb->cs_base, tb->cflags);
|
||||
qht_insert(&tb_ctx.htable, tb, h, &existing_tb);
|
||||
|
||||
/* remove TB from the page(s) if we couldn't insert it */
|
||||
if (unlikely(existing_tb)) {
|
||||
tb_remove(tb);
|
||||
tb_unlock_pages(tb);
|
||||
return existing_tb;
|
||||
tb = existing_tb;
|
||||
}
|
||||
|
||||
tb_unlock_pages(tb);
|
||||
if (p2 && p2 != p) {
|
||||
page_unlock(p2);
|
||||
}
|
||||
page_unlock(p);
|
||||
return tb;
|
||||
}
|
||||
|
||||
@@ -1083,8 +1069,7 @@ bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc)
|
||||
if (current_tb_modified) {
|
||||
/* Force execution of one insn next time. */
|
||||
CPUState *cpu = current_cpu;
|
||||
cpu->cflags_next_tb =
|
||||
1 | CF_LAST_IO | CF_NOIRQ | curr_cflags(current_cpu);
|
||||
cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1107,9 +1092,6 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages,
|
||||
TranslationBlock *current_tb = retaddr ? tcg_tb_lookup(retaddr) : NULL;
|
||||
#endif /* TARGET_HAS_PRECISE_SMC */
|
||||
|
||||
/* Range may not cross a page. */
|
||||
tcg_debug_assert(((start ^ last) & TARGET_PAGE_MASK) == 0);
|
||||
|
||||
/*
|
||||
* We remove all the TBs in the range [start, last].
|
||||
* XXX: see if in some cases it could be faster to invalidate all the code
|
||||
@@ -1154,8 +1136,7 @@ tb_invalidate_phys_page_range__locked(struct page_collection *pages,
|
||||
if (current_tb_modified) {
|
||||
page_collection_unlock(pages);
|
||||
/* Force execution of one insn next time. */
|
||||
current_cpu->cflags_next_tb =
|
||||
1 | CF_LAST_IO | CF_NOIRQ | curr_cflags(current_cpu);
|
||||
current_cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu);
|
||||
mmap_unlock();
|
||||
cpu_loop_exit_noexc(current_cpu);
|
||||
}
|
||||
@@ -1201,17 +1182,15 @@ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last)
|
||||
index_last = last >> TARGET_PAGE_BITS;
|
||||
for (index = start >> TARGET_PAGE_BITS; index <= index_last; index++) {
|
||||
PageDesc *pd = page_find(index);
|
||||
tb_page_addr_t page_start, page_last;
|
||||
tb_page_addr_t bound;
|
||||
|
||||
if (pd == NULL) {
|
||||
continue;
|
||||
}
|
||||
assert_page_locked(pd);
|
||||
page_start = index << TARGET_PAGE_BITS;
|
||||
page_last = page_start | ~TARGET_PAGE_MASK;
|
||||
page_last = MIN(page_last, last);
|
||||
tb_invalidate_phys_page_range__locked(pages, pd,
|
||||
page_start, page_last, 0);
|
||||
bound = (index << TARGET_PAGE_BITS) | ~TARGET_PAGE_MASK;
|
||||
bound = MIN(bound, last);
|
||||
tb_invalidate_phys_page_range__locked(pages, pd, start, bound, 0);
|
||||
}
|
||||
page_collection_unlock(pages);
|
||||
}
|
||||
|
||||
@@ -100,9 +100,14 @@ static void *mttcg_cpu_thread_fn(void *arg)
|
||||
break;
|
||||
case EXCP_HALTED:
|
||||
/*
|
||||
* Usually cpu->halted is set, but may have already been
|
||||
* reset by another thread by the time we arrive here.
|
||||
* during start-up the vCPU is reset and the thread is
|
||||
* kicked several times. If we don't ensure we go back
|
||||
* to sleep in the halted state we won't cleanly
|
||||
* start-up when the vCPU is enabled.
|
||||
*
|
||||
* cpu->halted should ensure we sleep in wait_io_event
|
||||
*/
|
||||
g_assert(cpu->halted);
|
||||
break;
|
||||
case EXCP_ATOMIC:
|
||||
qemu_mutex_unlock_iothread();
|
||||
|
||||
@@ -58,7 +58,7 @@ DEF_HELPER_FLAGS_5(atomic_cmpxchgq_be, TCG_CALL_NO_WG,
|
||||
DEF_HELPER_FLAGS_5(atomic_cmpxchgq_le, TCG_CALL_NO_WG,
|
||||
i64, env, i64, i64, i64, i32)
|
||||
#endif
|
||||
#if HAVE_CMPXCHG128
|
||||
#ifdef CONFIG_CMPXCHG128
|
||||
DEF_HELPER_FLAGS_5(atomic_cmpxchgo_be, TCG_CALL_NO_WG,
|
||||
i128, env, i64, i128, i128, i32)
|
||||
DEF_HELPER_FLAGS_5(atomic_cmpxchgo_le, TCG_CALL_NO_WG,
|
||||
|
||||
@@ -290,7 +290,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
{
|
||||
CPUArchState *env = cpu->env_ptr;
|
||||
TranslationBlock *tb, *existing_tb;
|
||||
tb_page_addr_t phys_pc, phys_p2;
|
||||
tb_page_addr_t phys_pc;
|
||||
tcg_insn_unit *gen_code_buf;
|
||||
int gen_code_size, search_size, max_insns;
|
||||
int64_t ti;
|
||||
@@ -313,7 +313,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
QEMU_BUILD_BUG_ON(CF_COUNT_MASK + 1 != TCG_MAX_INSNS);
|
||||
|
||||
buffer_overflow:
|
||||
assert_no_pages_locked();
|
||||
tb = tcg_tb_alloc(tcg_ctx);
|
||||
if (unlikely(!tb)) {
|
||||
/* flush must be done */
|
||||
@@ -334,10 +333,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
tb->cflags = cflags;
|
||||
tb_set_page_addr0(tb, phys_pc);
|
||||
tb_set_page_addr1(tb, -1);
|
||||
if (phys_pc != -1) {
|
||||
tb_lock_page0(phys_pc);
|
||||
}
|
||||
|
||||
tcg_ctx->gen_tb = tb;
|
||||
tcg_ctx->addr_type = TARGET_LONG_BITS == 32 ? TCG_TYPE_I32 : TCG_TYPE_I64;
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
@@ -354,7 +349,8 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
tcg_ctx->guest_mo = TCG_MO_ALL;
|
||||
#endif
|
||||
|
||||
restart_translate:
|
||||
tb_overflow:
|
||||
|
||||
trace_translate_block(tb, pc, tb->tc.ptr);
|
||||
|
||||
gen_code_size = setjmp_gen_code(env, tb, pc, host_pc, &max_insns, &ti);
|
||||
@@ -373,8 +369,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
qemu_log_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT,
|
||||
"Restarting code generation for "
|
||||
"code_gen_buffer overflow\n");
|
||||
tb_unlock_pages(tb);
|
||||
tcg_ctx->gen_tb = NULL;
|
||||
goto buffer_overflow;
|
||||
|
||||
case -2:
|
||||
@@ -393,39 +387,14 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
"Restarting code generation with "
|
||||
"smaller translation block (max %d insns)\n",
|
||||
max_insns);
|
||||
|
||||
/*
|
||||
* The half-sized TB may not cross pages.
|
||||
* TODO: Fix all targets that cross pages except with
|
||||
* the first insn, at which point this can't be reached.
|
||||
*/
|
||||
phys_p2 = tb_page_addr1(tb);
|
||||
if (unlikely(phys_p2 != -1)) {
|
||||
tb_unlock_page1(phys_pc, phys_p2);
|
||||
tb_set_page_addr1(tb, -1);
|
||||
}
|
||||
goto restart_translate;
|
||||
|
||||
case -3:
|
||||
/*
|
||||
* We had a page lock ordering problem. In order to avoid
|
||||
* deadlock we had to drop the lock on page0, which means
|
||||
* that everything we translated so far is compromised.
|
||||
* Restart with locks held on both pages.
|
||||
*/
|
||||
qemu_log_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT,
|
||||
"Restarting code generation with re-locked pages");
|
||||
goto restart_translate;
|
||||
goto tb_overflow;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
tcg_ctx->gen_tb = NULL;
|
||||
|
||||
search_size = encode_search(tb, (void *)gen_code_buf + gen_code_size);
|
||||
if (unlikely(search_size < 0)) {
|
||||
tb_unlock_pages(tb);
|
||||
goto buffer_overflow;
|
||||
}
|
||||
tb->tc.size = gen_code_size;
|
||||
@@ -535,7 +504,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
* before attempting to link to other TBs or add to the lookup table.
|
||||
*/
|
||||
if (tb_page_addr0(tb) == -1) {
|
||||
assert_no_pages_locked();
|
||||
return tb;
|
||||
}
|
||||
|
||||
@@ -550,9 +518,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
||||
* No explicit memory barrier is required -- tb_link_page() makes the
|
||||
* TB visible in a consistent state.
|
||||
*/
|
||||
existing_tb = tb_link_page(tb);
|
||||
assert_no_pages_locked();
|
||||
|
||||
existing_tb = tb_link_page(tb, tb_page_addr0(tb), tb_page_addr1(tb));
|
||||
/* if the TB already exists, discard what we just translated */
|
||||
if (unlikely(existing_tb != tb)) {
|
||||
uintptr_t orig_aligned = (uintptr_t)gen_code_buf;
|
||||
@@ -638,7 +604,7 @@ void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr)
|
||||
if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
|
||||
vaddr pc = log_pc(cpu, tb);
|
||||
if (qemu_log_in_addr_range(pc)) {
|
||||
qemu_log("cpu_io_recompile: rewound execution of TB to %016"
|
||||
qemu_log("cpu_io_recompile: rewound execution of TB to %"
|
||||
VADDR_PRIx "\n", pc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,23 +12,30 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "exec/translator.h"
|
||||
#include "exec/translate-all.h"
|
||||
#include "exec/plugin-gen.h"
|
||||
#include "tcg/tcg-op-common.h"
|
||||
#include "internal.h"
|
||||
|
||||
static void set_can_do_io(DisasContextBase *db, bool val)
|
||||
static void gen_io_start(void)
|
||||
{
|
||||
if (db->saved_can_do_io != val) {
|
||||
db->saved_can_do_io = val;
|
||||
tcg_gen_st_i32(tcg_constant_i32(val), cpu_env,
|
||||
offsetof(ArchCPU, parent_obj.can_do_io) -
|
||||
offsetof(ArchCPU, env));
|
||||
}
|
||||
tcg_gen_st_i32(tcg_constant_i32(1), cpu_env,
|
||||
offsetof(ArchCPU, parent_obj.can_do_io) -
|
||||
offsetof(ArchCPU, env));
|
||||
}
|
||||
|
||||
bool translator_io_start(DisasContextBase *db)
|
||||
{
|
||||
set_can_do_io(db, true);
|
||||
uint32_t cflags = tb_cflags(db->tb);
|
||||
|
||||
if (!(cflags & CF_USE_ICOUNT)) {
|
||||
return false;
|
||||
}
|
||||
if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) {
|
||||
/* Already started in translator_loop. */
|
||||
return true;
|
||||
}
|
||||
|
||||
gen_io_start();
|
||||
|
||||
/*
|
||||
* Ensure that this instruction will be the last in the TB.
|
||||
@@ -40,17 +47,14 @@ bool translator_io_start(DisasContextBase *db)
|
||||
return true;
|
||||
}
|
||||
|
||||
static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags)
|
||||
static TCGOp *gen_tb_start(uint32_t cflags)
|
||||
{
|
||||
TCGv_i32 count = NULL;
|
||||
TCGv_i32 count = tcg_temp_new_i32();
|
||||
TCGOp *icount_start_insn = NULL;
|
||||
|
||||
if ((cflags & CF_USE_ICOUNT) || !(cflags & CF_NOIRQ)) {
|
||||
count = tcg_temp_new_i32();
|
||||
tcg_gen_ld_i32(count, cpu_env,
|
||||
offsetof(ArchCPU, neg.icount_decr.u32) -
|
||||
offsetof(ArchCPU, env));
|
||||
}
|
||||
tcg_gen_ld_i32(count, cpu_env,
|
||||
offsetof(ArchCPU, neg.icount_decr.u32) -
|
||||
offsetof(ArchCPU, env));
|
||||
|
||||
if (cflags & CF_USE_ICOUNT) {
|
||||
/*
|
||||
@@ -80,15 +84,18 @@ static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags)
|
||||
tcg_gen_st16_i32(count, cpu_env,
|
||||
offsetof(ArchCPU, neg.icount_decr.u16.low) -
|
||||
offsetof(ArchCPU, env));
|
||||
/*
|
||||
* cpu->can_do_io is cleared automatically here at the beginning of
|
||||
* each translation block. The cost is minimal and only paid for
|
||||
* -icount, plus it would be very easy to forget doing it in the
|
||||
* translator. Doing it here means we don't need a gen_io_end() to
|
||||
* go with gen_io_start().
|
||||
*/
|
||||
tcg_gen_st_i32(tcg_constant_i32(0), cpu_env,
|
||||
offsetof(ArchCPU, parent_obj.can_do_io) -
|
||||
offsetof(ArchCPU, env));
|
||||
}
|
||||
|
||||
/*
|
||||
* cpu->can_do_io is set automatically here at the beginning of
|
||||
* each translation block. The cost is minimal, plus it would be
|
||||
* very easy to forget doing it in the translator.
|
||||
*/
|
||||
set_can_do_io(db, db->max_insns == 1 && (cflags & CF_LAST_IO));
|
||||
|
||||
return icount_start_insn;
|
||||
}
|
||||
|
||||
@@ -137,25 +144,22 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
db->num_insns = 0;
|
||||
db->max_insns = *max_insns;
|
||||
db->singlestep_enabled = cflags & CF_SINGLE_STEP;
|
||||
db->saved_can_do_io = -1;
|
||||
db->host_addr[0] = host_pc;
|
||||
db->host_addr[1] = NULL;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
page_protect(pc);
|
||||
#endif
|
||||
|
||||
ops->init_disas_context(db, cpu);
|
||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||
|
||||
/* Start translating. */
|
||||
icount_start_insn = gen_tb_start(db, cflags);
|
||||
icount_start_insn = gen_tb_start(cflags);
|
||||
ops->tb_start(db, cpu);
|
||||
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
|
||||
|
||||
if (cflags & CF_MEMI_ONLY) {
|
||||
/* We should only see CF_MEMI_ONLY for io_recompile. */
|
||||
assert(cflags & CF_LAST_IO);
|
||||
plugin_enabled = plugin_gen_tb_start(cpu, db, true);
|
||||
} else {
|
||||
plugin_enabled = plugin_gen_tb_start(cpu, db, false);
|
||||
}
|
||||
plugin_enabled = plugin_gen_tb_start(cpu, db, cflags & CF_MEMI_ONLY);
|
||||
|
||||
while (true) {
|
||||
*max_insns = ++db->num_insns;
|
||||
@@ -172,9 +176,13 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
|
||||
the next instruction. */
|
||||
if (db->num_insns == db->max_insns && (cflags & CF_LAST_IO)) {
|
||||
/* Accept I/O on the last instruction. */
|
||||
set_can_do_io(db, true);
|
||||
gen_io_start();
|
||||
ops->translate_insn(db, cpu);
|
||||
} else {
|
||||
/* we should only see CF_MEMI_ONLY for io_recompile */
|
||||
tcg_debug_assert(!(cflags & CF_MEMI_ONLY));
|
||||
ops->translate_insn(db, cpu);
|
||||
}
|
||||
ops->translate_insn(db, cpu);
|
||||
|
||||
/*
|
||||
* We can't instrument after instructions that change control
|
||||
@@ -248,36 +256,22 @@ static void *translator_access(CPUArchState *env, DisasContextBase *db,
|
||||
host = db->host_addr[1];
|
||||
base = TARGET_PAGE_ALIGN(db->pc_first);
|
||||
if (host == NULL) {
|
||||
tb_page_addr_t page0, old_page1, new_page1;
|
||||
|
||||
new_page1 = get_page_addr_code_hostp(env, base, &db->host_addr[1]);
|
||||
tb_page_addr_t phys_page =
|
||||
get_page_addr_code_hostp(env, base, &db->host_addr[1]);
|
||||
|
||||
/*
|
||||
* If the second page is MMIO, treat as if the first page
|
||||
* was MMIO as well, so that we do not cache the TB.
|
||||
*/
|
||||
if (unlikely(new_page1 == -1)) {
|
||||
tb_unlock_pages(tb);
|
||||
if (unlikely(phys_page == -1)) {
|
||||
tb_set_page_addr0(tb, -1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is not the first time around, and page1 matches,
|
||||
* then we already have the page locked. Alternately, we're
|
||||
* not doing anything to prevent the PTE from changing, so
|
||||
* we might wind up with a different page, requiring us to
|
||||
* re-do the locking.
|
||||
*/
|
||||
old_page1 = tb_page_addr1(tb);
|
||||
if (likely(new_page1 != old_page1)) {
|
||||
page0 = tb_page_addr0(tb);
|
||||
if (unlikely(old_page1 != -1)) {
|
||||
tb_unlock_page1(page0, old_page1);
|
||||
}
|
||||
tb_set_page_addr1(tb, new_page1);
|
||||
tb_lock_page1(page0, new_page1);
|
||||
}
|
||||
tb_set_page_addr1(tb, phys_page);
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
page_protect(end);
|
||||
#endif
|
||||
host = db->host_addr[1];
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ typedef struct PageFlagsNode {
|
||||
|
||||
static IntervalTreeRoot pageflags_root;
|
||||
|
||||
static PageFlagsNode *pageflags_find(target_ulong start, target_ulong last)
|
||||
static PageFlagsNode *pageflags_find(target_ulong start, target_long last)
|
||||
{
|
||||
IntervalTreeNode *n;
|
||||
|
||||
@@ -153,7 +153,7 @@ static PageFlagsNode *pageflags_find(target_ulong start, target_ulong last)
|
||||
}
|
||||
|
||||
static PageFlagsNode *pageflags_next(PageFlagsNode *p, target_ulong start,
|
||||
target_ulong last)
|
||||
target_long last)
|
||||
{
|
||||
IntervalTreeNode *n;
|
||||
|
||||
@@ -520,19 +520,19 @@ void page_set_flags(target_ulong start, target_ulong last, int flags)
|
||||
}
|
||||
}
|
||||
|
||||
bool page_check_range(target_ulong start, target_ulong len, int flags)
|
||||
int page_check_range(target_ulong start, target_ulong len, int flags)
|
||||
{
|
||||
target_ulong last;
|
||||
int locked; /* tri-state: =0: unlocked, +1: global, -1: local */
|
||||
bool ret;
|
||||
int ret;
|
||||
|
||||
if (len == 0) {
|
||||
return true; /* trivial length */
|
||||
return 0; /* trivial length */
|
||||
}
|
||||
|
||||
last = start + len - 1;
|
||||
if (last < start) {
|
||||
return false; /* wrap around */
|
||||
return -1; /* wrap around */
|
||||
}
|
||||
|
||||
locked = have_mmap_lock();
|
||||
@@ -551,33 +551,33 @@ bool page_check_range(target_ulong start, target_ulong len, int flags)
|
||||
p = pageflags_find(start, last);
|
||||
}
|
||||
if (!p) {
|
||||
ret = false; /* entire region invalid */
|
||||
ret = -1; /* entire region invalid */
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (start < p->itree.start) {
|
||||
ret = false; /* initial bytes invalid */
|
||||
ret = -1; /* initial bytes invalid */
|
||||
break;
|
||||
}
|
||||
|
||||
missing = flags & ~p->flags;
|
||||
if (missing & ~PAGE_WRITE) {
|
||||
ret = false; /* page doesn't match */
|
||||
if (missing & PAGE_READ) {
|
||||
ret = -1; /* page not readable */
|
||||
break;
|
||||
}
|
||||
if (missing & PAGE_WRITE) {
|
||||
if (!(p->flags & PAGE_WRITE_ORG)) {
|
||||
ret = false; /* page not writable */
|
||||
ret = -1; /* page not writable */
|
||||
break;
|
||||
}
|
||||
/* Asking about writable, but has been protected: undo. */
|
||||
if (!page_unprotect(start, 0)) {
|
||||
ret = false;
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
/* TODO: page_unprotect should take a range, not a single page. */
|
||||
if (last - start < TARGET_PAGE_SIZE) {
|
||||
ret = true; /* ok */
|
||||
ret = 0; /* ok */
|
||||
break;
|
||||
}
|
||||
start += TARGET_PAGE_SIZE;
|
||||
@@ -585,7 +585,7 @@ bool page_check_range(target_ulong start, target_ulong len, int flags)
|
||||
}
|
||||
|
||||
if (last <= p->itree.last) {
|
||||
ret = true; /* ok */
|
||||
ret = 0; /* ok */
|
||||
break;
|
||||
}
|
||||
start = p->itree.last + 1;
|
||||
@@ -598,54 +598,6 @@ bool page_check_range(target_ulong start, target_ulong len, int flags)
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool page_check_range_empty(target_ulong start, target_ulong last)
|
||||
{
|
||||
assert(last >= start);
|
||||
assert_memory_lock();
|
||||
return pageflags_find(start, last) == NULL;
|
||||
}
|
||||
|
||||
target_ulong page_find_range_empty(target_ulong min, target_ulong max,
|
||||
target_ulong len, target_ulong align)
|
||||
{
|
||||
target_ulong len_m1, align_m1;
|
||||
|
||||
assert(min <= max);
|
||||
assert(max <= GUEST_ADDR_MAX);
|
||||
assert(len != 0);
|
||||
assert(is_power_of_2(align));
|
||||
assert_memory_lock();
|
||||
|
||||
len_m1 = len - 1;
|
||||
align_m1 = align - 1;
|
||||
|
||||
/* Iteratively narrow the search region. */
|
||||
while (1) {
|
||||
PageFlagsNode *p;
|
||||
|
||||
/* Align min and double-check there's enough space remaining. */
|
||||
min = (min + align_m1) & ~align_m1;
|
||||
if (min > max) {
|
||||
return -1;
|
||||
}
|
||||
if (len_m1 > max - min) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = pageflags_find(min, min + len_m1);
|
||||
if (p == NULL) {
|
||||
/* Found! */
|
||||
return min;
|
||||
}
|
||||
if (max <= p->itree.last) {
|
||||
/* Existing allocation fills the remainder of the search region. */
|
||||
return -1;
|
||||
}
|
||||
/* Skip across existing allocation. */
|
||||
min = p->itree.last + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void page_protect(tb_page_addr_t address)
|
||||
{
|
||||
PageFlagsNode *p;
|
||||
@@ -793,10 +745,6 @@ static int probe_access_internal(CPUArchState *env, vaddr addr,
|
||||
if (guest_addr_valid_untagged(addr)) {
|
||||
int page_flags = page_get_flags(addr);
|
||||
if (page_flags & acc_flag) {
|
||||
if ((acc_flag == PAGE_READ || acc_flag == PAGE_WRITE)
|
||||
&& cpu_plugin_mem_cbs_enabled(env_cpu(env))) {
|
||||
return TLB_MMIO;
|
||||
}
|
||||
return 0; /* success */
|
||||
}
|
||||
maperr = !(page_flags & PAGE_VALID);
|
||||
@@ -819,7 +767,7 @@ int probe_access_flags(CPUArchState *env, vaddr addr, int size,
|
||||
|
||||
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
|
||||
flags = probe_access_internal(env, addr, size, access_type, nonfault, ra);
|
||||
*phost = (flags & TLB_INVALID_MASK) ? NULL : g2h(env_cpu(env), addr);
|
||||
*phost = flags ? NULL : g2h(env_cpu(env), addr);
|
||||
return flags;
|
||||
}
|
||||
|
||||
@@ -830,7 +778,7 @@ void *probe_access(CPUArchState *env, vaddr addr, int size,
|
||||
|
||||
g_assert(-(addr | TARGET_PAGE_MASK) >= size);
|
||||
flags = probe_access_internal(env, addr, size, access_type, false, ra);
|
||||
g_assert((flags & ~TLB_MMIO) == 0);
|
||||
g_assert(flags == 0);
|
||||
|
||||
return size ? g2h(env_cpu(env), addr) : NULL;
|
||||
}
|
||||
@@ -1433,7 +1381,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi,
|
||||
#include "atomic_template.h"
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_ATOMIC128) || HAVE_CMPXCHG128
|
||||
#if defined(CONFIG_ATOMIC128) || defined(CONFIG_CMPXCHG128)
|
||||
#define DATA_SIZE 16
|
||||
#include "atomic_template.h"
|
||||
#endif
|
||||
|
||||
@@ -31,7 +31,7 @@ endforeach
|
||||
|
||||
if dbus_display
|
||||
module_ss = ss.source_set()
|
||||
module_ss.add(when: [gio, pixman], if_true: files('dbusaudio.c'))
|
||||
module_ss.add(when: gio, if_true: files('dbusaudio.c'))
|
||||
audio_modules += {'dbus': module_ss}
|
||||
endif
|
||||
|
||||
|
||||
216
audio/pwaudio.c
216
audio/pwaudio.c
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* QEMU PipeWire audio driver
|
||||
* QEMU Pipewire audio driver
|
||||
*
|
||||
* Copyright (c) 2023 Red Hat Inc.
|
||||
*
|
||||
@@ -66,9 +66,6 @@ typedef struct PWVoiceIn {
|
||||
PWVoice v;
|
||||
} PWVoiceIn;
|
||||
|
||||
#define PW_VOICE_IN(v) ((PWVoiceIn *)v)
|
||||
#define PW_VOICE_OUT(v) ((PWVoiceOut *)v)
|
||||
|
||||
static void
|
||||
stream_destroy(void *data)
|
||||
{
|
||||
@@ -200,6 +197,16 @@ on_stream_state_changed(void *data, enum pw_stream_state old,
|
||||
|
||||
trace_pw_state_changed(pw_stream_get_node_id(v->stream),
|
||||
pw_stream_state_as_string(state));
|
||||
|
||||
switch (state) {
|
||||
case PW_STREAM_STATE_ERROR:
|
||||
case PW_STREAM_STATE_UNCONNECTED:
|
||||
break;
|
||||
case PW_STREAM_STATE_PAUSED:
|
||||
case PW_STREAM_STATE_CONNECTING:
|
||||
case PW_STREAM_STATE_STREAMING:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pw_stream_events capture_stream_events = {
|
||||
@@ -417,8 +424,8 @@ pw_to_audfmt(enum spa_audio_format fmt, int *endianness,
|
||||
}
|
||||
|
||||
static int
|
||||
qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
|
||||
const char *name, enum spa_direction dir)
|
||||
create_stream(pwaudio *c, PWVoice *v, const char *stream_name,
|
||||
const char *name, enum spa_direction dir)
|
||||
{
|
||||
int res;
|
||||
uint32_t n_params;
|
||||
@@ -429,10 +436,6 @@ qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
|
||||
struct pw_properties *props;
|
||||
|
||||
props = pw_properties_new(NULL, NULL);
|
||||
if (!props) {
|
||||
error_report("Failed to create PW properties: %s", g_strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 75% of the timer period for faster updates */
|
||||
buf_samples = (uint64_t)v->g->dev->timer_period * v->info.rate
|
||||
@@ -445,8 +448,8 @@ qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
|
||||
pw_properties_set(props, PW_KEY_TARGET_OBJECT, name);
|
||||
}
|
||||
v->stream = pw_stream_new(c->core, stream_name, props);
|
||||
|
||||
if (v->stream == NULL) {
|
||||
error_report("Failed to create PW stream: %s", g_strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -474,7 +477,6 @@ qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
|
||||
PW_STREAM_FLAG_MAP_BUFFERS |
|
||||
PW_STREAM_FLAG_RT_PROCESS, params, n_params);
|
||||
if (res < 0) {
|
||||
error_report("Failed to connect PW stream: %s", g_strerror(errno));
|
||||
pw_stream_destroy(v->stream);
|
||||
return -1;
|
||||
}
|
||||
@@ -482,37 +484,71 @@ qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
qpw_set_position(uint32_t channels, uint32_t position[SPA_AUDIO_MAX_CHANNELS])
|
||||
static int
|
||||
qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
|
||||
const char *name, enum spa_direction dir)
|
||||
{
|
||||
memcpy(position, (uint32_t[SPA_AUDIO_MAX_CHANNELS]) { SPA_AUDIO_CHANNEL_UNKNOWN, },
|
||||
sizeof(uint32_t) * SPA_AUDIO_MAX_CHANNELS);
|
||||
/*
|
||||
* TODO: This currently expects the only frontend supporting more than 2
|
||||
* channels is the usb-audio. We will need some means to set channel
|
||||
* order when a new frontend gains multi-channel support.
|
||||
*/
|
||||
switch (channels) {
|
||||
int r;
|
||||
|
||||
switch (v->info.channels) {
|
||||
case 8:
|
||||
position[6] = SPA_AUDIO_CHANNEL_SL;
|
||||
position[7] = SPA_AUDIO_CHANNEL_SR;
|
||||
/* fallthrough */
|
||||
v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
|
||||
v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
|
||||
v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
|
||||
v->info.position[3] = SPA_AUDIO_CHANNEL_LFE;
|
||||
v->info.position[4] = SPA_AUDIO_CHANNEL_RL;
|
||||
v->info.position[5] = SPA_AUDIO_CHANNEL_RR;
|
||||
v->info.position[6] = SPA_AUDIO_CHANNEL_SL;
|
||||
v->info.position[7] = SPA_AUDIO_CHANNEL_SR;
|
||||
break;
|
||||
case 6:
|
||||
position[2] = SPA_AUDIO_CHANNEL_FC;
|
||||
position[3] = SPA_AUDIO_CHANNEL_LFE;
|
||||
position[4] = SPA_AUDIO_CHANNEL_RL;
|
||||
position[5] = SPA_AUDIO_CHANNEL_RR;
|
||||
/* fallthrough */
|
||||
v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
|
||||
v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
|
||||
v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
|
||||
v->info.position[3] = SPA_AUDIO_CHANNEL_LFE;
|
||||
v->info.position[4] = SPA_AUDIO_CHANNEL_RL;
|
||||
v->info.position[5] = SPA_AUDIO_CHANNEL_RR;
|
||||
break;
|
||||
case 5:
|
||||
v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
|
||||
v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
|
||||
v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
|
||||
v->info.position[3] = SPA_AUDIO_CHANNEL_LFE;
|
||||
v->info.position[4] = SPA_AUDIO_CHANNEL_RC;
|
||||
break;
|
||||
case 4:
|
||||
v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
|
||||
v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
|
||||
v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
|
||||
v->info.position[3] = SPA_AUDIO_CHANNEL_RC;
|
||||
break;
|
||||
case 3:
|
||||
v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
|
||||
v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
|
||||
v->info.position[2] = SPA_AUDIO_CHANNEL_LFE;
|
||||
break;
|
||||
case 2:
|
||||
position[0] = SPA_AUDIO_CHANNEL_FL;
|
||||
position[1] = SPA_AUDIO_CHANNEL_FR;
|
||||
v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
|
||||
v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
|
||||
break;
|
||||
case 1:
|
||||
position[0] = SPA_AUDIO_CHANNEL_MONO;
|
||||
v->info.position[0] = SPA_AUDIO_CHANNEL_MONO;
|
||||
break;
|
||||
default:
|
||||
dolog("Internal error: unsupported channel count %d\n", channels);
|
||||
for (size_t i = 0; i < v->info.channels; i++) {
|
||||
v->info.position[i] = SPA_AUDIO_CHANNEL_UNKNOWN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* create a new unconnected pwstream */
|
||||
r = create_stream(c, v, stream_name, name, dir);
|
||||
if (r < 0) {
|
||||
AUD_log(AUDIO_CAP, "Failed to create stream.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -530,7 +566,6 @@ qpw_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
|
||||
|
||||
v->info.format = audfmt_to_pw(as->fmt, as->endianness);
|
||||
v->info.channels = as->nchannels;
|
||||
qpw_set_position(as->nchannels, v->info.position);
|
||||
v->info.rate = as->freq;
|
||||
|
||||
obt_as.fmt =
|
||||
@@ -544,6 +579,7 @@ qpw_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
|
||||
r = qpw_stream_new(c, v, ppdo->stream_name ? : c->dev->id,
|
||||
ppdo->name, SPA_DIRECTION_OUTPUT);
|
||||
if (r < 0) {
|
||||
error_report("qpw_stream_new for playback failed");
|
||||
pw_thread_loop_unlock(c->thread_loop);
|
||||
return -1;
|
||||
}
|
||||
@@ -577,7 +613,6 @@ qpw_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
|
||||
v->info.format = audfmt_to_pw(as->fmt, as->endianness);
|
||||
v->info.channels = as->nchannels;
|
||||
qpw_set_position(as->nchannels, v->info.position);
|
||||
v->info.rate = as->freq;
|
||||
|
||||
obt_as.fmt =
|
||||
@@ -588,6 +623,7 @@ qpw_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
r = qpw_stream_new(c, v, ppdo->stream_name ? : c->dev->id,
|
||||
ppdo->name, SPA_DIRECTION_INPUT);
|
||||
if (r < 0) {
|
||||
error_report("qpw_stream_new for recording failed");
|
||||
pw_thread_loop_unlock(c->thread_loop);
|
||||
return -1;
|
||||
}
|
||||
@@ -603,56 +639,63 @@ qpw_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
qpw_voice_fini(PWVoice *v)
|
||||
{
|
||||
pwaudio *c = v->g;
|
||||
|
||||
if (!v->stream) {
|
||||
return;
|
||||
}
|
||||
pw_thread_loop_lock(c->thread_loop);
|
||||
pw_stream_destroy(v->stream);
|
||||
v->stream = NULL;
|
||||
pw_thread_loop_unlock(c->thread_loop);
|
||||
}
|
||||
|
||||
static void
|
||||
qpw_fini_out(HWVoiceOut *hw)
|
||||
{
|
||||
qpw_voice_fini(&PW_VOICE_OUT(hw)->v);
|
||||
PWVoiceOut *pw = (PWVoiceOut *) hw;
|
||||
PWVoice *v = &pw->v;
|
||||
|
||||
if (v->stream) {
|
||||
pwaudio *c = v->g;
|
||||
pw_thread_loop_lock(c->thread_loop);
|
||||
pw_stream_destroy(v->stream);
|
||||
v->stream = NULL;
|
||||
pw_thread_loop_unlock(c->thread_loop);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qpw_fini_in(HWVoiceIn *hw)
|
||||
{
|
||||
qpw_voice_fini(&PW_VOICE_IN(hw)->v);
|
||||
PWVoiceIn *pw = (PWVoiceIn *) hw;
|
||||
PWVoice *v = &pw->v;
|
||||
|
||||
if (v->stream) {
|
||||
pwaudio *c = v->g;
|
||||
pw_thread_loop_lock(c->thread_loop);
|
||||
pw_stream_destroy(v->stream);
|
||||
v->stream = NULL;
|
||||
pw_thread_loop_unlock(c->thread_loop);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qpw_voice_set_enabled(PWVoice *v, bool enable)
|
||||
qpw_enable_out(HWVoiceOut *hw, bool enable)
|
||||
{
|
||||
PWVoiceOut *po = (PWVoiceOut *) hw;
|
||||
PWVoice *v = &po->v;
|
||||
pwaudio *c = v->g;
|
||||
pw_thread_loop_lock(c->thread_loop);
|
||||
pw_stream_set_active(v->stream, enable);
|
||||
pw_thread_loop_unlock(c->thread_loop);
|
||||
}
|
||||
|
||||
static void
|
||||
qpw_enable_out(HWVoiceOut *hw, bool enable)
|
||||
{
|
||||
qpw_voice_set_enabled(&PW_VOICE_OUT(hw)->v, enable);
|
||||
}
|
||||
|
||||
static void
|
||||
qpw_enable_in(HWVoiceIn *hw, bool enable)
|
||||
{
|
||||
qpw_voice_set_enabled(&PW_VOICE_IN(hw)->v, enable);
|
||||
PWVoiceIn *pi = (PWVoiceIn *) hw;
|
||||
PWVoice *v = &pi->v;
|
||||
pwaudio *c = v->g;
|
||||
pw_thread_loop_lock(c->thread_loop);
|
||||
pw_stream_set_active(v->stream, enable);
|
||||
pw_thread_loop_unlock(c->thread_loop);
|
||||
}
|
||||
|
||||
static void
|
||||
qpw_voice_set_volume(PWVoice *v, Volume *vol)
|
||||
qpw_volume_out(HWVoiceOut *hw, Volume *vol)
|
||||
{
|
||||
PWVoiceOut *pw = (PWVoiceOut *) hw;
|
||||
PWVoice *v = &pw->v;
|
||||
pwaudio *c = v->g;
|
||||
int i, ret;
|
||||
|
||||
@@ -673,16 +716,29 @@ qpw_voice_set_volume(PWVoice *v, Volume *vol)
|
||||
pw_thread_loop_unlock(c->thread_loop);
|
||||
}
|
||||
|
||||
static void
|
||||
qpw_volume_out(HWVoiceOut *hw, Volume *vol)
|
||||
{
|
||||
qpw_voice_set_volume(&PW_VOICE_OUT(hw)->v, vol);
|
||||
}
|
||||
|
||||
static void
|
||||
qpw_volume_in(HWVoiceIn *hw, Volume *vol)
|
||||
{
|
||||
qpw_voice_set_volume(&PW_VOICE_IN(hw)->v, vol);
|
||||
PWVoiceIn *pw = (PWVoiceIn *) hw;
|
||||
PWVoice *v = &pw->v;
|
||||
pwaudio *c = v->g;
|
||||
int i, ret;
|
||||
|
||||
pw_thread_loop_lock(c->thread_loop);
|
||||
v->volume.channels = vol->channels;
|
||||
|
||||
for (i = 0; i < vol->channels; ++i) {
|
||||
v->volume.values[i] = (float)vol->vol[i] / 255;
|
||||
}
|
||||
|
||||
ret = pw_stream_set_control(v->stream,
|
||||
SPA_PROP_channelVolumes, v->volume.channels, v->volume.values, 0);
|
||||
trace_pw_vol(ret == 0 ? "success" : "failed");
|
||||
|
||||
v->muted = vol->mute;
|
||||
float val = v->muted ? 1.f : 0.f;
|
||||
ret = pw_stream_set_control(v->stream, SPA_PROP_mute, 1, &val, 0);
|
||||
pw_thread_loop_unlock(c->thread_loop);
|
||||
}
|
||||
|
||||
static int wait_resync(pwaudio *pw)
|
||||
@@ -704,7 +760,6 @@ static int wait_resync(pwaudio *pw)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
on_core_error(void *data, uint32_t id, int seq, int res, const char *message)
|
||||
{
|
||||
@@ -739,28 +794,27 @@ static void *
|
||||
qpw_audio_init(Audiodev *dev)
|
||||
{
|
||||
g_autofree pwaudio *pw = g_new0(pwaudio, 1);
|
||||
|
||||
assert(dev->driver == AUDIODEV_DRIVER_PIPEWIRE);
|
||||
trace_pw_audio_init();
|
||||
|
||||
pw_init(NULL, NULL);
|
||||
|
||||
trace_pw_audio_init();
|
||||
assert(dev->driver == AUDIODEV_DRIVER_PIPEWIRE);
|
||||
|
||||
pw->dev = dev;
|
||||
pw->thread_loop = pw_thread_loop_new("PipeWire thread loop", NULL);
|
||||
pw->thread_loop = pw_thread_loop_new("Pipewire thread loop", NULL);
|
||||
if (pw->thread_loop == NULL) {
|
||||
error_report("Could not create PipeWire loop: %s", g_strerror(errno));
|
||||
error_report("Could not create Pipewire loop");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pw->context =
|
||||
pw_context_new(pw_thread_loop_get_loop(pw->thread_loop), NULL, 0);
|
||||
if (pw->context == NULL) {
|
||||
error_report("Could not create PipeWire context: %s", g_strerror(errno));
|
||||
error_report("Could not create Pipewire context");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pw_thread_loop_start(pw->thread_loop) < 0) {
|
||||
error_report("Could not start PipeWire loop: %s", g_strerror(errno));
|
||||
error_report("Could not start Pipewire loop");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -790,8 +844,12 @@ fail:
|
||||
if (pw->thread_loop) {
|
||||
pw_thread_loop_stop(pw->thread_loop);
|
||||
}
|
||||
g_clear_pointer(&pw->context, pw_context_destroy);
|
||||
g_clear_pointer(&pw->thread_loop, pw_thread_loop_destroy);
|
||||
if (pw->context) {
|
||||
g_clear_pointer(&pw->context, pw_context_destroy);
|
||||
}
|
||||
if (pw->thread_loop) {
|
||||
g_clear_pointer(&pw->thread_loop, pw_thread_loop_destroy);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ pw_read(int32_t avail, uint32_t index, size_t len) "avail=%d index=%u len=%zu"
|
||||
pw_write(int32_t filled, int32_t avail, uint32_t index, size_t len) "filled=%d avail=%d index=%u len=%zu"
|
||||
pw_vol(const char *ret) "set volume: %s"
|
||||
pw_period(uint64_t quantum, uint32_t rate) "period =%" PRIu64 "/%u"
|
||||
pw_audio_init(void) "Initialize PipeWire context"
|
||||
pw_audio_init(void) "Initialize Pipewire context"
|
||||
|
||||
# audio.c
|
||||
audio_timer_start(int interval) "interval %d ms"
|
||||
|
||||
@@ -191,11 +191,6 @@ static int cryptodev_backend_account(CryptoDevBackend *backend,
|
||||
if (algtype == QCRYPTODEV_BACKEND_ALG_ASYM) {
|
||||
CryptoDevBackendAsymOpInfo *asym_op_info = op_info->u.asym_op_info;
|
||||
len = asym_op_info->src_len;
|
||||
|
||||
if (unlikely(!backend->asym_stat)) {
|
||||
error_report("cryptodev: Unexpected asym operation");
|
||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||
}
|
||||
switch (op_info->op_code) {
|
||||
case VIRTIO_CRYPTO_AKCIPHER_ENCRYPT:
|
||||
CryptodevAsymStatIncEncrypt(backend, len);
|
||||
@@ -215,11 +210,6 @@ static int cryptodev_backend_account(CryptoDevBackend *backend,
|
||||
} else if (algtype == QCRYPTODEV_BACKEND_ALG_SYM) {
|
||||
CryptoDevBackendSymOpInfo *sym_op_info = op_info->u.sym_op_info;
|
||||
len = sym_op_info->src_len;
|
||||
|
||||
if (unlikely(!backend->sym_stat)) {
|
||||
error_report("cryptodev: Unexpected sym operation");
|
||||
return -VIRTIO_CRYPTO_NOTSUPP;
|
||||
}
|
||||
switch (op_info->op_code) {
|
||||
case VIRTIO_CRYPTO_CIPHER_ENCRYPT:
|
||||
CryptodevSymStatIncEncrypt(backend, len);
|
||||
|
||||
@@ -112,8 +112,12 @@ static int tpm_util_request(int fd,
|
||||
void *response,
|
||||
size_t responselen)
|
||||
{
|
||||
GPollFD fds[1] = { {.fd = fd, .events = G_IO_IN } };
|
||||
fd_set readfds;
|
||||
int n;
|
||||
struct timeval tv = {
|
||||
.tv_sec = 1,
|
||||
.tv_usec = 0,
|
||||
};
|
||||
|
||||
n = write(fd, request, requestlen);
|
||||
if (n < 0) {
|
||||
@@ -123,8 +127,11 @@ static int tpm_util_request(int fd,
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(fd, &readfds);
|
||||
|
||||
/* wait for a second */
|
||||
n = RETRY_ON_EINTR(g_poll(fds, 1, 1000));
|
||||
n = select(fd + 1, &readfds, NULL, NULL, &tv);
|
||||
if (n != 1) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
238
block/blkio.c
238
block/blkio.c
@@ -22,6 +22,16 @@
|
||||
|
||||
#include "block/block-io.h"
|
||||
|
||||
/*
|
||||
* Keep the QEMU BlockDriver names identical to the libblkio driver names.
|
||||
* Using macros instead of typing out the string literals avoids typos.
|
||||
*/
|
||||
#define DRIVER_IO_URING "io_uring"
|
||||
#define DRIVER_NVME_IO_URING "nvme-io_uring"
|
||||
#define DRIVER_VIRTIO_BLK_VFIO_PCI "virtio-blk-vfio-pci"
|
||||
#define DRIVER_VIRTIO_BLK_VHOST_USER "virtio-blk-vhost-user"
|
||||
#define DRIVER_VIRTIO_BLK_VHOST_VDPA "virtio-blk-vhost-vdpa"
|
||||
|
||||
/*
|
||||
* Allocated bounce buffers are kept in a list sorted by buffer address.
|
||||
*/
|
||||
@@ -603,8 +613,8 @@ static void blkio_unregister_buf(BlockDriverState *bs, void *host, size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
static int blkio_io_uring_connect(BlockDriverState *bs, QDict *options,
|
||||
int flags, Error **errp)
|
||||
static int blkio_io_uring_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
const char *filename = qdict_get_str(options, "filename");
|
||||
BDRVBlkioState *s = bs->opaque;
|
||||
@@ -627,18 +637,11 @@ static int blkio_io_uring_connect(BlockDriverState *bs, QDict *options,
|
||||
}
|
||||
}
|
||||
|
||||
ret = blkio_connect(s->blkio);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "blkio_connect failed: %s",
|
||||
blkio_get_error_msg());
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blkio_nvme_io_uring_connect(BlockDriverState *bs, QDict *options,
|
||||
int flags, Error **errp)
|
||||
static int blkio_nvme_io_uring(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
const char *path = qdict_get_try_str(options, "path");
|
||||
BDRVBlkioState *s = bs->opaque;
|
||||
@@ -662,23 +665,16 @@ static int blkio_nvme_io_uring_connect(BlockDriverState *bs, QDict *options,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = blkio_connect(s->blkio);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "blkio_connect failed: %s",
|
||||
blkio_get_error_msg());
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blkio_virtio_blk_connect(BlockDriverState *bs, QDict *options,
|
||||
int flags, Error **errp)
|
||||
static int blkio_virtio_blk_common_open(BlockDriverState *bs,
|
||||
QDict *options, int flags, Error **errp)
|
||||
{
|
||||
const char *path = qdict_get_try_str(options, "path");
|
||||
BDRVBlkioState *s = bs->opaque;
|
||||
bool fd_supported = false;
|
||||
int fd = -1, ret;
|
||||
int fd, ret;
|
||||
|
||||
if (!path) {
|
||||
error_setg(errp, "missing 'path' option");
|
||||
@@ -690,7 +686,7 @@ static int blkio_virtio_blk_connect(BlockDriverState *bs, QDict *options,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (blkio_set_int(s->blkio, "fd", -1) == 0) {
|
||||
if (blkio_get_int(s->blkio, "fd", &fd) == 0) {
|
||||
fd_supported = true;
|
||||
}
|
||||
|
||||
@@ -700,86 +696,33 @@ static int blkio_virtio_blk_connect(BlockDriverState *bs, QDict *options,
|
||||
* layer through the "/dev/fdset/N" special path.
|
||||
*/
|
||||
if (fd_supported) {
|
||||
/*
|
||||
* `path` can contain the path of a character device
|
||||
* (e.g. /dev/vhost-vdpa-0 or /dev/vfio/vfio) or a unix socket.
|
||||
*
|
||||
* So, we should always open it with O_RDWR flag, also if BDRV_O_RDWR
|
||||
* is not set in the open flags, because the exchange of IOCTL commands
|
||||
* for example will fail.
|
||||
*
|
||||
* In order to open the device read-only, we are using the `read-only`
|
||||
* property of the libblkio driver in blkio_file_open().
|
||||
*/
|
||||
fd = qemu_open(path, O_RDWR, NULL);
|
||||
if (fd < 0) {
|
||||
/*
|
||||
* qemu_open() can fail if the user specifies a path that is not
|
||||
* a file or device, for example in the case of Unix Domain Socket
|
||||
* for the virtio-blk-vhost-user driver. In such cases let's have
|
||||
* libblkio open the path directly.
|
||||
*/
|
||||
fd_supported = false;
|
||||
int open_flags;
|
||||
|
||||
if (flags & BDRV_O_RDWR) {
|
||||
open_flags = O_RDWR;
|
||||
} else {
|
||||
ret = blkio_set_int(s->blkio, "fd", fd);
|
||||
if (ret < 0) {
|
||||
fd_supported = false;
|
||||
qemu_close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
open_flags = O_RDONLY;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fd_supported) {
|
||||
ret = blkio_set_str(s->blkio, "path", path);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "failed to set path: %s",
|
||||
blkio_get_error_msg());
|
||||
return ret;
|
||||
fd = qemu_open(path, open_flags, errp);
|
||||
if (fd < 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
ret = blkio_connect(s->blkio);
|
||||
if (ret < 0 && fd >= 0) {
|
||||
/* Failed to give the FD to libblkio, close it */
|
||||
qemu_close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Before https://gitlab.com/libblkio/libblkio/-/merge_requests/208
|
||||
* (libblkio <= v1.3.0), setting the `fd` property is not enough to check
|
||||
* whether the driver supports the `fd` property or not. In that case,
|
||||
* blkio_connect() will fail with -EINVAL.
|
||||
* So let's try calling blkio_connect() again by directly setting `path`
|
||||
* to cover this scenario.
|
||||
*/
|
||||
if (fd_supported && ret == -EINVAL) {
|
||||
/*
|
||||
* We need to clear the `fd` property we set previously by setting
|
||||
* it to -1.
|
||||
*/
|
||||
ret = blkio_set_int(s->blkio, "fd", -1);
|
||||
ret = blkio_set_int(s->blkio, "fd", fd);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "failed to set fd: %s",
|
||||
blkio_get_error_msg());
|
||||
qemu_close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} else {
|
||||
ret = blkio_set_str(s->blkio, "path", path);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "failed to set path: %s",
|
||||
blkio_get_error_msg());
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = blkio_connect(s->blkio);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "blkio_connect failed: %s",
|
||||
blkio_get_error_msg());
|
||||
return ret;
|
||||
}
|
||||
|
||||
qdict_del(options, "path");
|
||||
@@ -801,6 +744,24 @@ static int blkio_file_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (strcmp(blkio_driver, DRIVER_IO_URING) == 0) {
|
||||
ret = blkio_io_uring_open(bs, options, flags, errp);
|
||||
} else if (strcmp(blkio_driver, DRIVER_NVME_IO_URING) == 0) {
|
||||
ret = blkio_nvme_io_uring(bs, options, flags, errp);
|
||||
} else if (strcmp(blkio_driver, DRIVER_VIRTIO_BLK_VFIO_PCI) == 0) {
|
||||
ret = blkio_virtio_blk_common_open(bs, options, flags, errp);
|
||||
} else if (strcmp(blkio_driver, DRIVER_VIRTIO_BLK_VHOST_USER) == 0) {
|
||||
ret = blkio_virtio_blk_common_open(bs, options, flags, errp);
|
||||
} else if (strcmp(blkio_driver, DRIVER_VIRTIO_BLK_VHOST_VDPA) == 0) {
|
||||
ret = blkio_virtio_blk_common_open(bs, options, flags, errp);
|
||||
} else {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
if (ret < 0) {
|
||||
blkio_destroy(&s->blkio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!(flags & BDRV_O_RDWR)) {
|
||||
ret = blkio_set_bool(s->blkio, "read-only", true);
|
||||
if (ret < 0) {
|
||||
@@ -811,20 +772,10 @@ static int blkio_file_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(blkio_driver, "io_uring") == 0) {
|
||||
ret = blkio_io_uring_connect(bs, options, flags, errp);
|
||||
} else if (strcmp(blkio_driver, "nvme-io_uring") == 0) {
|
||||
ret = blkio_nvme_io_uring_connect(bs, options, flags, errp);
|
||||
} else if (strcmp(blkio_driver, "virtio-blk-vfio-pci") == 0) {
|
||||
ret = blkio_virtio_blk_connect(bs, options, flags, errp);
|
||||
} else if (strcmp(blkio_driver, "virtio-blk-vhost-user") == 0) {
|
||||
ret = blkio_virtio_blk_connect(bs, options, flags, errp);
|
||||
} else if (strcmp(blkio_driver, "virtio-blk-vhost-vdpa") == 0) {
|
||||
ret = blkio_virtio_blk_connect(bs, options, flags, errp);
|
||||
} else {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
ret = blkio_connect(s->blkio);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "blkio_connect failed: %s",
|
||||
blkio_get_error_msg());
|
||||
blkio_destroy(&s->blkio);
|
||||
return ret;
|
||||
}
|
||||
@@ -904,7 +855,6 @@ static int blkio_file_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
QLIST_INIT(&s->bounce_bufs);
|
||||
s->blkioq = blkio_get_queue(s->blkio, 0);
|
||||
s->completion_fd = blkioq_get_completion_fd(s->blkioq);
|
||||
blkioq_set_completion_fd_enabled(s->blkioq, true);
|
||||
|
||||
blkio_attach_aio_context(bs, bdrv_get_aio_context(bs));
|
||||
return 0;
|
||||
@@ -1078,63 +1028,49 @@ static void blkio_refresh_limits(BlockDriverState *bs, Error **errp)
|
||||
* - truncate
|
||||
*/
|
||||
|
||||
/*
|
||||
* Do not include .format_name and .protocol_name because module_block.py
|
||||
* does not parse macros in the source code.
|
||||
*/
|
||||
#define BLKIO_DRIVER_COMMON \
|
||||
.instance_size = sizeof(BDRVBlkioState), \
|
||||
.bdrv_file_open = blkio_file_open, \
|
||||
.bdrv_close = blkio_close, \
|
||||
.bdrv_co_getlength = blkio_co_getlength, \
|
||||
.bdrv_co_truncate = blkio_truncate, \
|
||||
.bdrv_co_get_info = blkio_co_get_info, \
|
||||
.bdrv_attach_aio_context = blkio_attach_aio_context, \
|
||||
.bdrv_detach_aio_context = blkio_detach_aio_context, \
|
||||
.bdrv_co_pdiscard = blkio_co_pdiscard, \
|
||||
.bdrv_co_preadv = blkio_co_preadv, \
|
||||
.bdrv_co_pwritev = blkio_co_pwritev, \
|
||||
.bdrv_co_flush_to_disk = blkio_co_flush, \
|
||||
.bdrv_co_pwrite_zeroes = blkio_co_pwrite_zeroes, \
|
||||
.bdrv_refresh_limits = blkio_refresh_limits, \
|
||||
.bdrv_register_buf = blkio_register_buf, \
|
||||
.bdrv_unregister_buf = blkio_unregister_buf,
|
||||
#define BLKIO_DRIVER(name, ...) \
|
||||
{ \
|
||||
.format_name = name, \
|
||||
.protocol_name = name, \
|
||||
.instance_size = sizeof(BDRVBlkioState), \
|
||||
.bdrv_file_open = blkio_file_open, \
|
||||
.bdrv_close = blkio_close, \
|
||||
.bdrv_co_getlength = blkio_co_getlength, \
|
||||
.bdrv_co_truncate = blkio_truncate, \
|
||||
.bdrv_co_get_info = blkio_co_get_info, \
|
||||
.bdrv_attach_aio_context = blkio_attach_aio_context, \
|
||||
.bdrv_detach_aio_context = blkio_detach_aio_context, \
|
||||
.bdrv_co_pdiscard = blkio_co_pdiscard, \
|
||||
.bdrv_co_preadv = blkio_co_preadv, \
|
||||
.bdrv_co_pwritev = blkio_co_pwritev, \
|
||||
.bdrv_co_flush_to_disk = blkio_co_flush, \
|
||||
.bdrv_co_pwrite_zeroes = blkio_co_pwrite_zeroes, \
|
||||
.bdrv_refresh_limits = blkio_refresh_limits, \
|
||||
.bdrv_register_buf = blkio_register_buf, \
|
||||
.bdrv_unregister_buf = blkio_unregister_buf, \
|
||||
__VA_ARGS__ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the same .format_name and .protocol_name as the libblkio driver name for
|
||||
* consistency.
|
||||
*/
|
||||
|
||||
static BlockDriver bdrv_io_uring = {
|
||||
.format_name = "io_uring",
|
||||
.protocol_name = "io_uring",
|
||||
static BlockDriver bdrv_io_uring = BLKIO_DRIVER(
|
||||
DRIVER_IO_URING,
|
||||
.bdrv_needs_filename = true,
|
||||
BLKIO_DRIVER_COMMON
|
||||
};
|
||||
);
|
||||
|
||||
static BlockDriver bdrv_nvme_io_uring = {
|
||||
.format_name = "nvme-io_uring",
|
||||
.protocol_name = "nvme-io_uring",
|
||||
BLKIO_DRIVER_COMMON
|
||||
};
|
||||
static BlockDriver bdrv_nvme_io_uring = BLKIO_DRIVER(
|
||||
DRIVER_NVME_IO_URING,
|
||||
);
|
||||
|
||||
static BlockDriver bdrv_virtio_blk_vfio_pci = {
|
||||
.format_name = "virtio-blk-vfio-pci",
|
||||
.protocol_name = "virtio-blk-vfio-pci",
|
||||
BLKIO_DRIVER_COMMON
|
||||
};
|
||||
static BlockDriver bdrv_virtio_blk_vfio_pci = BLKIO_DRIVER(
|
||||
DRIVER_VIRTIO_BLK_VFIO_PCI
|
||||
);
|
||||
|
||||
static BlockDriver bdrv_virtio_blk_vhost_user = {
|
||||
.format_name = "virtio-blk-vhost-user",
|
||||
.protocol_name = "virtio-blk-vhost-user",
|
||||
BLKIO_DRIVER_COMMON
|
||||
};
|
||||
static BlockDriver bdrv_virtio_blk_vhost_user = BLKIO_DRIVER(
|
||||
DRIVER_VIRTIO_BLK_VHOST_USER
|
||||
);
|
||||
|
||||
static BlockDriver bdrv_virtio_blk_vhost_vdpa = {
|
||||
.format_name = "virtio-blk-vhost-vdpa",
|
||||
.protocol_name = "virtio-blk-vhost-vdpa",
|
||||
BLKIO_DRIVER_COMMON
|
||||
};
|
||||
static BlockDriver bdrv_virtio_blk_vhost_vdpa = BLKIO_DRIVER(
|
||||
DRIVER_VIRTIO_BLK_VHOST_VDPA
|
||||
);
|
||||
|
||||
static void bdrv_blkio_init(void)
|
||||
{
|
||||
|
||||
@@ -1232,6 +1232,7 @@ static int hdev_get_max_hw_transfer(int fd, struct stat *st)
|
||||
static int get_sysfs_str_val(struct stat *st, const char *attribute,
|
||||
char **val) {
|
||||
g_autofree char *sysfspath = NULL;
|
||||
int ret;
|
||||
size_t len;
|
||||
|
||||
if (!S_ISBLK(st->st_mode)) {
|
||||
@@ -1241,7 +1242,8 @@ static int get_sysfs_str_val(struct stat *st, const char *attribute,
|
||||
sysfspath = g_strdup_printf("/sys/dev/block/%u:%u/queue/%s",
|
||||
major(st->st_rdev), minor(st->st_rdev),
|
||||
attribute);
|
||||
if (!g_file_get_contents(sysfspath, val, &len, NULL)) {
|
||||
ret = g_file_get_contents(sysfspath, val, &len, NULL);
|
||||
if (ret == -1) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
@@ -1251,7 +1253,7 @@ static int get_sysfs_str_val(struct stat *st, const char *attribute,
|
||||
if (*(p + len - 1) == '\n') {
|
||||
*(p + len - 1) = '\0';
|
||||
}
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1412,9 +1414,11 @@ static void raw_refresh_zoned_limits(BlockDriverState *bs, struct stat *st,
|
||||
BlockZoneModel zoned;
|
||||
int ret;
|
||||
|
||||
bs->bl.zoned = BLK_Z_NONE;
|
||||
|
||||
ret = get_sysfs_zoned_model(st, &zoned);
|
||||
if (ret < 0 || zoned == BLK_Z_NONE) {
|
||||
goto no_zoned;
|
||||
return;
|
||||
}
|
||||
bs->bl.zoned = zoned;
|
||||
|
||||
@@ -1435,10 +1439,10 @@ static void raw_refresh_zoned_limits(BlockDriverState *bs, struct stat *st,
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Unable to read chunk_sectors "
|
||||
"sysfs attribute");
|
||||
goto no_zoned;
|
||||
return;
|
||||
} else if (!ret) {
|
||||
error_setg(errp, "Read 0 from chunk_sectors sysfs attribute");
|
||||
goto no_zoned;
|
||||
return;
|
||||
}
|
||||
bs->bl.zone_size = ret << BDRV_SECTOR_BITS;
|
||||
|
||||
@@ -1446,10 +1450,10 @@ static void raw_refresh_zoned_limits(BlockDriverState *bs, struct stat *st,
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Unable to read nr_zones "
|
||||
"sysfs attribute");
|
||||
goto no_zoned;
|
||||
return;
|
||||
} else if (!ret) {
|
||||
error_setg(errp, "Read 0 from nr_zones sysfs attribute");
|
||||
goto no_zoned;
|
||||
return;
|
||||
}
|
||||
bs->bl.nr_zones = ret;
|
||||
|
||||
@@ -1470,15 +1474,10 @@ static void raw_refresh_zoned_limits(BlockDriverState *bs, struct stat *st,
|
||||
ret = get_zones_wp(bs, s->fd, 0, bs->bl.nr_zones, 0);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "report wps failed");
|
||||
goto no_zoned;
|
||||
bs->wps = NULL;
|
||||
return;
|
||||
}
|
||||
qemu_co_mutex_init(&bs->wps->colock);
|
||||
return;
|
||||
|
||||
no_zoned:
|
||||
bs->bl.zoned = BLK_Z_NONE;
|
||||
g_free(bs->wps);
|
||||
bs->wps = NULL;
|
||||
}
|
||||
#else /* !defined(CONFIG_BLKZONED) */
|
||||
static void raw_refresh_zoned_limits(BlockDriverState *bs, struct stat *st,
|
||||
@@ -2455,10 +2454,9 @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
|
||||
if (fd_open(bs) < 0)
|
||||
return -EIO;
|
||||
#if defined(CONFIG_BLKZONED)
|
||||
if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) &&
|
||||
bs->bl.zoned != BLK_Z_NONE) {
|
||||
if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) && bs->wps) {
|
||||
qemu_co_mutex_lock(&bs->wps->colock);
|
||||
if (type & QEMU_AIO_ZONE_APPEND) {
|
||||
if (type & QEMU_AIO_ZONE_APPEND && bs->bl.zone_size) {
|
||||
int index = offset / bs->bl.zone_size;
|
||||
offset = bs->wps->wp[index];
|
||||
}
|
||||
@@ -2506,10 +2504,11 @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
|
||||
|
||||
out:
|
||||
#if defined(CONFIG_BLKZONED)
|
||||
if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) &&
|
||||
bs->bl.zoned != BLK_Z_NONE) {
|
||||
BlockZoneWps *wps = bs->wps;
|
||||
if (ret == 0) {
|
||||
{
|
||||
BlockZoneWps *wps = bs->wps;
|
||||
if (ret == 0) {
|
||||
if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND))
|
||||
&& wps && bs->bl.zone_size) {
|
||||
uint64_t *wp = &wps->wp[offset / bs->bl.zone_size];
|
||||
if (!BDRV_ZT_IS_CONV(*wp)) {
|
||||
if (type & QEMU_AIO_ZONE_APPEND) {
|
||||
@@ -2522,12 +2521,17 @@ out:
|
||||
*wp = offset + bytes;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
if (type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) {
|
||||
update_zones_wp(bs, s->fd, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) && wps) {
|
||||
qemu_co_mutex_unlock(&wps->colock);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1710,11 +1710,7 @@ static int bdrv_pad_request(BlockDriverState *bs,
|
||||
int sliced_niov;
|
||||
size_t sliced_head, sliced_tail;
|
||||
|
||||
/* Should have been checked by the caller already */
|
||||
ret = bdrv_check_request32(*offset, *bytes, *qiov, *qiov_offset);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
bdrv_check_qiov_request(*offset, *bytes, *qiov, *qiov_offset, &error_abort);
|
||||
|
||||
if (!bdrv_init_padding(bs, *offset, *bytes, write, pad)) {
|
||||
if (padded) {
|
||||
@@ -1727,7 +1723,7 @@ static int bdrv_pad_request(BlockDriverState *bs,
|
||||
&sliced_head, &sliced_tail,
|
||||
&sliced_niov);
|
||||
|
||||
/* Guaranteed by bdrv_check_request32() */
|
||||
/* Guaranteed by bdrv_check_qiov_request() */
|
||||
assert(*bytes <= SIZE_MAX);
|
||||
ret = bdrv_create_padded_qiov(bs, pad, sliced_iov, sliced_niov,
|
||||
sliced_head, *bytes);
|
||||
|
||||
96
block/nbd.c
96
block/nbd.c
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* QEMU Block driver for NBD
|
||||
* QEMU Block driver for NBD
|
||||
*
|
||||
* Copyright (c) 2019 Virtuozzo International GmbH.
|
||||
* Copyright Red Hat
|
||||
* Copyright (C) 2016 Red Hat, Inc.
|
||||
* Copyright (C) 2008 Bull S.A.S.
|
||||
* Author: Laurent Vivier <Laurent.Vivier@bull.net>
|
||||
*
|
||||
@@ -50,8 +50,8 @@
|
||||
#define EN_OPTSTR ":exportname="
|
||||
#define MAX_NBD_REQUESTS 16
|
||||
|
||||
#define COOKIE_TO_INDEX(cookie) ((cookie) - 1)
|
||||
#define INDEX_TO_COOKIE(index) ((index) + 1)
|
||||
#define HANDLE_TO_INDEX(bs, handle) ((handle) ^ (uint64_t)(intptr_t)(bs))
|
||||
#define INDEX_TO_HANDLE(bs, index) ((index) ^ (uint64_t)(intptr_t)(bs))
|
||||
|
||||
typedef struct {
|
||||
Coroutine *coroutine;
|
||||
@@ -417,25 +417,25 @@ static void coroutine_fn GRAPH_RDLOCK nbd_reconnect_attempt(BDRVNBDState *s)
|
||||
reconnect_delay_timer_del(s);
|
||||
}
|
||||
|
||||
static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie)
|
||||
static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t handle)
|
||||
{
|
||||
int ret;
|
||||
uint64_t ind = COOKIE_TO_INDEX(cookie), ind2;
|
||||
uint64_t ind = HANDLE_TO_INDEX(s, handle), ind2;
|
||||
QEMU_LOCK_GUARD(&s->receive_mutex);
|
||||
|
||||
while (true) {
|
||||
if (s->reply.cookie == cookie) {
|
||||
if (s->reply.handle == handle) {
|
||||
/* We are done */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (s->reply.cookie != 0) {
|
||||
if (s->reply.handle != 0) {
|
||||
/*
|
||||
* Some other request is being handled now. It should already be
|
||||
* woken by whoever set s->reply.cookie (or never wait in this
|
||||
* woken by whoever set s->reply.handle (or never wait in this
|
||||
* yield). So, we should not wake it here.
|
||||
*/
|
||||
ind2 = COOKIE_TO_INDEX(s->reply.cookie);
|
||||
ind2 = HANDLE_TO_INDEX(s, s->reply.handle);
|
||||
assert(!s->requests[ind2].receiving);
|
||||
|
||||
s->requests[ind].receiving = true;
|
||||
@@ -445,9 +445,9 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie)
|
||||
/*
|
||||
* We may be woken for 2 reasons:
|
||||
* 1. From this function, executing in parallel coroutine, when our
|
||||
* cookie is received.
|
||||
* handle is received.
|
||||
* 2. From nbd_co_receive_one_chunk(), when previous request is
|
||||
* finished and s->reply.cookie set to 0.
|
||||
* finished and s->reply.handle set to 0.
|
||||
* Anyway, it's OK to lock the mutex and go to the next iteration.
|
||||
*/
|
||||
|
||||
@@ -456,8 +456,8 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We are under mutex and cookie is 0. We have to do the dirty work. */
|
||||
assert(s->reply.cookie == 0);
|
||||
/* We are under mutex and handle is 0. We have to do the dirty work. */
|
||||
assert(s->reply.handle == 0);
|
||||
ret = nbd_receive_reply(s->bs, s->ioc, &s->reply, NULL);
|
||||
if (ret <= 0) {
|
||||
ret = ret ? ret : -EIO;
|
||||
@@ -468,12 +468,12 @@ static coroutine_fn int nbd_receive_replies(BDRVNBDState *s, uint64_t cookie)
|
||||
nbd_channel_error(s, -EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
ind2 = COOKIE_TO_INDEX(s->reply.cookie);
|
||||
ind2 = HANDLE_TO_INDEX(s, s->reply.handle);
|
||||
if (ind2 >= MAX_NBD_REQUESTS || !s->requests[ind2].coroutine) {
|
||||
nbd_channel_error(s, -EINVAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (s->reply.cookie == cookie) {
|
||||
if (s->reply.handle == handle) {
|
||||
/* We are done */
|
||||
return 0;
|
||||
}
|
||||
@@ -519,7 +519,7 @@ nbd_co_send_request(BlockDriverState *bs, NBDRequest *request,
|
||||
qemu_mutex_unlock(&s->requests_lock);
|
||||
|
||||
qemu_co_mutex_lock(&s->send_mutex);
|
||||
request->cookie = INDEX_TO_COOKIE(i);
|
||||
request->handle = INDEX_TO_HANDLE(s, i);
|
||||
|
||||
assert(s->ioc);
|
||||
|
||||
@@ -828,11 +828,11 @@ static coroutine_fn int nbd_co_receive_structured_payload(
|
||||
* corresponding to the server's error reply), and errp is unchanged.
|
||||
*/
|
||||
static coroutine_fn int nbd_co_do_receive_one_chunk(
|
||||
BDRVNBDState *s, uint64_t cookie, bool only_structured,
|
||||
BDRVNBDState *s, uint64_t handle, bool only_structured,
|
||||
int *request_ret, QEMUIOVector *qiov, void **payload, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
int i = COOKIE_TO_INDEX(cookie);
|
||||
int i = HANDLE_TO_INDEX(s, handle);
|
||||
void *local_payload = NULL;
|
||||
NBDStructuredReplyChunk *chunk;
|
||||
|
||||
@@ -841,14 +841,14 @@ static coroutine_fn int nbd_co_do_receive_one_chunk(
|
||||
}
|
||||
*request_ret = 0;
|
||||
|
||||
ret = nbd_receive_replies(s, cookie);
|
||||
ret = nbd_receive_replies(s, handle);
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "Connection closed");
|
||||
return -EIO;
|
||||
}
|
||||
assert(s->ioc);
|
||||
|
||||
assert(s->reply.cookie == cookie);
|
||||
assert(s->reply.handle == handle);
|
||||
|
||||
if (nbd_reply_is_simple(&s->reply)) {
|
||||
if (only_structured) {
|
||||
@@ -918,11 +918,11 @@ static coroutine_fn int nbd_co_do_receive_one_chunk(
|
||||
* Return value is a fatal error code or normal nbd reply error code
|
||||
*/
|
||||
static coroutine_fn int nbd_co_receive_one_chunk(
|
||||
BDRVNBDState *s, uint64_t cookie, bool only_structured,
|
||||
BDRVNBDState *s, uint64_t handle, bool only_structured,
|
||||
int *request_ret, QEMUIOVector *qiov, NBDReply *reply, void **payload,
|
||||
Error **errp)
|
||||
{
|
||||
int ret = nbd_co_do_receive_one_chunk(s, cookie, only_structured,
|
||||
int ret = nbd_co_do_receive_one_chunk(s, handle, only_structured,
|
||||
request_ret, qiov, payload, errp);
|
||||
|
||||
if (ret < 0) {
|
||||
@@ -932,7 +932,7 @@ static coroutine_fn int nbd_co_receive_one_chunk(
|
||||
/* For assert at loop start in nbd_connection_entry */
|
||||
*reply = s->reply;
|
||||
}
|
||||
s->reply.cookie = 0;
|
||||
s->reply.handle = 0;
|
||||
|
||||
nbd_recv_coroutines_wake(s);
|
||||
|
||||
@@ -975,10 +975,10 @@ static void nbd_iter_request_error(NBDReplyChunkIter *iter, int ret)
|
||||
* NBD_FOREACH_REPLY_CHUNK
|
||||
* The pointer stored in @payload requires g_free() to free it.
|
||||
*/
|
||||
#define NBD_FOREACH_REPLY_CHUNK(s, iter, cookie, structured, \
|
||||
#define NBD_FOREACH_REPLY_CHUNK(s, iter, handle, structured, \
|
||||
qiov, reply, payload) \
|
||||
for (iter = (NBDReplyChunkIter) { .only_structured = structured }; \
|
||||
nbd_reply_chunk_iter_receive(s, &iter, cookie, qiov, reply, payload);)
|
||||
nbd_reply_chunk_iter_receive(s, &iter, handle, qiov, reply, payload);)
|
||||
|
||||
/*
|
||||
* nbd_reply_chunk_iter_receive
|
||||
@@ -986,7 +986,7 @@ static void nbd_iter_request_error(NBDReplyChunkIter *iter, int ret)
|
||||
*/
|
||||
static bool coroutine_fn nbd_reply_chunk_iter_receive(BDRVNBDState *s,
|
||||
NBDReplyChunkIter *iter,
|
||||
uint64_t cookie,
|
||||
uint64_t handle,
|
||||
QEMUIOVector *qiov,
|
||||
NBDReply *reply,
|
||||
void **payload)
|
||||
@@ -1005,7 +1005,7 @@ static bool coroutine_fn nbd_reply_chunk_iter_receive(BDRVNBDState *s,
|
||||
reply = &local_reply;
|
||||
}
|
||||
|
||||
ret = nbd_co_receive_one_chunk(s, cookie, iter->only_structured,
|
||||
ret = nbd_co_receive_one_chunk(s, handle, iter->only_structured,
|
||||
&request_ret, qiov, reply, payload,
|
||||
&local_err);
|
||||
if (ret < 0) {
|
||||
@@ -1038,7 +1038,7 @@ static bool coroutine_fn nbd_reply_chunk_iter_receive(BDRVNBDState *s,
|
||||
|
||||
break_loop:
|
||||
qemu_mutex_lock(&s->requests_lock);
|
||||
s->requests[COOKIE_TO_INDEX(cookie)].coroutine = NULL;
|
||||
s->requests[HANDLE_TO_INDEX(s, handle)].coroutine = NULL;
|
||||
s->in_flight--;
|
||||
qemu_co_queue_next(&s->free_sema);
|
||||
qemu_mutex_unlock(&s->requests_lock);
|
||||
@@ -1046,13 +1046,12 @@ break_loop:
|
||||
return false;
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
nbd_co_receive_return_code(BDRVNBDState *s, uint64_t cookie,
|
||||
int *request_ret, Error **errp)
|
||||
static int coroutine_fn nbd_co_receive_return_code(BDRVNBDState *s, uint64_t handle,
|
||||
int *request_ret, Error **errp)
|
||||
{
|
||||
NBDReplyChunkIter iter;
|
||||
|
||||
NBD_FOREACH_REPLY_CHUNK(s, iter, cookie, false, NULL, NULL, NULL) {
|
||||
NBD_FOREACH_REPLY_CHUNK(s, iter, handle, false, NULL, NULL, NULL) {
|
||||
/* nbd_reply_chunk_iter_receive does all the work */
|
||||
}
|
||||
|
||||
@@ -1061,17 +1060,16 @@ nbd_co_receive_return_code(BDRVNBDState *s, uint64_t cookie,
|
||||
return iter.ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
nbd_co_receive_cmdread_reply(BDRVNBDState *s, uint64_t cookie,
|
||||
uint64_t offset, QEMUIOVector *qiov,
|
||||
int *request_ret, Error **errp)
|
||||
static int coroutine_fn nbd_co_receive_cmdread_reply(BDRVNBDState *s, uint64_t handle,
|
||||
uint64_t offset, QEMUIOVector *qiov,
|
||||
int *request_ret, Error **errp)
|
||||
{
|
||||
NBDReplyChunkIter iter;
|
||||
NBDReply reply;
|
||||
void *payload = NULL;
|
||||
Error *local_err = NULL;
|
||||
|
||||
NBD_FOREACH_REPLY_CHUNK(s, iter, cookie, s->info.structured_reply,
|
||||
NBD_FOREACH_REPLY_CHUNK(s, iter, handle, s->info.structured_reply,
|
||||
qiov, &reply, &payload)
|
||||
{
|
||||
int ret;
|
||||
@@ -1114,10 +1112,10 @@ nbd_co_receive_cmdread_reply(BDRVNBDState *s, uint64_t cookie,
|
||||
return iter.ret;
|
||||
}
|
||||
|
||||
static int coroutine_fn
|
||||
nbd_co_receive_blockstatus_reply(BDRVNBDState *s, uint64_t cookie,
|
||||
uint64_t length, NBDExtent *extent,
|
||||
int *request_ret, Error **errp)
|
||||
static int coroutine_fn nbd_co_receive_blockstatus_reply(BDRVNBDState *s,
|
||||
uint64_t handle, uint64_t length,
|
||||
NBDExtent *extent,
|
||||
int *request_ret, Error **errp)
|
||||
{
|
||||
NBDReplyChunkIter iter;
|
||||
NBDReply reply;
|
||||
@@ -1126,7 +1124,7 @@ nbd_co_receive_blockstatus_reply(BDRVNBDState *s, uint64_t cookie,
|
||||
bool received = false;
|
||||
|
||||
assert(!extent->length);
|
||||
NBD_FOREACH_REPLY_CHUNK(s, iter, cookie, false, NULL, &reply, &payload) {
|
||||
NBD_FOREACH_REPLY_CHUNK(s, iter, handle, false, NULL, &reply, &payload) {
|
||||
int ret;
|
||||
NBDStructuredReplyChunk *chunk = &reply.structured;
|
||||
|
||||
@@ -1196,11 +1194,11 @@ nbd_co_request(BlockDriverState *bs, NBDRequest *request,
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = nbd_co_receive_return_code(s, request->cookie,
|
||||
ret = nbd_co_receive_return_code(s, request->handle,
|
||||
&request_ret, &local_err);
|
||||
if (local_err) {
|
||||
trace_nbd_co_request_fail(request->from, request->len,
|
||||
request->cookie, request->flags,
|
||||
request->handle, request->flags,
|
||||
request->type,
|
||||
nbd_cmd_lookup(request->type),
|
||||
ret, error_get_pretty(local_err));
|
||||
@@ -1255,10 +1253,10 @@ nbd_client_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = nbd_co_receive_cmdread_reply(s, request.cookie, offset, qiov,
|
||||
ret = nbd_co_receive_cmdread_reply(s, request.handle, offset, qiov,
|
||||
&request_ret, &local_err);
|
||||
if (local_err) {
|
||||
trace_nbd_co_request_fail(request.from, request.len, request.cookie,
|
||||
trace_nbd_co_request_fail(request.from, request.len, request.handle,
|
||||
request.flags, request.type,
|
||||
nbd_cmd_lookup(request.type),
|
||||
ret, error_get_pretty(local_err));
|
||||
@@ -1413,11 +1411,11 @@ static int coroutine_fn GRAPH_RDLOCK nbd_client_co_block_status(
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = nbd_co_receive_blockstatus_reply(s, request.cookie, bytes,
|
||||
ret = nbd_co_receive_blockstatus_reply(s, request.handle, bytes,
|
||||
&extent, &request_ret,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
trace_nbd_co_request_fail(request.from, request.len, request.cookie,
|
||||
trace_nbd_co_request_fail(request.from, request.len, request.handle,
|
||||
request.flags, request.type,
|
||||
nbd_cmd_lookup(request.type),
|
||||
ret, error_get_pretty(local_err));
|
||||
|
||||
@@ -501,9 +501,8 @@ static void nvme_submit_command(NVMeQueuePair *q, NVMeRequest *req,
|
||||
q->sq.tail * NVME_SQ_ENTRY_BYTES, cmd, sizeof(*cmd));
|
||||
q->sq.tail = (q->sq.tail + 1) % NVME_QUEUE_SIZE;
|
||||
q->need_kick++;
|
||||
qemu_mutex_unlock(&q->lock);
|
||||
|
||||
blk_io_plug_call(nvme_unplug_fn, q);
|
||||
qemu_mutex_unlock(&q->lock);
|
||||
}
|
||||
|
||||
static void nvme_admin_cmd_sync_cb(void *opaque, int ret)
|
||||
|
||||
@@ -473,6 +473,10 @@ int main(int argc, char **argv)
|
||||
target_environ = envlist_to_environ(envlist, NULL);
|
||||
envlist_free(envlist);
|
||||
|
||||
if (reserved_va) {
|
||||
mmap_next_start = reserved_va + 1;
|
||||
}
|
||||
|
||||
{
|
||||
Error *err = NULL;
|
||||
if (seed_optarg != NULL) {
|
||||
@@ -490,49 +494,7 @@ int main(int argc, char **argv)
|
||||
* Now that page sizes are configured we can do
|
||||
* proper page alignment for guest_base.
|
||||
*/
|
||||
if (have_guest_base) {
|
||||
if (guest_base & ~qemu_host_page_mask) {
|
||||
error_report("Selected guest base not host page aligned");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If reserving host virtual address space, do so now.
|
||||
* Combined with '-B', ensure that the chosen range is free.
|
||||
*/
|
||||
if (reserved_va) {
|
||||
void *p;
|
||||
|
||||
if (have_guest_base) {
|
||||
p = mmap((void *)guest_base, reserved_va + 1, PROT_NONE,
|
||||
MAP_ANON | MAP_PRIVATE | MAP_FIXED | MAP_EXCL, -1, 0);
|
||||
} else {
|
||||
p = mmap(NULL, reserved_va + 1, PROT_NONE,
|
||||
MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
}
|
||||
if (p == MAP_FAILED) {
|
||||
const char *err = strerror(errno);
|
||||
char *sz = size_to_str(reserved_va + 1);
|
||||
|
||||
if (have_guest_base) {
|
||||
error_report("Cannot allocate %s bytes at -B %p for guest "
|
||||
"address space: %s", sz, (void *)guest_base, err);
|
||||
} else {
|
||||
error_report("Cannot allocate %s bytes for guest "
|
||||
"address space: %s", sz, err);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
guest_base = (uintptr_t)p;
|
||||
have_guest_base = true;
|
||||
|
||||
/* Ensure that mmap_next_start is within range. */
|
||||
if (reserved_va <= mmap_next_start) {
|
||||
mmap_next_start = (reserved_va / 4 * 3)
|
||||
& TARGET_PAGE_MASK & qemu_host_page_mask;
|
||||
}
|
||||
}
|
||||
guest_base = HOST_PAGE_ALIGN(guest_base);
|
||||
|
||||
if (loader_exec(filename, argv + optind, target_environ, regs, info,
|
||||
&bprm) != 0) {
|
||||
|
||||
@@ -32,7 +32,6 @@ void mmap_lock(void)
|
||||
|
||||
void mmap_unlock(void)
|
||||
{
|
||||
assert(mmap_lock_count > 0);
|
||||
if (--mmap_lock_count == 0) {
|
||||
pthread_mutex_unlock(&mmap_mutex);
|
||||
}
|
||||
@@ -214,6 +213,8 @@ static int mmap_frag(abi_ulong real_start,
|
||||
#endif
|
||||
abi_ulong mmap_next_start = TASK_UNMAPPED_BASE;
|
||||
|
||||
unsigned long last_brk;
|
||||
|
||||
/*
|
||||
* Subroutine of mmap_find_vma, used when we have pre-allocated a chunk of guest
|
||||
* address space.
|
||||
@@ -221,16 +222,50 @@ abi_ulong mmap_next_start = TASK_UNMAPPED_BASE;
|
||||
static abi_ulong mmap_find_vma_reserved(abi_ulong start, abi_ulong size,
|
||||
abi_ulong alignment)
|
||||
{
|
||||
abi_ulong ret;
|
||||
abi_ulong addr;
|
||||
abi_ulong end_addr;
|
||||
int prot;
|
||||
int looped = 0;
|
||||
|
||||
ret = page_find_range_empty(start, reserved_va, size, alignment);
|
||||
if (ret == -1 && start > TARGET_PAGE_SIZE) {
|
||||
/* Restart at the beginning of the address space. */
|
||||
ret = page_find_range_empty(TARGET_PAGE_SIZE, start - 1,
|
||||
size, alignment);
|
||||
if (size > reserved_va) {
|
||||
return (abi_ulong)-1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
size = HOST_PAGE_ALIGN(size) + alignment;
|
||||
end_addr = start + size;
|
||||
if (end_addr > reserved_va) {
|
||||
end_addr = reserved_va + 1;
|
||||
}
|
||||
addr = end_addr - qemu_host_page_size;
|
||||
|
||||
while (1) {
|
||||
if (addr > end_addr) {
|
||||
if (looped) {
|
||||
return (abi_ulong)-1;
|
||||
}
|
||||
end_addr = reserved_va + 1;
|
||||
addr = end_addr - qemu_host_page_size;
|
||||
looped = 1;
|
||||
continue;
|
||||
}
|
||||
prot = page_get_flags(addr);
|
||||
if (prot) {
|
||||
end_addr = addr;
|
||||
}
|
||||
if (end_addr - addr >= size) {
|
||||
break;
|
||||
}
|
||||
addr -= qemu_host_page_size;
|
||||
}
|
||||
|
||||
if (start == mmap_next_start) {
|
||||
mmap_next_start = addr;
|
||||
}
|
||||
/* addr is sufficiently low to align it up */
|
||||
if (alignment != 0) {
|
||||
addr = (addr + alignment) & ~(alignment - 1);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -258,8 +293,7 @@ static abi_ulong mmap_find_vma_aligned(abi_ulong start, abi_ulong size,
|
||||
|
||||
if (reserved_va) {
|
||||
return mmap_find_vma_reserved(start, size,
|
||||
(alignment != 0 ? 1 << alignment :
|
||||
MAX(qemu_host_page_size, TARGET_PAGE_SIZE)));
|
||||
(alignment != 0 ? 1 << alignment : 0));
|
||||
}
|
||||
|
||||
addr = start;
|
||||
@@ -575,7 +609,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
|
||||
}
|
||||
|
||||
/* Reject the mapping if any page within the range is mapped */
|
||||
if ((flags & MAP_EXCL) && !page_check_range_empty(start, end - 1)) {
|
||||
if ((flags & MAP_EXCL) && page_check_range(start, len, 0) < 0) {
|
||||
errno = EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -232,6 +232,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
|
||||
abi_ulong new_size, unsigned long flags,
|
||||
abi_ulong new_addr);
|
||||
int target_msync(abi_ulong start, abi_ulong len, int flags);
|
||||
extern unsigned long last_brk;
|
||||
extern abi_ulong mmap_next_start;
|
||||
abi_ulong mmap_find_vma(abi_ulong start, abi_ulong size);
|
||||
void TSA_NO_TSA mmap_fork_start(void);
|
||||
@@ -266,7 +267,7 @@ abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2);
|
||||
|
||||
static inline bool access_ok(int type, abi_ulong addr, abi_ulong size)
|
||||
{
|
||||
return page_check_range((target_ulong)addr, size, type);
|
||||
return page_check_range((target_ulong)addr, size, type) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -227,9 +227,7 @@ type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
|
||||
}
|
||||
|
||||
/* So far all target and host bitmasks are the same */
|
||||
#undef target_to_host_bitmask
|
||||
#define target_to_host_bitmask(x, tbl) (x)
|
||||
#undef host_to_target_bitmask
|
||||
#define host_to_target_bitmask(x, tbl) (x)
|
||||
|
||||
#endif /* SYSCALL_DEFS_H */
|
||||
|
||||
@@ -106,27 +106,11 @@ static void pty_chr_update_read_handler(Chardev *chr)
|
||||
static int char_pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||
{
|
||||
PtyChardev *s = PTY_CHARDEV(chr);
|
||||
GPollFD pfd;
|
||||
int rc;
|
||||
|
||||
if (s->connected) {
|
||||
return io_channel_send(s->ioc, buf, len);
|
||||
if (!s->connected) {
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* The other side might already be re-connected, but the timer might
|
||||
* not have fired yet. So let's check here whether we can write again:
|
||||
*/
|
||||
pfd.fd = QIO_CHANNEL_FILE(s->ioc)->fd;
|
||||
pfd.events = G_IO_OUT;
|
||||
pfd.revents = 0;
|
||||
rc = RETRY_ON_EINTR(g_poll(&pfd, 1, 0));
|
||||
g_assert(rc >= 0);
|
||||
if (!(pfd.revents & G_IO_HUP) && (pfd.revents & G_IO_OUT)) {
|
||||
io_channel_send(s->ioc, buf, len);
|
||||
}
|
||||
|
||||
return len;
|
||||
return io_channel_send(s->ioc, buf, len);
|
||||
}
|
||||
|
||||
static GSource *pty_chr_add_watch(Chardev *chr, GIOCondition cond)
|
||||
|
||||
@@ -742,12 +742,8 @@ static void tcp_chr_websock_handshake(QIOTask *task, gpointer user_data)
|
||||
{
|
||||
Chardev *chr = user_data;
|
||||
SocketChardev *s = user_data;
|
||||
Error *err = NULL;
|
||||
|
||||
if (qio_task_propagate_error(task, &err)) {
|
||||
error_reportf_err(err,
|
||||
"websock handshake of character device %s failed: ",
|
||||
chr->label);
|
||||
if (qio_task_propagate_error(task, NULL)) {
|
||||
tcp_chr_disconnect(chr);
|
||||
} else {
|
||||
if (s->do_telnetopt) {
|
||||
@@ -782,12 +778,8 @@ static void tcp_chr_tls_handshake(QIOTask *task,
|
||||
{
|
||||
Chardev *chr = user_data;
|
||||
SocketChardev *s = user_data;
|
||||
Error *err = NULL;
|
||||
|
||||
if (qio_task_propagate_error(task, &err)) {
|
||||
error_reportf_err(err,
|
||||
"TLS handshake of character device %s failed: ",
|
||||
chr->label);
|
||||
if (qio_task_propagate_error(task, NULL)) {
|
||||
tcp_chr_disconnect(chr);
|
||||
} else {
|
||||
if (s->is_websock) {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#CONFIG_VFIO_CCW=n
|
||||
#CONFIG_VIRTIO_PCI=n
|
||||
#CONFIG_WDT_DIAG288=n
|
||||
#CONFIG_PCIE_DEVICES=n
|
||||
|
||||
# Boards:
|
||||
#
|
||||
|
||||
173
configure
vendored
173
configure
vendored
@@ -451,11 +451,7 @@ elif check_define __s390__ ; then
|
||||
cpu="s390"
|
||||
fi
|
||||
elif check_define __riscv ; then
|
||||
if check_define _LP64 ; then
|
||||
cpu="riscv64"
|
||||
else
|
||||
cpu="riscv32"
|
||||
fi
|
||||
cpu="riscv"
|
||||
elif check_define __arm__ ; then
|
||||
cpu="arm"
|
||||
elif check_define __aarch64__ ; then
|
||||
@@ -469,118 +465,49 @@ else
|
||||
echo "WARNING: unrecognized host CPU, proceeding with 'uname -m' output '$cpu'"
|
||||
fi
|
||||
|
||||
# Normalise host CPU name to the values used by Meson cross files and in source
|
||||
# directories, and set multilib cflags. The canonicalization isn't really
|
||||
# necessary, because the architectures that we check for should not hit the
|
||||
# 'uname -m' case, but better safe than sorry in case --cpu= is used.
|
||||
#
|
||||
# Normalise host CPU name and set multilib cflags. The canonicalization
|
||||
# isn't really necessary, because the architectures that we check for
|
||||
# should not hit the 'uname -m' case, but better safe than sorry.
|
||||
# Note that this case should only have supported host CPUs, not guests.
|
||||
# Please keep it sorted and synchronized with meson.build's host_arch.
|
||||
host_arch=
|
||||
linux_arch=
|
||||
case "$cpu" in
|
||||
aarch64)
|
||||
host_arch=aarch64
|
||||
linux_arch=arm64
|
||||
;;
|
||||
|
||||
armv*b|armv*l|arm)
|
||||
cpu=arm
|
||||
host_arch=arm
|
||||
linux_arch=arm
|
||||
;;
|
||||
cpu="arm" ;;
|
||||
|
||||
i386|i486|i586|i686)
|
||||
cpu="i386"
|
||||
host_arch=i386
|
||||
linux_arch=x86
|
||||
CPU_CFLAGS="-m32"
|
||||
;;
|
||||
|
||||
loongarch*)
|
||||
cpu=loongarch64
|
||||
host_arch=loongarch64
|
||||
;;
|
||||
|
||||
mips64*)
|
||||
cpu=mips64
|
||||
host_arch=mips
|
||||
linux_arch=mips
|
||||
;;
|
||||
mips*)
|
||||
cpu=mips
|
||||
host_arch=mips
|
||||
linux_arch=mips
|
||||
;;
|
||||
|
||||
ppc)
|
||||
host_arch=ppc
|
||||
linux_arch=powerpc
|
||||
CPU_CFLAGS="-m32"
|
||||
;;
|
||||
ppc64)
|
||||
host_arch=ppc64
|
||||
linux_arch=powerpc
|
||||
CPU_CFLAGS="-m64 -mbig-endian"
|
||||
;;
|
||||
ppc64le)
|
||||
cpu=ppc64
|
||||
host_arch=ppc64
|
||||
linux_arch=powerpc
|
||||
CPU_CFLAGS="-m64 -mlittle-endian"
|
||||
;;
|
||||
|
||||
riscv32 | riscv64)
|
||||
host_arch=riscv
|
||||
linux_arch=riscv
|
||||
;;
|
||||
|
||||
s390)
|
||||
linux_arch=s390
|
||||
CPU_CFLAGS="-m31"
|
||||
;;
|
||||
s390x)
|
||||
host_arch=s390x
|
||||
linux_arch=s390
|
||||
CPU_CFLAGS="-m64"
|
||||
;;
|
||||
|
||||
sparc|sun4[cdmuv])
|
||||
cpu=sparc
|
||||
CPU_CFLAGS="-m32 -mv8plus -mcpu=ultrasparc"
|
||||
;;
|
||||
sparc64)
|
||||
host_arch=sparc64
|
||||
CPU_CFLAGS="-m64 -mcpu=ultrasparc"
|
||||
;;
|
||||
|
||||
CPU_CFLAGS="-m32" ;;
|
||||
x32)
|
||||
cpu="x86_64"
|
||||
host_arch=x86_64
|
||||
linux_arch=x86
|
||||
CPU_CFLAGS="-mx32"
|
||||
;;
|
||||
CPU_CFLAGS="-mx32" ;;
|
||||
x86_64|amd64)
|
||||
cpu="x86_64"
|
||||
host_arch=x86_64
|
||||
linux_arch=x86
|
||||
# ??? 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"
|
||||
;;
|
||||
esac
|
||||
CPU_CFLAGS="-m64 -mcx16" ;;
|
||||
|
||||
if test -n "$host_arch" && {
|
||||
! test -d "$source_path/linux-user/include/host/$host_arch" ||
|
||||
! test -d "$source_path/common-user/host/$host_arch"; }; then
|
||||
error_exit "linux-user/include/host/$host_arch does not exist." \
|
||||
"This is a bug in the configure script, please report it."
|
||||
fi
|
||||
if test -n "$linux_arch" && ! test -d "$source_path/linux-headers/asm-$linux_arch"; then
|
||||
error_exit "linux-headers/asm-$linux_arch does not exist." \
|
||||
"This is a bug in the configure script, please report it."
|
||||
fi
|
||||
mips*)
|
||||
cpu="mips" ;;
|
||||
|
||||
ppc)
|
||||
CPU_CFLAGS="-m32" ;;
|
||||
ppc64)
|
||||
CPU_CFLAGS="-m64 -mbig-endian" ;;
|
||||
ppc64le)
|
||||
cpu="ppc64"
|
||||
CPU_CFLAGS="-m64 -mlittle-endian" ;;
|
||||
|
||||
s390)
|
||||
CPU_CFLAGS="-m31" ;;
|
||||
s390x)
|
||||
CPU_CFLAGS="-m64" ;;
|
||||
|
||||
sparc|sun4[cdmuv])
|
||||
cpu="sparc"
|
||||
CPU_CFLAGS="-m32 -mv8plus -mcpu=ultrasparc" ;;
|
||||
sparc64)
|
||||
CPU_CFLAGS="-m64 -mcpu=ultrasparc" ;;
|
||||
esac
|
||||
|
||||
check_py_version() {
|
||||
# We require python >= 3.7.
|
||||
@@ -826,9 +753,6 @@ for opt do
|
||||
# everything else has the same name in configure and meson
|
||||
--*) meson_option_parse "$opt" "$optarg"
|
||||
;;
|
||||
# Pass through -Dxxxx options to meson
|
||||
-D*) meson_options="$meson_options $opt"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -872,7 +796,7 @@ default_target_list=""
|
||||
mak_wilds=""
|
||||
|
||||
if [ "$linux_user" != no ]; then
|
||||
if [ "$targetos" = linux ] && [ -n "$host_arch" ]; then
|
||||
if [ "$targetos" = linux ] && [ -d "$source_path/linux-user/include/host/$cpu" ]; then
|
||||
linux_user=yes
|
||||
elif [ "$linux_user" = yes ]; then
|
||||
error_exit "linux-user not supported on this architecture"
|
||||
@@ -918,7 +842,6 @@ $(echo Available targets: $default_target_list | \
|
||||
--target-list-exclude=LIST exclude a set of targets from the default target-list
|
||||
|
||||
Advanced options (experts only):
|
||||
-Dmesonoptname=val passthrough option to meson unmodified
|
||||
--cross-prefix=PREFIX use PREFIX for compile tools, PREFIX can be blank [$cross_prefix]
|
||||
--cc=CC use C compiler CC [$cc]
|
||||
--host-cc=CC use C compiler CC [$host_cc] for code run at
|
||||
@@ -1777,9 +1700,37 @@ echo "PKG_CONFIG=${pkg_config}" >> $config_host_mak
|
||||
echo "CC=$cc" >> $config_host_mak
|
||||
echo "EXESUF=$EXESUF" >> $config_host_mak
|
||||
|
||||
# use included Linux headers for KVM architectures
|
||||
if test "$linux" = "yes" && test -n "$linux_arch"; then
|
||||
symlink "$source_path/linux-headers/asm-$linux_arch" linux-headers/asm
|
||||
# use included Linux headers
|
||||
if test "$linux" = "yes" ; then
|
||||
mkdir -p linux-headers
|
||||
case "$cpu" in
|
||||
i386|x86_64)
|
||||
linux_arch=x86
|
||||
;;
|
||||
ppc|ppc64)
|
||||
linux_arch=powerpc
|
||||
;;
|
||||
s390x)
|
||||
linux_arch=s390
|
||||
;;
|
||||
aarch64)
|
||||
linux_arch=arm64
|
||||
;;
|
||||
loongarch*)
|
||||
linux_arch=loongarch
|
||||
;;
|
||||
mips64)
|
||||
linux_arch=mips
|
||||
;;
|
||||
*)
|
||||
# For most CPUs the kernel architecture name and QEMU CPU name match.
|
||||
linux_arch="$cpu"
|
||||
;;
|
||||
esac
|
||||
# For non-KVM architectures we will not have asm headers
|
||||
if [ -e "$source_path/linux-headers/asm-$linux_arch" ]; then
|
||||
symlink "$source_path/linux-headers/asm-$linux_arch" linux-headers/asm
|
||||
fi
|
||||
fi
|
||||
|
||||
for target in $target_list; do
|
||||
|
||||
@@ -316,11 +316,6 @@ static int fill_context(KDDEBUGGER_DATA64 *kdbg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!Prcb) {
|
||||
eprintf("Context for CPU #%d is missing\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (va_space_rw(vs, Prcb + kdbg->OffsetPrcbContext,
|
||||
&Context, sizeof(Context), 0)) {
|
||||
eprintf("Failed to read CPU #%d ContextFrame location\n", i);
|
||||
|
||||
@@ -772,7 +772,7 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
char *opt = argv[i];
|
||||
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
|
||||
g_autofree char **tokens = g_strsplit(opt, "=", 2);
|
||||
|
||||
if (g_strcmp0(tokens[0], "iblksize") == 0) {
|
||||
l1_iblksize = STRTOLL(tokens[1]);
|
||||
|
||||
@@ -148,7 +148,7 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
|
||||
int argc, char **argv)
|
||||
{
|
||||
for (int i = 0; i < argc; i++) {
|
||||
g_auto(GStrv) tokens = g_strsplit(argv[i], "=", 2);
|
||||
g_autofree char **tokens = g_strsplit(argv[i], "=", 2);
|
||||
if (g_strcmp0(tokens[0], "filename") == 0) {
|
||||
file_name = g_strdup(tokens[1]);
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
char *opt = argv[i];
|
||||
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
|
||||
g_autofree char **tokens = g_strsplit(opt, "=", 2);
|
||||
if (g_strcmp0(tokens[0], "ifilter") == 0) {
|
||||
parse_insn_match(tokens[1]);
|
||||
} else if (g_strcmp0(tokens[0], "afilter") == 0) {
|
||||
|
||||
@@ -135,7 +135,7 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
|
||||
{
|
||||
for (int i = 0; i < argc; i++) {
|
||||
char *opt = argv[i];
|
||||
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
|
||||
g_autofree char **tokens = g_strsplit(opt, "=", 2);
|
||||
if (g_strcmp0(tokens[0], "inline") == 0) {
|
||||
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) {
|
||||
fprintf(stderr, "boolean argument parsing failed: %s\n", opt);
|
||||
|
||||
@@ -169,7 +169,7 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
char *opt = argv[i];
|
||||
g_auto(GStrv) tokens = g_strsplit(opt, "=", -1);
|
||||
g_autofree char **tokens = g_strsplit(opt, "=", -1);
|
||||
|
||||
if (g_strcmp0(tokens[0], "sortby") == 0) {
|
||||
if (g_strcmp0(tokens[1], "reads") == 0) {
|
||||
|
||||
@@ -333,7 +333,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
char *p = argv[i];
|
||||
g_auto(GStrv) tokens = g_strsplit(p, "=", -1);
|
||||
g_autofree char **tokens = g_strsplit(p, "=", -1);
|
||||
if (g_strcmp0(tokens[0], "inline") == 0) {
|
||||
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &do_inline)) {
|
||||
fprintf(stderr, "boolean argument parsing failed: %s\n", p);
|
||||
|
||||
@@ -263,7 +263,7 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info,
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
char *opt = argv[i];
|
||||
g_auto(GStrv) tokens = g_strsplit(opt, "=", 2);
|
||||
g_autofree char **tokens = g_strsplit(opt, "=", 2);
|
||||
|
||||
if (g_strcmp0(tokens[0], "track") == 0) {
|
||||
if (g_strcmp0(tokens[1], "read") == 0) {
|
||||
|
||||
@@ -130,7 +130,7 @@ static void report_divergance(ExecState *us, ExecState *them)
|
||||
}
|
||||
}
|
||||
divergence_log = g_slist_prepend(divergence_log,
|
||||
g_memdup2(&divrec, sizeof(divrec)));
|
||||
g_memdup(&divrec, sizeof(divrec)));
|
||||
|
||||
/* Output short log entry of going out of sync... */
|
||||
if (verbose || divrec.distance == 1 || diverged) {
|
||||
@@ -323,7 +323,7 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
char *p = argv[i];
|
||||
g_auto(GStrv) tokens = g_strsplit(p, "=", 2);
|
||||
g_autofree char **tokens = g_strsplit(p, "=", 2);
|
||||
|
||||
if (g_strcmp0(tokens[0], "verbose") == 0) {
|
||||
if (!qemu_plugin_bool_parse(tokens[0], tokens[1], &verbose)) {
|
||||
|
||||
@@ -303,53 +303,6 @@ vg_get_display_info(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd)
|
||||
cmd->state = VG_CMD_STATE_PENDING;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_edid_cb(gint fd, GIOCondition condition, gpointer user_data)
|
||||
{
|
||||
struct virtio_gpu_resp_edid resp_edid;
|
||||
VuGpu *vg = user_data;
|
||||
struct virtio_gpu_ctrl_command *cmd = QTAILQ_LAST(&vg->fenceq);
|
||||
|
||||
g_debug("get edid cb");
|
||||
assert(cmd->cmd_hdr.type == VIRTIO_GPU_CMD_GET_EDID);
|
||||
if (!vg_recv_msg(vg, VHOST_USER_GPU_GET_EDID,
|
||||
sizeof(resp_edid), &resp_edid)) {
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
QTAILQ_REMOVE(&vg->fenceq, cmd, next);
|
||||
vg_ctrl_response(vg, cmd, &resp_edid.hdr, sizeof(resp_edid));
|
||||
|
||||
vg->wait_in = 0;
|
||||
vg_handle_ctrl(&vg->dev.parent, 0);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
void
|
||||
vg_get_edid(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd)
|
||||
{
|
||||
struct virtio_gpu_cmd_get_edid get_edid;
|
||||
|
||||
VUGPU_FILL_CMD(get_edid);
|
||||
virtio_gpu_bswap_32(&get_edid, sizeof(get_edid));
|
||||
|
||||
VhostUserGpuMsg msg = {
|
||||
.request = VHOST_USER_GPU_GET_EDID,
|
||||
.size = sizeof(VhostUserGpuEdidRequest),
|
||||
.payload.edid_req = {
|
||||
.scanout_id = get_edid.scanout,
|
||||
},
|
||||
};
|
||||
|
||||
assert(vg->wait_in == 0);
|
||||
|
||||
vg_send_msg(vg, &msg, -1);
|
||||
vg->wait_in = g_unix_fd_add(vg->sock_fd, G_IO_IN | G_IO_HUP,
|
||||
get_edid_cb, vg);
|
||||
cmd->state = VG_CMD_STATE_PENDING;
|
||||
}
|
||||
|
||||
static void
|
||||
vg_resource_create_2d(VuGpu *g,
|
||||
struct virtio_gpu_ctrl_command *cmd)
|
||||
@@ -884,9 +837,8 @@ vg_process_cmd(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd)
|
||||
case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING:
|
||||
vg_resource_detach_backing(vg, cmd);
|
||||
break;
|
||||
case VIRTIO_GPU_CMD_GET_EDID:
|
||||
vg_get_edid(vg, cmd);
|
||||
break;
|
||||
/* case VIRTIO_GPU_CMD_GET_EDID: */
|
||||
/* break */
|
||||
default:
|
||||
g_warning("TODO handle ctrl %x\n", cmd->cmd_hdr.type);
|
||||
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
||||
@@ -1070,36 +1022,26 @@ vg_queue_set_started(VuDev *dev, int qidx, bool started)
|
||||
static gboolean
|
||||
protocol_features_cb(gint fd, GIOCondition condition, gpointer user_data)
|
||||
{
|
||||
const uint64_t protocol_edid = (1 << VHOST_USER_GPU_PROTOCOL_F_EDID);
|
||||
VuGpu *g = user_data;
|
||||
uint64_t protocol_features;
|
||||
uint64_t u64;
|
||||
VhostUserGpuMsg msg = {
|
||||
.request = VHOST_USER_GPU_GET_PROTOCOL_FEATURES
|
||||
};
|
||||
|
||||
if (!vg_recv_msg(g, msg.request,
|
||||
sizeof(protocol_features), &protocol_features)) {
|
||||
if (!vg_recv_msg(g, msg.request, sizeof(u64), &u64)) {
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
protocol_features &= protocol_edid;
|
||||
|
||||
msg = (VhostUserGpuMsg) {
|
||||
.request = VHOST_USER_GPU_SET_PROTOCOL_FEATURES,
|
||||
.size = sizeof(uint64_t),
|
||||
.payload.u64 = protocol_features,
|
||||
.payload.u64 = 0
|
||||
};
|
||||
vg_send_msg(g, &msg, -1);
|
||||
|
||||
g->wait_in = 0;
|
||||
vg_handle_ctrl(&g->dev.parent, 0);
|
||||
|
||||
if (g->edid_inited && !(protocol_features & protocol_edid)) {
|
||||
g_printerr("EDID feature set by the frontend but it does not support "
|
||||
"the EDID vhost-user-gpu protocol.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
@@ -1107,7 +1049,7 @@ static void
|
||||
set_gpu_protocol_features(VuGpu *g)
|
||||
{
|
||||
VhostUserGpuMsg msg = {
|
||||
.request = VHOST_USER_GPU_GET_PROTOCOL_FEATURES,
|
||||
.request = VHOST_USER_GPU_GET_PROTOCOL_FEATURES
|
||||
};
|
||||
|
||||
vg_send_msg(g, &msg, -1);
|
||||
@@ -1144,7 +1086,6 @@ vg_get_features(VuDev *dev)
|
||||
if (opt_virgl) {
|
||||
features |= 1 << VIRTIO_GPU_F_VIRGL;
|
||||
}
|
||||
features |= 1 << VIRTIO_GPU_F_EDID;
|
||||
|
||||
return features;
|
||||
}
|
||||
@@ -1162,8 +1103,6 @@ vg_set_features(VuDev *dev, uint64_t features)
|
||||
g->virgl_inited = true;
|
||||
}
|
||||
|
||||
g->edid_inited = !!(features & (1 << VIRTIO_GPU_F_EDID));
|
||||
|
||||
g->virgl = virgl;
|
||||
}
|
||||
|
||||
|
||||
@@ -495,9 +495,6 @@ void vg_virgl_process_cmd(VuGpu *g, struct virtio_gpu_ctrl_command *cmd)
|
||||
case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
|
||||
vg_get_display_info(g, cmd);
|
||||
break;
|
||||
case VIRTIO_GPU_CMD_GET_EDID:
|
||||
vg_get_edid(g, cmd);
|
||||
break;
|
||||
default:
|
||||
g_debug("TODO handle ctrl %x\n", cmd->cmd_hdr.type);
|
||||
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
||||
|
||||
@@ -36,7 +36,6 @@ typedef enum VhostUserGpuRequest {
|
||||
VHOST_USER_GPU_UPDATE,
|
||||
VHOST_USER_GPU_DMABUF_SCANOUT,
|
||||
VHOST_USER_GPU_DMABUF_UPDATE,
|
||||
VHOST_USER_GPU_GET_EDID,
|
||||
} VhostUserGpuRequest;
|
||||
|
||||
typedef struct VhostUserGpuDisplayInfoReply {
|
||||
@@ -84,10 +83,6 @@ typedef struct VhostUserGpuDMABUFScanout {
|
||||
int fd_drm_fourcc;
|
||||
} QEMU_PACKED VhostUserGpuDMABUFScanout;
|
||||
|
||||
typedef struct VhostUserGpuEdidRequest {
|
||||
uint32_t scanout_id;
|
||||
} QEMU_PACKED VhostUserGpuEdidRequest;
|
||||
|
||||
typedef struct VhostUserGpuMsg {
|
||||
uint32_t request; /* VhostUserGpuRequest */
|
||||
uint32_t flags;
|
||||
@@ -98,8 +93,6 @@ typedef struct VhostUserGpuMsg {
|
||||
VhostUserGpuScanout scanout;
|
||||
VhostUserGpuUpdate update;
|
||||
VhostUserGpuDMABUFScanout dmabuf_scanout;
|
||||
VhostUserGpuEdidRequest edid_req;
|
||||
struct virtio_gpu_resp_edid resp_edid;
|
||||
struct virtio_gpu_resp_display_info display_info;
|
||||
uint64_t u64;
|
||||
} payload;
|
||||
@@ -111,8 +104,6 @@ static VhostUserGpuMsg m __attribute__ ((unused));
|
||||
|
||||
#define VHOST_USER_GPU_MSG_FLAG_REPLY 0x4
|
||||
|
||||
#define VHOST_USER_GPU_PROTOCOL_F_EDID 0
|
||||
|
||||
struct virtio_gpu_scanout {
|
||||
uint32_t width, height;
|
||||
int x, y;
|
||||
@@ -131,7 +122,6 @@ typedef struct VuGpu {
|
||||
|
||||
bool virgl;
|
||||
bool virgl_inited;
|
||||
bool edid_inited;
|
||||
uint32_t inflight;
|
||||
|
||||
struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS];
|
||||
@@ -181,7 +171,6 @@ int vg_create_mapping_iov(VuGpu *g,
|
||||
struct iovec **iov);
|
||||
void vg_cleanup_mapping_iov(VuGpu *g, struct iovec *iov, uint32_t count);
|
||||
void vg_get_display_info(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd);
|
||||
void vg_get_edid(VuGpu *vg, struct virtio_gpu_ctrl_command *cmd);
|
||||
|
||||
void vg_wait_ok(VuGpu *g);
|
||||
|
||||
|
||||
780
crypto/aes.c
780
crypto/aes.c
@@ -28,10 +28,7 @@
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bswap.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "crypto/aes.h"
|
||||
#include "crypto/aes-round.h"
|
||||
|
||||
typedef uint32_t u32;
|
||||
typedef uint8_t u8;
|
||||
@@ -111,152 +108,278 @@ const uint8_t AES_isbox[256] = {
|
||||
0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D,
|
||||
};
|
||||
|
||||
/* AES ShiftRows, for complete unrolling. */
|
||||
#define AES_SH(X) (((X) * 5) & 15)
|
||||
|
||||
/* AES InvShiftRows, for complete unrolling. */
|
||||
#define AES_ISH(X) (((X) * 13) & 15)
|
||||
|
||||
/*
|
||||
* MixColumns lookup table, for use with rot32.
|
||||
*/
|
||||
static const uint32_t AES_mc_rot[256] = {
|
||||
0x00000000, 0x03010102, 0x06020204, 0x05030306,
|
||||
0x0c040408, 0x0f05050a, 0x0a06060c, 0x0907070e,
|
||||
0x18080810, 0x1b090912, 0x1e0a0a14, 0x1d0b0b16,
|
||||
0x140c0c18, 0x170d0d1a, 0x120e0e1c, 0x110f0f1e,
|
||||
0x30101020, 0x33111122, 0x36121224, 0x35131326,
|
||||
0x3c141428, 0x3f15152a, 0x3a16162c, 0x3917172e,
|
||||
0x28181830, 0x2b191932, 0x2e1a1a34, 0x2d1b1b36,
|
||||
0x241c1c38, 0x271d1d3a, 0x221e1e3c, 0x211f1f3e,
|
||||
0x60202040, 0x63212142, 0x66222244, 0x65232346,
|
||||
0x6c242448, 0x6f25254a, 0x6a26264c, 0x6927274e,
|
||||
0x78282850, 0x7b292952, 0x7e2a2a54, 0x7d2b2b56,
|
||||
0x742c2c58, 0x772d2d5a, 0x722e2e5c, 0x712f2f5e,
|
||||
0x50303060, 0x53313162, 0x56323264, 0x55333366,
|
||||
0x5c343468, 0x5f35356a, 0x5a36366c, 0x5937376e,
|
||||
0x48383870, 0x4b393972, 0x4e3a3a74, 0x4d3b3b76,
|
||||
0x443c3c78, 0x473d3d7a, 0x423e3e7c, 0x413f3f7e,
|
||||
0xc0404080, 0xc3414182, 0xc6424284, 0xc5434386,
|
||||
0xcc444488, 0xcf45458a, 0xca46468c, 0xc947478e,
|
||||
0xd8484890, 0xdb494992, 0xde4a4a94, 0xdd4b4b96,
|
||||
0xd44c4c98, 0xd74d4d9a, 0xd24e4e9c, 0xd14f4f9e,
|
||||
0xf05050a0, 0xf35151a2, 0xf65252a4, 0xf55353a6,
|
||||
0xfc5454a8, 0xff5555aa, 0xfa5656ac, 0xf95757ae,
|
||||
0xe85858b0, 0xeb5959b2, 0xee5a5ab4, 0xed5b5bb6,
|
||||
0xe45c5cb8, 0xe75d5dba, 0xe25e5ebc, 0xe15f5fbe,
|
||||
0xa06060c0, 0xa36161c2, 0xa66262c4, 0xa56363c6,
|
||||
0xac6464c8, 0xaf6565ca, 0xaa6666cc, 0xa96767ce,
|
||||
0xb86868d0, 0xbb6969d2, 0xbe6a6ad4, 0xbd6b6bd6,
|
||||
0xb46c6cd8, 0xb76d6dda, 0xb26e6edc, 0xb16f6fde,
|
||||
0x907070e0, 0x937171e2, 0x967272e4, 0x957373e6,
|
||||
0x9c7474e8, 0x9f7575ea, 0x9a7676ec, 0x997777ee,
|
||||
0x887878f0, 0x8b7979f2, 0x8e7a7af4, 0x8d7b7bf6,
|
||||
0x847c7cf8, 0x877d7dfa, 0x827e7efc, 0x817f7ffe,
|
||||
0x9b80801b, 0x98818119, 0x9d82821f, 0x9e83831d,
|
||||
0x97848413, 0x94858511, 0x91868617, 0x92878715,
|
||||
0x8388880b, 0x80898909, 0x858a8a0f, 0x868b8b0d,
|
||||
0x8f8c8c03, 0x8c8d8d01, 0x898e8e07, 0x8a8f8f05,
|
||||
0xab90903b, 0xa8919139, 0xad92923f, 0xae93933d,
|
||||
0xa7949433, 0xa4959531, 0xa1969637, 0xa2979735,
|
||||
0xb398982b, 0xb0999929, 0xb59a9a2f, 0xb69b9b2d,
|
||||
0xbf9c9c23, 0xbc9d9d21, 0xb99e9e27, 0xba9f9f25,
|
||||
0xfba0a05b, 0xf8a1a159, 0xfda2a25f, 0xfea3a35d,
|
||||
0xf7a4a453, 0xf4a5a551, 0xf1a6a657, 0xf2a7a755,
|
||||
0xe3a8a84b, 0xe0a9a949, 0xe5aaaa4f, 0xe6abab4d,
|
||||
0xefacac43, 0xecadad41, 0xe9aeae47, 0xeaafaf45,
|
||||
0xcbb0b07b, 0xc8b1b179, 0xcdb2b27f, 0xceb3b37d,
|
||||
0xc7b4b473, 0xc4b5b571, 0xc1b6b677, 0xc2b7b775,
|
||||
0xd3b8b86b, 0xd0b9b969, 0xd5baba6f, 0xd6bbbb6d,
|
||||
0xdfbcbc63, 0xdcbdbd61, 0xd9bebe67, 0xdabfbf65,
|
||||
0x5bc0c09b, 0x58c1c199, 0x5dc2c29f, 0x5ec3c39d,
|
||||
0x57c4c493, 0x54c5c591, 0x51c6c697, 0x52c7c795,
|
||||
0x43c8c88b, 0x40c9c989, 0x45caca8f, 0x46cbcb8d,
|
||||
0x4fcccc83, 0x4ccdcd81, 0x49cece87, 0x4acfcf85,
|
||||
0x6bd0d0bb, 0x68d1d1b9, 0x6dd2d2bf, 0x6ed3d3bd,
|
||||
0x67d4d4b3, 0x64d5d5b1, 0x61d6d6b7, 0x62d7d7b5,
|
||||
0x73d8d8ab, 0x70d9d9a9, 0x75dadaaf, 0x76dbdbad,
|
||||
0x7fdcdca3, 0x7cdddda1, 0x79dedea7, 0x7adfdfa5,
|
||||
0x3be0e0db, 0x38e1e1d9, 0x3de2e2df, 0x3ee3e3dd,
|
||||
0x37e4e4d3, 0x34e5e5d1, 0x31e6e6d7, 0x32e7e7d5,
|
||||
0x23e8e8cb, 0x20e9e9c9, 0x25eaeacf, 0x26ebebcd,
|
||||
0x2fececc3, 0x2cededc1, 0x29eeeec7, 0x2aefefc5,
|
||||
0x0bf0f0fb, 0x08f1f1f9, 0x0df2f2ff, 0x0ef3f3fd,
|
||||
0x07f4f4f3, 0x04f5f5f1, 0x01f6f6f7, 0x02f7f7f5,
|
||||
0x13f8f8eb, 0x10f9f9e9, 0x15fafaef, 0x16fbfbed,
|
||||
0x1ffcfce3, 0x1cfdfde1, 0x19fefee7, 0x1affffe5,
|
||||
const uint8_t AES_shifts[16] = {
|
||||
0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11
|
||||
};
|
||||
|
||||
/*
|
||||
* Inverse MixColumns lookup table, for use with rot32.
|
||||
*/
|
||||
static const uint32_t AES_imc_rot[256] = {
|
||||
0x00000000, 0x0b0d090e, 0x161a121c, 0x1d171b12,
|
||||
0x2c342438, 0x27392d36, 0x3a2e3624, 0x31233f2a,
|
||||
0x58684870, 0x5365417e, 0x4e725a6c, 0x457f5362,
|
||||
0x745c6c48, 0x7f516546, 0x62467e54, 0x694b775a,
|
||||
0xb0d090e0, 0xbbdd99ee, 0xa6ca82fc, 0xadc78bf2,
|
||||
0x9ce4b4d8, 0x97e9bdd6, 0x8afea6c4, 0x81f3afca,
|
||||
0xe8b8d890, 0xe3b5d19e, 0xfea2ca8c, 0xf5afc382,
|
||||
0xc48cfca8, 0xcf81f5a6, 0xd296eeb4, 0xd99be7ba,
|
||||
0x7bbb3bdb, 0x70b632d5, 0x6da129c7, 0x66ac20c9,
|
||||
0x578f1fe3, 0x5c8216ed, 0x41950dff, 0x4a9804f1,
|
||||
0x23d373ab, 0x28de7aa5, 0x35c961b7, 0x3ec468b9,
|
||||
0x0fe75793, 0x04ea5e9d, 0x19fd458f, 0x12f04c81,
|
||||
0xcb6bab3b, 0xc066a235, 0xdd71b927, 0xd67cb029,
|
||||
0xe75f8f03, 0xec52860d, 0xf1459d1f, 0xfa489411,
|
||||
0x9303e34b, 0x980eea45, 0x8519f157, 0x8e14f859,
|
||||
0xbf37c773, 0xb43ace7d, 0xa92dd56f, 0xa220dc61,
|
||||
0xf66d76ad, 0xfd607fa3, 0xe07764b1, 0xeb7a6dbf,
|
||||
0xda595295, 0xd1545b9b, 0xcc434089, 0xc74e4987,
|
||||
0xae053edd, 0xa50837d3, 0xb81f2cc1, 0xb31225cf,
|
||||
0x82311ae5, 0x893c13eb, 0x942b08f9, 0x9f2601f7,
|
||||
0x46bde64d, 0x4db0ef43, 0x50a7f451, 0x5baafd5f,
|
||||
0x6a89c275, 0x6184cb7b, 0x7c93d069, 0x779ed967,
|
||||
0x1ed5ae3d, 0x15d8a733, 0x08cfbc21, 0x03c2b52f,
|
||||
0x32e18a05, 0x39ec830b, 0x24fb9819, 0x2ff69117,
|
||||
0x8dd64d76, 0x86db4478, 0x9bcc5f6a, 0x90c15664,
|
||||
0xa1e2694e, 0xaaef6040, 0xb7f87b52, 0xbcf5725c,
|
||||
0xd5be0506, 0xdeb30c08, 0xc3a4171a, 0xc8a91e14,
|
||||
0xf98a213e, 0xf2872830, 0xef903322, 0xe49d3a2c,
|
||||
0x3d06dd96, 0x360bd498, 0x2b1ccf8a, 0x2011c684,
|
||||
0x1132f9ae, 0x1a3ff0a0, 0x0728ebb2, 0x0c25e2bc,
|
||||
0x656e95e6, 0x6e639ce8, 0x737487fa, 0x78798ef4,
|
||||
0x495ab1de, 0x4257b8d0, 0x5f40a3c2, 0x544daacc,
|
||||
0xf7daec41, 0xfcd7e54f, 0xe1c0fe5d, 0xeacdf753,
|
||||
0xdbeec879, 0xd0e3c177, 0xcdf4da65, 0xc6f9d36b,
|
||||
0xafb2a431, 0xa4bfad3f, 0xb9a8b62d, 0xb2a5bf23,
|
||||
0x83868009, 0x888b8907, 0x959c9215, 0x9e919b1b,
|
||||
0x470a7ca1, 0x4c0775af, 0x51106ebd, 0x5a1d67b3,
|
||||
0x6b3e5899, 0x60335197, 0x7d244a85, 0x7629438b,
|
||||
0x1f6234d1, 0x146f3ddf, 0x097826cd, 0x02752fc3,
|
||||
0x335610e9, 0x385b19e7, 0x254c02f5, 0x2e410bfb,
|
||||
0x8c61d79a, 0x876cde94, 0x9a7bc586, 0x9176cc88,
|
||||
0xa055f3a2, 0xab58faac, 0xb64fe1be, 0xbd42e8b0,
|
||||
0xd4099fea, 0xdf0496e4, 0xc2138df6, 0xc91e84f8,
|
||||
0xf83dbbd2, 0xf330b2dc, 0xee27a9ce, 0xe52aa0c0,
|
||||
0x3cb1477a, 0x37bc4e74, 0x2aab5566, 0x21a65c68,
|
||||
0x10856342, 0x1b886a4c, 0x069f715e, 0x0d927850,
|
||||
0x64d90f0a, 0x6fd40604, 0x72c31d16, 0x79ce1418,
|
||||
0x48ed2b32, 0x43e0223c, 0x5ef7392e, 0x55fa3020,
|
||||
0x01b79aec, 0x0aba93e2, 0x17ad88f0, 0x1ca081fe,
|
||||
0x2d83bed4, 0x268eb7da, 0x3b99acc8, 0x3094a5c6,
|
||||
0x59dfd29c, 0x52d2db92, 0x4fc5c080, 0x44c8c98e,
|
||||
0x75ebf6a4, 0x7ee6ffaa, 0x63f1e4b8, 0x68fcedb6,
|
||||
0xb1670a0c, 0xba6a0302, 0xa77d1810, 0xac70111e,
|
||||
0x9d532e34, 0x965e273a, 0x8b493c28, 0x80443526,
|
||||
0xe90f427c, 0xe2024b72, 0xff155060, 0xf418596e,
|
||||
0xc53b6644, 0xce366f4a, 0xd3217458, 0xd82c7d56,
|
||||
0x7a0ca137, 0x7101a839, 0x6c16b32b, 0x671bba25,
|
||||
0x5638850f, 0x5d358c01, 0x40229713, 0x4b2f9e1d,
|
||||
0x2264e947, 0x2969e049, 0x347efb5b, 0x3f73f255,
|
||||
0x0e50cd7f, 0x055dc471, 0x184adf63, 0x1347d66d,
|
||||
0xcadc31d7, 0xc1d138d9, 0xdcc623cb, 0xd7cb2ac5,
|
||||
0xe6e815ef, 0xede51ce1, 0xf0f207f3, 0xfbff0efd,
|
||||
0x92b479a7, 0x99b970a9, 0x84ae6bbb, 0x8fa362b5,
|
||||
0xbe805d9f, 0xb58d5491, 0xa89a4f83, 0xa397468d,
|
||||
const uint8_t AES_ishifts[16] = {
|
||||
0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3
|
||||
};
|
||||
|
||||
/* AES_imc[x][0] = [x].[0e, 09, 0d, 0b]; */
|
||||
/* AES_imc[x][1] = [x].[0b, 0e, 09, 0d]; */
|
||||
/* AES_imc[x][2] = [x].[0d, 0b, 0e, 09]; */
|
||||
/* AES_imc[x][3] = [x].[09, 0d, 0b, 0e]; */
|
||||
const uint32_t AES_imc[256][4] = {
|
||||
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, /* x=00 */
|
||||
{ 0x0E090D0B, 0x0B0E090D, 0x0D0B0E09, 0x090D0B0E, }, /* x=01 */
|
||||
{ 0x1C121A16, 0x161C121A, 0x1A161C12, 0x121A161C, }, /* x=02 */
|
||||
{ 0x121B171D, 0x1D121B17, 0x171D121B, 0x1B171D12, }, /* x=03 */
|
||||
{ 0x3824342C, 0x2C382434, 0x342C3824, 0x24342C38, }, /* x=04 */
|
||||
{ 0x362D3927, 0x27362D39, 0x3927362D, 0x2D392736, }, /* x=05 */
|
||||
{ 0x24362E3A, 0x3A24362E, 0x2E3A2436, 0x362E3A24, }, /* x=06 */
|
||||
{ 0x2A3F2331, 0x312A3F23, 0x23312A3F, 0x3F23312A, }, /* x=07 */
|
||||
{ 0x70486858, 0x58704868, 0x68587048, 0x48685870, }, /* x=08 */
|
||||
{ 0x7E416553, 0x537E4165, 0x65537E41, 0x4165537E, }, /* x=09 */
|
||||
{ 0x6C5A724E, 0x4E6C5A72, 0x724E6C5A, 0x5A724E6C, }, /* x=0A */
|
||||
{ 0x62537F45, 0x4562537F, 0x7F456253, 0x537F4562, }, /* x=0B */
|
||||
{ 0x486C5C74, 0x74486C5C, 0x5C74486C, 0x6C5C7448, }, /* x=0C */
|
||||
{ 0x4665517F, 0x7F466551, 0x517F4665, 0x65517F46, }, /* x=0D */
|
||||
{ 0x547E4662, 0x62547E46, 0x4662547E, 0x7E466254, }, /* x=0E */
|
||||
{ 0x5A774B69, 0x695A774B, 0x4B695A77, 0x774B695A, }, /* x=0F */
|
||||
{ 0xE090D0B0, 0xB0E090D0, 0xD0B0E090, 0x90D0B0E0, }, /* x=10 */
|
||||
{ 0xEE99DDBB, 0xBBEE99DD, 0xDDBBEE99, 0x99DDBBEE, }, /* x=11 */
|
||||
{ 0xFC82CAA6, 0xA6FC82CA, 0xCAA6FC82, 0x82CAA6FC, }, /* x=12 */
|
||||
{ 0xF28BC7AD, 0xADF28BC7, 0xC7ADF28B, 0x8BC7ADF2, }, /* x=13 */
|
||||
{ 0xD8B4E49C, 0x9CD8B4E4, 0xE49CD8B4, 0xB4E49CD8, }, /* x=14 */
|
||||
{ 0xD6BDE997, 0x97D6BDE9, 0xE997D6BD, 0xBDE997D6, }, /* x=15 */
|
||||
{ 0xC4A6FE8A, 0x8AC4A6FE, 0xFE8AC4A6, 0xA6FE8AC4, }, /* x=16 */
|
||||
{ 0xCAAFF381, 0x81CAAFF3, 0xF381CAAF, 0xAFF381CA, }, /* x=17 */
|
||||
{ 0x90D8B8E8, 0xE890D8B8, 0xB8E890D8, 0xD8B8E890, }, /* x=18 */
|
||||
{ 0x9ED1B5E3, 0xE39ED1B5, 0xB5E39ED1, 0xD1B5E39E, }, /* x=19 */
|
||||
{ 0x8CCAA2FE, 0xFE8CCAA2, 0xA2FE8CCA, 0xCAA2FE8C, }, /* x=1A */
|
||||
{ 0x82C3AFF5, 0xF582C3AF, 0xAFF582C3, 0xC3AFF582, }, /* x=1B */
|
||||
{ 0xA8FC8CC4, 0xC4A8FC8C, 0x8CC4A8FC, 0xFC8CC4A8, }, /* x=1C */
|
||||
{ 0xA6F581CF, 0xCFA6F581, 0x81CFA6F5, 0xF581CFA6, }, /* x=1D */
|
||||
{ 0xB4EE96D2, 0xD2B4EE96, 0x96D2B4EE, 0xEE96D2B4, }, /* x=1E */
|
||||
{ 0xBAE79BD9, 0xD9BAE79B, 0x9BD9BAE7, 0xE79BD9BA, }, /* x=1F */
|
||||
{ 0xDB3BBB7B, 0x7BDB3BBB, 0xBB7BDB3B, 0x3BBB7BDB, }, /* x=20 */
|
||||
{ 0xD532B670, 0x70D532B6, 0xB670D532, 0x32B670D5, }, /* x=21 */
|
||||
{ 0xC729A16D, 0x6DC729A1, 0xA16DC729, 0x29A16DC7, }, /* x=22 */
|
||||
{ 0xC920AC66, 0x66C920AC, 0xAC66C920, 0x20AC66C9, }, /* x=23 */
|
||||
{ 0xE31F8F57, 0x57E31F8F, 0x8F57E31F, 0x1F8F57E3, }, /* x=24 */
|
||||
{ 0xED16825C, 0x5CED1682, 0x825CED16, 0x16825CED, }, /* x=25 */
|
||||
{ 0xFF0D9541, 0x41FF0D95, 0x9541FF0D, 0x0D9541FF, }, /* x=26 */
|
||||
{ 0xF104984A, 0x4AF10498, 0x984AF104, 0x04984AF1, }, /* x=27 */
|
||||
{ 0xAB73D323, 0x23AB73D3, 0xD323AB73, 0x73D323AB, }, /* x=28 */
|
||||
{ 0xA57ADE28, 0x28A57ADE, 0xDE28A57A, 0x7ADE28A5, }, /* x=29 */
|
||||
{ 0xB761C935, 0x35B761C9, 0xC935B761, 0x61C935B7, }, /* x=2A */
|
||||
{ 0xB968C43E, 0x3EB968C4, 0xC43EB968, 0x68C43EB9, }, /* x=2B */
|
||||
{ 0x9357E70F, 0x0F9357E7, 0xE70F9357, 0x57E70F93, }, /* x=2C */
|
||||
{ 0x9D5EEA04, 0x049D5EEA, 0xEA049D5E, 0x5EEA049D, }, /* x=2D */
|
||||
{ 0x8F45FD19, 0x198F45FD, 0xFD198F45, 0x45FD198F, }, /* x=2E */
|
||||
{ 0x814CF012, 0x12814CF0, 0xF012814C, 0x4CF01281, }, /* x=2F */
|
||||
{ 0x3BAB6BCB, 0xCB3BAB6B, 0x6BCB3BAB, 0xAB6BCB3B, }, /* x=30 */
|
||||
{ 0x35A266C0, 0xC035A266, 0x66C035A2, 0xA266C035, }, /* x=31 */
|
||||
{ 0x27B971DD, 0xDD27B971, 0x71DD27B9, 0xB971DD27, }, /* x=32 */
|
||||
{ 0x29B07CD6, 0xD629B07C, 0x7CD629B0, 0xB07CD629, }, /* x=33 */
|
||||
{ 0x038F5FE7, 0xE7038F5F, 0x5FE7038F, 0x8F5FE703, }, /* x=34 */
|
||||
{ 0x0D8652EC, 0xEC0D8652, 0x52EC0D86, 0x8652EC0D, }, /* x=35 */
|
||||
{ 0x1F9D45F1, 0xF11F9D45, 0x45F11F9D, 0x9D45F11F, }, /* x=36 */
|
||||
{ 0x119448FA, 0xFA119448, 0x48FA1194, 0x9448FA11, }, /* x=37 */
|
||||
{ 0x4BE30393, 0x934BE303, 0x03934BE3, 0xE303934B, }, /* x=38 */
|
||||
{ 0x45EA0E98, 0x9845EA0E, 0x0E9845EA, 0xEA0E9845, }, /* x=39 */
|
||||
{ 0x57F11985, 0x8557F119, 0x198557F1, 0xF1198557, }, /* x=3A */
|
||||
{ 0x59F8148E, 0x8E59F814, 0x148E59F8, 0xF8148E59, }, /* x=3B */
|
||||
{ 0x73C737BF, 0xBF73C737, 0x37BF73C7, 0xC737BF73, }, /* x=3C */
|
||||
{ 0x7DCE3AB4, 0xB47DCE3A, 0x3AB47DCE, 0xCE3AB47D, }, /* x=3D */
|
||||
{ 0x6FD52DA9, 0xA96FD52D, 0x2DA96FD5, 0xD52DA96F, }, /* x=3E */
|
||||
{ 0x61DC20A2, 0xA261DC20, 0x20A261DC, 0xDC20A261, }, /* x=3F */
|
||||
{ 0xAD766DF6, 0xF6AD766D, 0x6DF6AD76, 0x766DF6AD, }, /* x=40 */
|
||||
{ 0xA37F60FD, 0xFDA37F60, 0x60FDA37F, 0x7F60FDA3, }, /* x=41 */
|
||||
{ 0xB16477E0, 0xE0B16477, 0x77E0B164, 0x6477E0B1, }, /* x=42 */
|
||||
{ 0xBF6D7AEB, 0xEBBF6D7A, 0x7AEBBF6D, 0x6D7AEBBF, }, /* x=43 */
|
||||
{ 0x955259DA, 0xDA955259, 0x59DA9552, 0x5259DA95, }, /* x=44 */
|
||||
{ 0x9B5B54D1, 0xD19B5B54, 0x54D19B5B, 0x5B54D19B, }, /* x=45 */
|
||||
{ 0x894043CC, 0xCC894043, 0x43CC8940, 0x4043CC89, }, /* x=46 */
|
||||
{ 0x87494EC7, 0xC787494E, 0x4EC78749, 0x494EC787, }, /* x=47 */
|
||||
{ 0xDD3E05AE, 0xAEDD3E05, 0x05AEDD3E, 0x3E05AEDD, }, /* x=48 */
|
||||
{ 0xD33708A5, 0xA5D33708, 0x08A5D337, 0x3708A5D3, }, /* x=49 */
|
||||
{ 0xC12C1FB8, 0xB8C12C1F, 0x1FB8C12C, 0x2C1FB8C1, }, /* x=4A */
|
||||
{ 0xCF2512B3, 0xB3CF2512, 0x12B3CF25, 0x2512B3CF, }, /* x=4B */
|
||||
{ 0xE51A3182, 0x82E51A31, 0x3182E51A, 0x1A3182E5, }, /* x=4C */
|
||||
{ 0xEB133C89, 0x89EB133C, 0x3C89EB13, 0x133C89EB, }, /* x=4D */
|
||||
{ 0xF9082B94, 0x94F9082B, 0x2B94F908, 0x082B94F9, }, /* x=4E */
|
||||
{ 0xF701269F, 0x9FF70126, 0x269FF701, 0x01269FF7, }, /* x=4F */
|
||||
{ 0x4DE6BD46, 0x464DE6BD, 0xBD464DE6, 0xE6BD464D, }, /* x=50 */
|
||||
{ 0x43EFB04D, 0x4D43EFB0, 0xB04D43EF, 0xEFB04D43, }, /* x=51 */
|
||||
{ 0x51F4A750, 0x5051F4A7, 0xA75051F4, 0xF4A75051, }, /* x=52 */
|
||||
{ 0x5FFDAA5B, 0x5B5FFDAA, 0xAA5B5FFD, 0xFDAA5B5F, }, /* x=53 */
|
||||
{ 0x75C2896A, 0x6A75C289, 0x896A75C2, 0xC2896A75, }, /* x=54 */
|
||||
{ 0x7BCB8461, 0x617BCB84, 0x84617BCB, 0xCB84617B, }, /* x=55 */
|
||||
{ 0x69D0937C, 0x7C69D093, 0x937C69D0, 0xD0937C69, }, /* x=56 */
|
||||
{ 0x67D99E77, 0x7767D99E, 0x9E7767D9, 0xD99E7767, }, /* x=57 */
|
||||
{ 0x3DAED51E, 0x1E3DAED5, 0xD51E3DAE, 0xAED51E3D, }, /* x=58 */
|
||||
{ 0x33A7D815, 0x1533A7D8, 0xD81533A7, 0xA7D81533, }, /* x=59 */
|
||||
{ 0x21BCCF08, 0x0821BCCF, 0xCF0821BC, 0xBCCF0821, }, /* x=5A */
|
||||
{ 0x2FB5C203, 0x032FB5C2, 0xC2032FB5, 0xB5C2032F, }, /* x=5B */
|
||||
{ 0x058AE132, 0x32058AE1, 0xE132058A, 0x8AE13205, }, /* x=5C */
|
||||
{ 0x0B83EC39, 0x390B83EC, 0xEC390B83, 0x83EC390B, }, /* x=5D */
|
||||
{ 0x1998FB24, 0x241998FB, 0xFB241998, 0x98FB2419, }, /* x=5E */
|
||||
{ 0x1791F62F, 0x2F1791F6, 0xF62F1791, 0x91F62F17, }, /* x=5F */
|
||||
{ 0x764DD68D, 0x8D764DD6, 0xD68D764D, 0x4DD68D76, }, /* x=60 */
|
||||
{ 0x7844DB86, 0x867844DB, 0xDB867844, 0x44DB8678, }, /* x=61 */
|
||||
{ 0x6A5FCC9B, 0x9B6A5FCC, 0xCC9B6A5F, 0x5FCC9B6A, }, /* x=62 */
|
||||
{ 0x6456C190, 0x906456C1, 0xC1906456, 0x56C19064, }, /* x=63 */
|
||||
{ 0x4E69E2A1, 0xA14E69E2, 0xE2A14E69, 0x69E2A14E, }, /* x=64 */
|
||||
{ 0x4060EFAA, 0xAA4060EF, 0xEFAA4060, 0x60EFAA40, }, /* x=65 */
|
||||
{ 0x527BF8B7, 0xB7527BF8, 0xF8B7527B, 0x7BF8B752, }, /* x=66 */
|
||||
{ 0x5C72F5BC, 0xBC5C72F5, 0xF5BC5C72, 0x72F5BC5C, }, /* x=67 */
|
||||
{ 0x0605BED5, 0xD50605BE, 0xBED50605, 0x05BED506, }, /* x=68 */
|
||||
{ 0x080CB3DE, 0xDE080CB3, 0xB3DE080C, 0x0CB3DE08, }, /* x=69 */
|
||||
{ 0x1A17A4C3, 0xC31A17A4, 0xA4C31A17, 0x17A4C31A, }, /* x=6A */
|
||||
{ 0x141EA9C8, 0xC8141EA9, 0xA9C8141E, 0x1EA9C814, }, /* x=6B */
|
||||
{ 0x3E218AF9, 0xF93E218A, 0x8AF93E21, 0x218AF93E, }, /* x=6C */
|
||||
{ 0x302887F2, 0xF2302887, 0x87F23028, 0x2887F230, }, /* x=6D */
|
||||
{ 0x223390EF, 0xEF223390, 0x90EF2233, 0x3390EF22, }, /* x=6E */
|
||||
{ 0x2C3A9DE4, 0xE42C3A9D, 0x9DE42C3A, 0x3A9DE42C, }, /* x=6F */
|
||||
{ 0x96DD063D, 0x3D96DD06, 0x063D96DD, 0xDD063D96, }, /* x=70 */
|
||||
{ 0x98D40B36, 0x3698D40B, 0x0B3698D4, 0xD40B3698, }, /* x=71 */
|
||||
{ 0x8ACF1C2B, 0x2B8ACF1C, 0x1C2B8ACF, 0xCF1C2B8A, }, /* x=72 */
|
||||
{ 0x84C61120, 0x2084C611, 0x112084C6, 0xC6112084, }, /* x=73 */
|
||||
{ 0xAEF93211, 0x11AEF932, 0x3211AEF9, 0xF93211AE, }, /* x=74 */
|
||||
{ 0xA0F03F1A, 0x1AA0F03F, 0x3F1AA0F0, 0xF03F1AA0, }, /* x=75 */
|
||||
{ 0xB2EB2807, 0x07B2EB28, 0x2807B2EB, 0xEB2807B2, }, /* x=76 */
|
||||
{ 0xBCE2250C, 0x0CBCE225, 0x250CBCE2, 0xE2250CBC, }, /* x=77 */
|
||||
{ 0xE6956E65, 0x65E6956E, 0x6E65E695, 0x956E65E6, }, /* x=78 */
|
||||
{ 0xE89C636E, 0x6EE89C63, 0x636EE89C, 0x9C636EE8, }, /* x=79 */
|
||||
{ 0xFA877473, 0x73FA8774, 0x7473FA87, 0x877473FA, }, /* x=7A */
|
||||
{ 0xF48E7978, 0x78F48E79, 0x7978F48E, 0x8E7978F4, }, /* x=7B */
|
||||
{ 0xDEB15A49, 0x49DEB15A, 0x5A49DEB1, 0xB15A49DE, }, /* x=7C */
|
||||
{ 0xD0B85742, 0x42D0B857, 0x5742D0B8, 0xB85742D0, }, /* x=7D */
|
||||
{ 0xC2A3405F, 0x5FC2A340, 0x405FC2A3, 0xA3405FC2, }, /* x=7E */
|
||||
{ 0xCCAA4D54, 0x54CCAA4D, 0x4D54CCAA, 0xAA4D54CC, }, /* x=7F */
|
||||
{ 0x41ECDAF7, 0xF741ECDA, 0xDAF741EC, 0xECDAF741, }, /* x=80 */
|
||||
{ 0x4FE5D7FC, 0xFC4FE5D7, 0xD7FC4FE5, 0xE5D7FC4F, }, /* x=81 */
|
||||
{ 0x5DFEC0E1, 0xE15DFEC0, 0xC0E15DFE, 0xFEC0E15D, }, /* x=82 */
|
||||
{ 0x53F7CDEA, 0xEA53F7CD, 0xCDEA53F7, 0xF7CDEA53, }, /* x=83 */
|
||||
{ 0x79C8EEDB, 0xDB79C8EE, 0xEEDB79C8, 0xC8EEDB79, }, /* x=84 */
|
||||
{ 0x77C1E3D0, 0xD077C1E3, 0xE3D077C1, 0xC1E3D077, }, /* x=85 */
|
||||
{ 0x65DAF4CD, 0xCD65DAF4, 0xF4CD65DA, 0xDAF4CD65, }, /* x=86 */
|
||||
{ 0x6BD3F9C6, 0xC66BD3F9, 0xF9C66BD3, 0xD3F9C66B, }, /* x=87 */
|
||||
{ 0x31A4B2AF, 0xAF31A4B2, 0xB2AF31A4, 0xA4B2AF31, }, /* x=88 */
|
||||
{ 0x3FADBFA4, 0xA43FADBF, 0xBFA43FAD, 0xADBFA43F, }, /* x=89 */
|
||||
{ 0x2DB6A8B9, 0xB92DB6A8, 0xA8B92DB6, 0xB6A8B92D, }, /* x=8A */
|
||||
{ 0x23BFA5B2, 0xB223BFA5, 0xA5B223BF, 0xBFA5B223, }, /* x=8B */
|
||||
{ 0x09808683, 0x83098086, 0x86830980, 0x80868309, }, /* x=8C */
|
||||
{ 0x07898B88, 0x8807898B, 0x8B880789, 0x898B8807, }, /* x=8D */
|
||||
{ 0x15929C95, 0x9515929C, 0x9C951592, 0x929C9515, }, /* x=8E */
|
||||
{ 0x1B9B919E, 0x9E1B9B91, 0x919E1B9B, 0x9B919E1B, }, /* x=8F */
|
||||
{ 0xA17C0A47, 0x47A17C0A, 0x0A47A17C, 0x7C0A47A1, }, /* x=90 */
|
||||
{ 0xAF75074C, 0x4CAF7507, 0x074CAF75, 0x75074CAF, }, /* x=91 */
|
||||
{ 0xBD6E1051, 0x51BD6E10, 0x1051BD6E, 0x6E1051BD, }, /* x=92 */
|
||||
{ 0xB3671D5A, 0x5AB3671D, 0x1D5AB367, 0x671D5AB3, }, /* x=93 */
|
||||
{ 0x99583E6B, 0x6B99583E, 0x3E6B9958, 0x583E6B99, }, /* x=94 */
|
||||
{ 0x97513360, 0x60975133, 0x33609751, 0x51336097, }, /* x=95 */
|
||||
{ 0x854A247D, 0x7D854A24, 0x247D854A, 0x4A247D85, }, /* x=96 */
|
||||
{ 0x8B432976, 0x768B4329, 0x29768B43, 0x4329768B, }, /* x=97 */
|
||||
{ 0xD134621F, 0x1FD13462, 0x621FD134, 0x34621FD1, }, /* x=98 */
|
||||
{ 0xDF3D6F14, 0x14DF3D6F, 0x6F14DF3D, 0x3D6F14DF, }, /* x=99 */
|
||||
{ 0xCD267809, 0x09CD2678, 0x7809CD26, 0x267809CD, }, /* x=9A */
|
||||
{ 0xC32F7502, 0x02C32F75, 0x7502C32F, 0x2F7502C3, }, /* x=9B */
|
||||
{ 0xE9105633, 0x33E91056, 0x5633E910, 0x105633E9, }, /* x=9C */
|
||||
{ 0xE7195B38, 0x38E7195B, 0x5B38E719, 0x195B38E7, }, /* x=9D */
|
||||
{ 0xF5024C25, 0x25F5024C, 0x4C25F502, 0x024C25F5, }, /* x=9E */
|
||||
{ 0xFB0B412E, 0x2EFB0B41, 0x412EFB0B, 0x0B412EFB, }, /* x=9F */
|
||||
{ 0x9AD7618C, 0x8C9AD761, 0x618C9AD7, 0xD7618C9A, }, /* x=A0 */
|
||||
{ 0x94DE6C87, 0x8794DE6C, 0x6C8794DE, 0xDE6C8794, }, /* x=A1 */
|
||||
{ 0x86C57B9A, 0x9A86C57B, 0x7B9A86C5, 0xC57B9A86, }, /* x=A2 */
|
||||
{ 0x88CC7691, 0x9188CC76, 0x769188CC, 0xCC769188, }, /* x=A3 */
|
||||
{ 0xA2F355A0, 0xA0A2F355, 0x55A0A2F3, 0xF355A0A2, }, /* x=A4 */
|
||||
{ 0xACFA58AB, 0xABACFA58, 0x58ABACFA, 0xFA58ABAC, }, /* x=A5 */
|
||||
{ 0xBEE14FB6, 0xB6BEE14F, 0x4FB6BEE1, 0xE14FB6BE, }, /* x=A6 */
|
||||
{ 0xB0E842BD, 0xBDB0E842, 0x42BDB0E8, 0xE842BDB0, }, /* x=A7 */
|
||||
{ 0xEA9F09D4, 0xD4EA9F09, 0x09D4EA9F, 0x9F09D4EA, }, /* x=A8 */
|
||||
{ 0xE49604DF, 0xDFE49604, 0x04DFE496, 0x9604DFE4, }, /* x=A9 */
|
||||
{ 0xF68D13C2, 0xC2F68D13, 0x13C2F68D, 0x8D13C2F6, }, /* x=AA */
|
||||
{ 0xF8841EC9, 0xC9F8841E, 0x1EC9F884, 0x841EC9F8, }, /* x=AB */
|
||||
{ 0xD2BB3DF8, 0xF8D2BB3D, 0x3DF8D2BB, 0xBB3DF8D2, }, /* x=AC */
|
||||
{ 0xDCB230F3, 0xF3DCB230, 0x30F3DCB2, 0xB230F3DC, }, /* x=AD */
|
||||
{ 0xCEA927EE, 0xEECEA927, 0x27EECEA9, 0xA927EECE, }, /* x=AE */
|
||||
{ 0xC0A02AE5, 0xE5C0A02A, 0x2AE5C0A0, 0xA02AE5C0, }, /* x=AF */
|
||||
{ 0x7A47B13C, 0x3C7A47B1, 0xB13C7A47, 0x47B13C7A, }, /* x=B0 */
|
||||
{ 0x744EBC37, 0x37744EBC, 0xBC37744E, 0x4EBC3774, }, /* x=B1 */
|
||||
{ 0x6655AB2A, 0x2A6655AB, 0xAB2A6655, 0x55AB2A66, }, /* x=B2 */
|
||||
{ 0x685CA621, 0x21685CA6, 0xA621685C, 0x5CA62168, }, /* x=B3 */
|
||||
{ 0x42638510, 0x10426385, 0x85104263, 0x63851042, }, /* x=B4 */
|
||||
{ 0x4C6A881B, 0x1B4C6A88, 0x881B4C6A, 0x6A881B4C, }, /* x=B5 */
|
||||
{ 0x5E719F06, 0x065E719F, 0x9F065E71, 0x719F065E, }, /* x=B6 */
|
||||
{ 0x5078920D, 0x0D507892, 0x920D5078, 0x78920D50, }, /* x=B7 */
|
||||
{ 0x0A0FD964, 0x640A0FD9, 0xD9640A0F, 0x0FD9640A, }, /* x=B8 */
|
||||
{ 0x0406D46F, 0x6F0406D4, 0xD46F0406, 0x06D46F04, }, /* x=B9 */
|
||||
{ 0x161DC372, 0x72161DC3, 0xC372161D, 0x1DC37216, }, /* x=BA */
|
||||
{ 0x1814CE79, 0x791814CE, 0xCE791814, 0x14CE7918, }, /* x=BB */
|
||||
{ 0x322BED48, 0x48322BED, 0xED48322B, 0x2BED4832, }, /* x=BC */
|
||||
{ 0x3C22E043, 0x433C22E0, 0xE0433C22, 0x22E0433C, }, /* x=BD */
|
||||
{ 0x2E39F75E, 0x5E2E39F7, 0xF75E2E39, 0x39F75E2E, }, /* x=BE */
|
||||
{ 0x2030FA55, 0x552030FA, 0xFA552030, 0x30FA5520, }, /* x=BF */
|
||||
{ 0xEC9AB701, 0x01EC9AB7, 0xB701EC9A, 0x9AB701EC, }, /* x=C0 */
|
||||
{ 0xE293BA0A, 0x0AE293BA, 0xBA0AE293, 0x93BA0AE2, }, /* x=C1 */
|
||||
{ 0xF088AD17, 0x17F088AD, 0xAD17F088, 0x88AD17F0, }, /* x=C2 */
|
||||
{ 0xFE81A01C, 0x1CFE81A0, 0xA01CFE81, 0x81A01CFE, }, /* x=C3 */
|
||||
{ 0xD4BE832D, 0x2DD4BE83, 0x832DD4BE, 0xBE832DD4, }, /* x=C4 */
|
||||
{ 0xDAB78E26, 0x26DAB78E, 0x8E26DAB7, 0xB78E26DA, }, /* x=C5 */
|
||||
{ 0xC8AC993B, 0x3BC8AC99, 0x993BC8AC, 0xAC993BC8, }, /* x=C6 */
|
||||
{ 0xC6A59430, 0x30C6A594, 0x9430C6A5, 0xA59430C6, }, /* x=C7 */
|
||||
{ 0x9CD2DF59, 0x599CD2DF, 0xDF599CD2, 0xD2DF599C, }, /* x=C8 */
|
||||
{ 0x92DBD252, 0x5292DBD2, 0xD25292DB, 0xDBD25292, }, /* x=C9 */
|
||||
{ 0x80C0C54F, 0x4F80C0C5, 0xC54F80C0, 0xC0C54F80, }, /* x=CA */
|
||||
{ 0x8EC9C844, 0x448EC9C8, 0xC8448EC9, 0xC9C8448E, }, /* x=CB */
|
||||
{ 0xA4F6EB75, 0x75A4F6EB, 0xEB75A4F6, 0xF6EB75A4, }, /* x=CC */
|
||||
{ 0xAAFFE67E, 0x7EAAFFE6, 0xE67EAAFF, 0xFFE67EAA, }, /* x=CD */
|
||||
{ 0xB8E4F163, 0x63B8E4F1, 0xF163B8E4, 0xE4F163B8, }, /* x=CE */
|
||||
{ 0xB6EDFC68, 0x68B6EDFC, 0xFC68B6ED, 0xEDFC68B6, }, /* x=CF */
|
||||
{ 0x0C0A67B1, 0xB10C0A67, 0x67B10C0A, 0x0A67B10C, }, /* x=D0 */
|
||||
{ 0x02036ABA, 0xBA02036A, 0x6ABA0203, 0x036ABA02, }, /* x=D1 */
|
||||
{ 0x10187DA7, 0xA710187D, 0x7DA71018, 0x187DA710, }, /* x=D2 */
|
||||
{ 0x1E1170AC, 0xAC1E1170, 0x70AC1E11, 0x1170AC1E, }, /* x=D3 */
|
||||
{ 0x342E539D, 0x9D342E53, 0x539D342E, 0x2E539D34, }, /* x=D4 */
|
||||
{ 0x3A275E96, 0x963A275E, 0x5E963A27, 0x275E963A, }, /* x=D5 */
|
||||
{ 0x283C498B, 0x8B283C49, 0x498B283C, 0x3C498B28, }, /* x=D6 */
|
||||
{ 0x26354480, 0x80263544, 0x44802635, 0x35448026, }, /* x=D7 */
|
||||
{ 0x7C420FE9, 0xE97C420F, 0x0FE97C42, 0x420FE97C, }, /* x=D8 */
|
||||
{ 0x724B02E2, 0xE2724B02, 0x02E2724B, 0x4B02E272, }, /* x=D9 */
|
||||
{ 0x605015FF, 0xFF605015, 0x15FF6050, 0x5015FF60, }, /* x=DA */
|
||||
{ 0x6E5918F4, 0xF46E5918, 0x18F46E59, 0x5918F46E, }, /* x=DB */
|
||||
{ 0x44663BC5, 0xC544663B, 0x3BC54466, 0x663BC544, }, /* x=DC */
|
||||
{ 0x4A6F36CE, 0xCE4A6F36, 0x36CE4A6F, 0x6F36CE4A, }, /* x=DD */
|
||||
{ 0x587421D3, 0xD3587421, 0x21D35874, 0x7421D358, }, /* x=DE */
|
||||
{ 0x567D2CD8, 0xD8567D2C, 0x2CD8567D, 0x7D2CD856, }, /* x=DF */
|
||||
{ 0x37A10C7A, 0x7A37A10C, 0x0C7A37A1, 0xA10C7A37, }, /* x=E0 */
|
||||
{ 0x39A80171, 0x7139A801, 0x017139A8, 0xA8017139, }, /* x=E1 */
|
||||
{ 0x2BB3166C, 0x6C2BB316, 0x166C2BB3, 0xB3166C2B, }, /* x=E2 */
|
||||
{ 0x25BA1B67, 0x6725BA1B, 0x1B6725BA, 0xBA1B6725, }, /* x=E3 */
|
||||
{ 0x0F853856, 0x560F8538, 0x38560F85, 0x8538560F, }, /* x=E4 */
|
||||
{ 0x018C355D, 0x5D018C35, 0x355D018C, 0x8C355D01, }, /* x=E5 */
|
||||
{ 0x13972240, 0x40139722, 0x22401397, 0x97224013, }, /* x=E6 */
|
||||
{ 0x1D9E2F4B, 0x4B1D9E2F, 0x2F4B1D9E, 0x9E2F4B1D, }, /* x=E7 */
|
||||
{ 0x47E96422, 0x2247E964, 0x642247E9, 0xE9642247, }, /* x=E8 */
|
||||
{ 0x49E06929, 0x2949E069, 0x692949E0, 0xE0692949, }, /* x=E9 */
|
||||
{ 0x5BFB7E34, 0x345BFB7E, 0x7E345BFB, 0xFB7E345B, }, /* x=EA */
|
||||
{ 0x55F2733F, 0x3F55F273, 0x733F55F2, 0xF2733F55, }, /* x=EB */
|
||||
{ 0x7FCD500E, 0x0E7FCD50, 0x500E7FCD, 0xCD500E7F, }, /* x=EC */
|
||||
{ 0x71C45D05, 0x0571C45D, 0x5D0571C4, 0xC45D0571, }, /* x=ED */
|
||||
{ 0x63DF4A18, 0x1863DF4A, 0x4A1863DF, 0xDF4A1863, }, /* x=EE */
|
||||
{ 0x6DD64713, 0x136DD647, 0x47136DD6, 0xD647136D, }, /* x=EF */
|
||||
{ 0xD731DCCA, 0xCAD731DC, 0xDCCAD731, 0x31DCCAD7, }, /* x=F0 */
|
||||
{ 0xD938D1C1, 0xC1D938D1, 0xD1C1D938, 0x38D1C1D9, }, /* x=F1 */
|
||||
{ 0xCB23C6DC, 0xDCCB23C6, 0xC6DCCB23, 0x23C6DCCB, }, /* x=F2 */
|
||||
{ 0xC52ACBD7, 0xD7C52ACB, 0xCBD7C52A, 0x2ACBD7C5, }, /* x=F3 */
|
||||
{ 0xEF15E8E6, 0xE6EF15E8, 0xE8E6EF15, 0x15E8E6EF, }, /* x=F4 */
|
||||
{ 0xE11CE5ED, 0xEDE11CE5, 0xE5EDE11C, 0x1CE5EDE1, }, /* x=F5 */
|
||||
{ 0xF307F2F0, 0xF0F307F2, 0xF2F0F307, 0x07F2F0F3, }, /* x=F6 */
|
||||
{ 0xFD0EFFFB, 0xFBFD0EFF, 0xFFFBFD0E, 0x0EFFFBFD, }, /* x=F7 */
|
||||
{ 0xA779B492, 0x92A779B4, 0xB492A779, 0x79B492A7, }, /* x=F8 */
|
||||
{ 0xA970B999, 0x99A970B9, 0xB999A970, 0x70B999A9, }, /* x=F9 */
|
||||
{ 0xBB6BAE84, 0x84BB6BAE, 0xAE84BB6B, 0x6BAE84BB, }, /* x=FA */
|
||||
{ 0xB562A38F, 0x8FB562A3, 0xA38FB562, 0x62A38FB5, }, /* x=FB */
|
||||
{ 0x9F5D80BE, 0xBE9F5D80, 0x80BE9F5D, 0x5D80BE9F, }, /* x=FC */
|
||||
{ 0x91548DB5, 0xB591548D, 0x8DB59154, 0x548DB591, }, /* x=FD */
|
||||
{ 0x834F9AA8, 0xA8834F9A, 0x9AA8834F, 0x4F9AA883, }, /* x=FE */
|
||||
{ 0x8D4697A3, 0xA38D4697, 0x97A38D46, 0x4697A38D, }, /* x=FF */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
AES_Te0[x] = S [x].[02, 01, 01, 03];
|
||||
@@ -272,7 +395,7 @@ AES_Td3[x] = Si[x].[09, 0d, 0b, 0e];
|
||||
AES_Td4[x] = Si[x].[01, 01, 01, 01];
|
||||
*/
|
||||
|
||||
static const uint32_t AES_Te0[256] = {
|
||||
const uint32_t AES_Te0[256] = {
|
||||
0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
|
||||
0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
|
||||
0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
|
||||
@@ -338,8 +461,7 @@ static const uint32_t AES_Te0[256] = {
|
||||
0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
|
||||
0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
|
||||
};
|
||||
|
||||
static const uint32_t AES_Te1[256] = {
|
||||
const uint32_t AES_Te1[256] = {
|
||||
0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
|
||||
0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
|
||||
0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
|
||||
@@ -405,8 +527,7 @@ static const uint32_t AES_Te1[256] = {
|
||||
0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
|
||||
0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
|
||||
};
|
||||
|
||||
static const uint32_t AES_Te2[256] = {
|
||||
const uint32_t AES_Te2[256] = {
|
||||
0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
|
||||
0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
|
||||
0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
|
||||
@@ -472,8 +593,8 @@ static const uint32_t AES_Te2[256] = {
|
||||
0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
|
||||
0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
|
||||
};
|
||||
const uint32_t AES_Te3[256] = {
|
||||
|
||||
static const uint32_t AES_Te3[256] = {
|
||||
0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
|
||||
0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
|
||||
0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
|
||||
@@ -539,8 +660,7 @@ static const uint32_t AES_Te3[256] = {
|
||||
0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
|
||||
0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
|
||||
};
|
||||
|
||||
static const uint32_t AES_Te4[256] = {
|
||||
const uint32_t AES_Te4[256] = {
|
||||
0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
|
||||
0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
|
||||
0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
|
||||
@@ -606,8 +726,7 @@ static const uint32_t AES_Te4[256] = {
|
||||
0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
|
||||
0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
|
||||
};
|
||||
|
||||
static const uint32_t AES_Td0[256] = {
|
||||
const uint32_t AES_Td0[256] = {
|
||||
0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
|
||||
0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
|
||||
0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
|
||||
@@ -673,8 +792,7 @@ static const uint32_t AES_Td0[256] = {
|
||||
0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
|
||||
0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
|
||||
};
|
||||
|
||||
static const uint32_t AES_Td1[256] = {
|
||||
const uint32_t AES_Td1[256] = {
|
||||
0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
|
||||
0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
|
||||
0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
|
||||
@@ -740,8 +858,7 @@ static const uint32_t AES_Td1[256] = {
|
||||
0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
|
||||
0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
|
||||
};
|
||||
|
||||
static const uint32_t AES_Td2[256] = {
|
||||
const uint32_t AES_Td2[256] = {
|
||||
0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
|
||||
0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
|
||||
0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
|
||||
@@ -808,8 +925,7 @@ static const uint32_t AES_Td2[256] = {
|
||||
0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
|
||||
0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
|
||||
};
|
||||
|
||||
static const uint32_t AES_Td3[256] = {
|
||||
const uint32_t AES_Td3[256] = {
|
||||
0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
|
||||
0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
|
||||
0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
|
||||
@@ -875,8 +991,7 @@ static const uint32_t AES_Td3[256] = {
|
||||
0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
|
||||
0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
|
||||
};
|
||||
|
||||
static const uint32_t AES_Td4[256] = {
|
||||
const uint32_t AES_Td4[256] = {
|
||||
0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
|
||||
0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
|
||||
0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
|
||||
@@ -942,351 +1057,12 @@ static const uint32_t AES_Td4[256] = {
|
||||
0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
|
||||
0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
|
||||
};
|
||||
|
||||
static const u32 rcon[] = {
|
||||
0x01000000, 0x02000000, 0x04000000, 0x08000000,
|
||||
0x10000000, 0x20000000, 0x40000000, 0x80000000,
|
||||
0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
|
||||
};
|
||||
|
||||
/*
|
||||
* Perform MixColumns.
|
||||
*/
|
||||
static inline void
|
||||
aesenc_MC_swap(AESState *r, const AESState *st, bool swap)
|
||||
{
|
||||
int swap_b = swap * 0xf;
|
||||
int swap_w = swap * 0x3;
|
||||
bool be = HOST_BIG_ENDIAN ^ swap;
|
||||
uint32_t t;
|
||||
|
||||
/* Note that AES_mc_rot is encoded for little-endian. */
|
||||
t = ( AES_mc_rot[st->b[swap_b ^ 0x0]] ^
|
||||
rol32(AES_mc_rot[st->b[swap_b ^ 0x1]], 8) ^
|
||||
rol32(AES_mc_rot[st->b[swap_b ^ 0x2]], 16) ^
|
||||
rol32(AES_mc_rot[st->b[swap_b ^ 0x3]], 24));
|
||||
if (be) {
|
||||
t = bswap32(t);
|
||||
}
|
||||
r->w[swap_w ^ 0] = t;
|
||||
|
||||
t = ( AES_mc_rot[st->b[swap_b ^ 0x4]] ^
|
||||
rol32(AES_mc_rot[st->b[swap_b ^ 0x5]], 8) ^
|
||||
rol32(AES_mc_rot[st->b[swap_b ^ 0x6]], 16) ^
|
||||
rol32(AES_mc_rot[st->b[swap_b ^ 0x7]], 24));
|
||||
if (be) {
|
||||
t = bswap32(t);
|
||||
}
|
||||
r->w[swap_w ^ 1] = t;
|
||||
|
||||
t = ( AES_mc_rot[st->b[swap_b ^ 0x8]] ^
|
||||
rol32(AES_mc_rot[st->b[swap_b ^ 0x9]], 8) ^
|
||||
rol32(AES_mc_rot[st->b[swap_b ^ 0xA]], 16) ^
|
||||
rol32(AES_mc_rot[st->b[swap_b ^ 0xB]], 24));
|
||||
if (be) {
|
||||
t = bswap32(t);
|
||||
}
|
||||
r->w[swap_w ^ 2] = t;
|
||||
|
||||
t = ( AES_mc_rot[st->b[swap_b ^ 0xC]] ^
|
||||
rol32(AES_mc_rot[st->b[swap_b ^ 0xD]], 8) ^
|
||||
rol32(AES_mc_rot[st->b[swap_b ^ 0xE]], 16) ^
|
||||
rol32(AES_mc_rot[st->b[swap_b ^ 0xF]], 24));
|
||||
if (be) {
|
||||
t = bswap32(t);
|
||||
}
|
||||
r->w[swap_w ^ 3] = t;
|
||||
}
|
||||
|
||||
void aesenc_MC_gen(AESState *r, const AESState *st)
|
||||
{
|
||||
aesenc_MC_swap(r, st, false);
|
||||
}
|
||||
|
||||
void aesenc_MC_genrev(AESState *r, const AESState *st)
|
||||
{
|
||||
aesenc_MC_swap(r, st, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform SubBytes + ShiftRows + AddRoundKey.
|
||||
*/
|
||||
static inline void
|
||||
aesenc_SB_SR_AK_swap(AESState *ret, const AESState *st,
|
||||
const AESState *rk, bool swap)
|
||||
{
|
||||
const int swap_b = swap ? 15 : 0;
|
||||
AESState t;
|
||||
|
||||
t.b[swap_b ^ 0x0] = AES_sbox[st->b[swap_b ^ AES_SH(0x0)]];
|
||||
t.b[swap_b ^ 0x1] = AES_sbox[st->b[swap_b ^ AES_SH(0x1)]];
|
||||
t.b[swap_b ^ 0x2] = AES_sbox[st->b[swap_b ^ AES_SH(0x2)]];
|
||||
t.b[swap_b ^ 0x3] = AES_sbox[st->b[swap_b ^ AES_SH(0x3)]];
|
||||
t.b[swap_b ^ 0x4] = AES_sbox[st->b[swap_b ^ AES_SH(0x4)]];
|
||||
t.b[swap_b ^ 0x5] = AES_sbox[st->b[swap_b ^ AES_SH(0x5)]];
|
||||
t.b[swap_b ^ 0x6] = AES_sbox[st->b[swap_b ^ AES_SH(0x6)]];
|
||||
t.b[swap_b ^ 0x7] = AES_sbox[st->b[swap_b ^ AES_SH(0x7)]];
|
||||
t.b[swap_b ^ 0x8] = AES_sbox[st->b[swap_b ^ AES_SH(0x8)]];
|
||||
t.b[swap_b ^ 0x9] = AES_sbox[st->b[swap_b ^ AES_SH(0x9)]];
|
||||
t.b[swap_b ^ 0xa] = AES_sbox[st->b[swap_b ^ AES_SH(0xA)]];
|
||||
t.b[swap_b ^ 0xb] = AES_sbox[st->b[swap_b ^ AES_SH(0xB)]];
|
||||
t.b[swap_b ^ 0xc] = AES_sbox[st->b[swap_b ^ AES_SH(0xC)]];
|
||||
t.b[swap_b ^ 0xd] = AES_sbox[st->b[swap_b ^ AES_SH(0xD)]];
|
||||
t.b[swap_b ^ 0xe] = AES_sbox[st->b[swap_b ^ AES_SH(0xE)]];
|
||||
t.b[swap_b ^ 0xf] = AES_sbox[st->b[swap_b ^ AES_SH(0xF)]];
|
||||
|
||||
/*
|
||||
* Perform the AddRoundKey with generic vectors.
|
||||
* This may be expanded to either host integer or host vector code.
|
||||
* The key and output endianness match, so no bswap required.
|
||||
*/
|
||||
ret->v = t.v ^ rk->v;
|
||||
}
|
||||
|
||||
void aesenc_SB_SR_AK_gen(AESState *r, const AESState *s, const AESState *k)
|
||||
{
|
||||
aesenc_SB_SR_AK_swap(r, s, k, false);
|
||||
}
|
||||
|
||||
void aesenc_SB_SR_AK_genrev(AESState *r, const AESState *s, const AESState *k)
|
||||
{
|
||||
aesenc_SB_SR_AK_swap(r, s, k, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform SubBytes + ShiftRows + MixColumns + AddRoundKey.
|
||||
*/
|
||||
static inline void
|
||||
aesenc_SB_SR_MC_AK_swap(AESState *r, const AESState *st,
|
||||
const AESState *rk, bool swap)
|
||||
{
|
||||
int swap_b = swap * 0xf;
|
||||
int swap_w = swap * 0x3;
|
||||
bool be = HOST_BIG_ENDIAN ^ swap;
|
||||
uint32_t w0, w1, w2, w3;
|
||||
|
||||
w0 = (AES_Te0[st->b[swap_b ^ AES_SH(0x0)]] ^
|
||||
AES_Te1[st->b[swap_b ^ AES_SH(0x1)]] ^
|
||||
AES_Te2[st->b[swap_b ^ AES_SH(0x2)]] ^
|
||||
AES_Te3[st->b[swap_b ^ AES_SH(0x3)]]);
|
||||
|
||||
w1 = (AES_Te0[st->b[swap_b ^ AES_SH(0x4)]] ^
|
||||
AES_Te1[st->b[swap_b ^ AES_SH(0x5)]] ^
|
||||
AES_Te2[st->b[swap_b ^ AES_SH(0x6)]] ^
|
||||
AES_Te3[st->b[swap_b ^ AES_SH(0x7)]]);
|
||||
|
||||
w2 = (AES_Te0[st->b[swap_b ^ AES_SH(0x8)]] ^
|
||||
AES_Te1[st->b[swap_b ^ AES_SH(0x9)]] ^
|
||||
AES_Te2[st->b[swap_b ^ AES_SH(0xA)]] ^
|
||||
AES_Te3[st->b[swap_b ^ AES_SH(0xB)]]);
|
||||
|
||||
w3 = (AES_Te0[st->b[swap_b ^ AES_SH(0xC)]] ^
|
||||
AES_Te1[st->b[swap_b ^ AES_SH(0xD)]] ^
|
||||
AES_Te2[st->b[swap_b ^ AES_SH(0xE)]] ^
|
||||
AES_Te3[st->b[swap_b ^ AES_SH(0xF)]]);
|
||||
|
||||
/* Note that AES_TeX is encoded for big-endian. */
|
||||
if (!be) {
|
||||
w0 = bswap32(w0);
|
||||
w1 = bswap32(w1);
|
||||
w2 = bswap32(w2);
|
||||
w3 = bswap32(w3);
|
||||
}
|
||||
|
||||
r->w[swap_w ^ 0] = rk->w[swap_w ^ 0] ^ w0;
|
||||
r->w[swap_w ^ 1] = rk->w[swap_w ^ 1] ^ w1;
|
||||
r->w[swap_w ^ 2] = rk->w[swap_w ^ 2] ^ w2;
|
||||
r->w[swap_w ^ 3] = rk->w[swap_w ^ 3] ^ w3;
|
||||
}
|
||||
|
||||
void aesenc_SB_SR_MC_AK_gen(AESState *r, const AESState *st,
|
||||
const AESState *rk)
|
||||
{
|
||||
aesenc_SB_SR_MC_AK_swap(r, st, rk, false);
|
||||
}
|
||||
|
||||
void aesenc_SB_SR_MC_AK_genrev(AESState *r, const AESState *st,
|
||||
const AESState *rk)
|
||||
{
|
||||
aesenc_SB_SR_MC_AK_swap(r, st, rk, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform InvMixColumns.
|
||||
*/
|
||||
static inline void
|
||||
aesdec_IMC_swap(AESState *r, const AESState *st, bool swap)
|
||||
{
|
||||
int swap_b = swap * 0xf;
|
||||
int swap_w = swap * 0x3;
|
||||
bool be = HOST_BIG_ENDIAN ^ swap;
|
||||
uint32_t t;
|
||||
|
||||
/* Note that AES_imc_rot is encoded for little-endian. */
|
||||
t = ( AES_imc_rot[st->b[swap_b ^ 0x0]] ^
|
||||
rol32(AES_imc_rot[st->b[swap_b ^ 0x1]], 8) ^
|
||||
rol32(AES_imc_rot[st->b[swap_b ^ 0x2]], 16) ^
|
||||
rol32(AES_imc_rot[st->b[swap_b ^ 0x3]], 24));
|
||||
if (be) {
|
||||
t = bswap32(t);
|
||||
}
|
||||
r->w[swap_w ^ 0] = t;
|
||||
|
||||
t = ( AES_imc_rot[st->b[swap_b ^ 0x4]] ^
|
||||
rol32(AES_imc_rot[st->b[swap_b ^ 0x5]], 8) ^
|
||||
rol32(AES_imc_rot[st->b[swap_b ^ 0x6]], 16) ^
|
||||
rol32(AES_imc_rot[st->b[swap_b ^ 0x7]], 24));
|
||||
if (be) {
|
||||
t = bswap32(t);
|
||||
}
|
||||
r->w[swap_w ^ 1] = t;
|
||||
|
||||
t = ( AES_imc_rot[st->b[swap_b ^ 0x8]] ^
|
||||
rol32(AES_imc_rot[st->b[swap_b ^ 0x9]], 8) ^
|
||||
rol32(AES_imc_rot[st->b[swap_b ^ 0xA]], 16) ^
|
||||
rol32(AES_imc_rot[st->b[swap_b ^ 0xB]], 24));
|
||||
if (be) {
|
||||
t = bswap32(t);
|
||||
}
|
||||
r->w[swap_w ^ 2] = t;
|
||||
|
||||
t = ( AES_imc_rot[st->b[swap_b ^ 0xC]] ^
|
||||
rol32(AES_imc_rot[st->b[swap_b ^ 0xD]], 8) ^
|
||||
rol32(AES_imc_rot[st->b[swap_b ^ 0xE]], 16) ^
|
||||
rol32(AES_imc_rot[st->b[swap_b ^ 0xF]], 24));
|
||||
if (be) {
|
||||
t = bswap32(t);
|
||||
}
|
||||
r->w[swap_w ^ 3] = t;
|
||||
}
|
||||
|
||||
void aesdec_IMC_gen(AESState *r, const AESState *st)
|
||||
{
|
||||
aesdec_IMC_swap(r, st, false);
|
||||
}
|
||||
|
||||
void aesdec_IMC_genrev(AESState *r, const AESState *st)
|
||||
{
|
||||
aesdec_IMC_swap(r, st, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform InvSubBytes + InvShiftRows + AddRoundKey.
|
||||
*/
|
||||
static inline void
|
||||
aesdec_ISB_ISR_AK_swap(AESState *ret, const AESState *st,
|
||||
const AESState *rk, bool swap)
|
||||
{
|
||||
const int swap_b = swap ? 15 : 0;
|
||||
AESState t;
|
||||
|
||||
t.b[swap_b ^ 0x0] = AES_isbox[st->b[swap_b ^ AES_ISH(0x0)]];
|
||||
t.b[swap_b ^ 0x1] = AES_isbox[st->b[swap_b ^ AES_ISH(0x1)]];
|
||||
t.b[swap_b ^ 0x2] = AES_isbox[st->b[swap_b ^ AES_ISH(0x2)]];
|
||||
t.b[swap_b ^ 0x3] = AES_isbox[st->b[swap_b ^ AES_ISH(0x3)]];
|
||||
t.b[swap_b ^ 0x4] = AES_isbox[st->b[swap_b ^ AES_ISH(0x4)]];
|
||||
t.b[swap_b ^ 0x5] = AES_isbox[st->b[swap_b ^ AES_ISH(0x5)]];
|
||||
t.b[swap_b ^ 0x6] = AES_isbox[st->b[swap_b ^ AES_ISH(0x6)]];
|
||||
t.b[swap_b ^ 0x7] = AES_isbox[st->b[swap_b ^ AES_ISH(0x7)]];
|
||||
t.b[swap_b ^ 0x8] = AES_isbox[st->b[swap_b ^ AES_ISH(0x8)]];
|
||||
t.b[swap_b ^ 0x9] = AES_isbox[st->b[swap_b ^ AES_ISH(0x9)]];
|
||||
t.b[swap_b ^ 0xa] = AES_isbox[st->b[swap_b ^ AES_ISH(0xA)]];
|
||||
t.b[swap_b ^ 0xb] = AES_isbox[st->b[swap_b ^ AES_ISH(0xB)]];
|
||||
t.b[swap_b ^ 0xc] = AES_isbox[st->b[swap_b ^ AES_ISH(0xC)]];
|
||||
t.b[swap_b ^ 0xd] = AES_isbox[st->b[swap_b ^ AES_ISH(0xD)]];
|
||||
t.b[swap_b ^ 0xe] = AES_isbox[st->b[swap_b ^ AES_ISH(0xE)]];
|
||||
t.b[swap_b ^ 0xf] = AES_isbox[st->b[swap_b ^ AES_ISH(0xF)]];
|
||||
|
||||
/*
|
||||
* Perform the AddRoundKey with generic vectors.
|
||||
* This may be expanded to either host integer or host vector code.
|
||||
* The key and output endianness match, so no bswap required.
|
||||
*/
|
||||
ret->v = t.v ^ rk->v;
|
||||
}
|
||||
|
||||
void aesdec_ISB_ISR_AK_gen(AESState *r, const AESState *s, const AESState *k)
|
||||
{
|
||||
aesdec_ISB_ISR_AK_swap(r, s, k, false);
|
||||
}
|
||||
|
||||
void aesdec_ISB_ISR_AK_genrev(AESState *r, const AESState *s, const AESState *k)
|
||||
{
|
||||
aesdec_ISB_ISR_AK_swap(r, s, k, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform InvSubBytes + InvShiftRows + InvMixColumns + AddRoundKey.
|
||||
*/
|
||||
static inline void
|
||||
aesdec_ISB_ISR_IMC_AK_swap(AESState *r, const AESState *st,
|
||||
const AESState *rk, bool swap)
|
||||
{
|
||||
int swap_b = swap * 0xf;
|
||||
int swap_w = swap * 0x3;
|
||||
bool be = HOST_BIG_ENDIAN ^ swap;
|
||||
uint32_t w0, w1, w2, w3;
|
||||
|
||||
w0 = (AES_Td0[st->b[swap_b ^ AES_ISH(0x0)]] ^
|
||||
AES_Td1[st->b[swap_b ^ AES_ISH(0x1)]] ^
|
||||
AES_Td2[st->b[swap_b ^ AES_ISH(0x2)]] ^
|
||||
AES_Td3[st->b[swap_b ^ AES_ISH(0x3)]]);
|
||||
|
||||
w1 = (AES_Td0[st->b[swap_b ^ AES_ISH(0x4)]] ^
|
||||
AES_Td1[st->b[swap_b ^ AES_ISH(0x5)]] ^
|
||||
AES_Td2[st->b[swap_b ^ AES_ISH(0x6)]] ^
|
||||
AES_Td3[st->b[swap_b ^ AES_ISH(0x7)]]);
|
||||
|
||||
w2 = (AES_Td0[st->b[swap_b ^ AES_ISH(0x8)]] ^
|
||||
AES_Td1[st->b[swap_b ^ AES_ISH(0x9)]] ^
|
||||
AES_Td2[st->b[swap_b ^ AES_ISH(0xA)]] ^
|
||||
AES_Td3[st->b[swap_b ^ AES_ISH(0xB)]]);
|
||||
|
||||
w3 = (AES_Td0[st->b[swap_b ^ AES_ISH(0xC)]] ^
|
||||
AES_Td1[st->b[swap_b ^ AES_ISH(0xD)]] ^
|
||||
AES_Td2[st->b[swap_b ^ AES_ISH(0xE)]] ^
|
||||
AES_Td3[st->b[swap_b ^ AES_ISH(0xF)]]);
|
||||
|
||||
/* Note that AES_TdX is encoded for big-endian. */
|
||||
if (!be) {
|
||||
w0 = bswap32(w0);
|
||||
w1 = bswap32(w1);
|
||||
w2 = bswap32(w2);
|
||||
w3 = bswap32(w3);
|
||||
}
|
||||
|
||||
r->w[swap_w ^ 0] = rk->w[swap_w ^ 0] ^ w0;
|
||||
r->w[swap_w ^ 1] = rk->w[swap_w ^ 1] ^ w1;
|
||||
r->w[swap_w ^ 2] = rk->w[swap_w ^ 2] ^ w2;
|
||||
r->w[swap_w ^ 3] = rk->w[swap_w ^ 3] ^ w3;
|
||||
}
|
||||
|
||||
void aesdec_ISB_ISR_IMC_AK_gen(AESState *r, const AESState *st,
|
||||
const AESState *rk)
|
||||
{
|
||||
aesdec_ISB_ISR_IMC_AK_swap(r, st, rk, false);
|
||||
}
|
||||
|
||||
void aesdec_ISB_ISR_IMC_AK_genrev(AESState *r, const AESState *st,
|
||||
const AESState *rk)
|
||||
{
|
||||
aesdec_ISB_ISR_IMC_AK_swap(r, st, rk, true);
|
||||
}
|
||||
|
||||
void aesdec_ISB_ISR_AK_IMC_gen(AESState *ret, const AESState *st,
|
||||
const AESState *rk)
|
||||
{
|
||||
aesdec_ISB_ISR_AK_gen(ret, st, rk);
|
||||
aesdec_IMC_gen(ret, ret);
|
||||
}
|
||||
|
||||
void aesdec_ISB_ISR_AK_IMC_genrev(AESState *ret, const AESState *st,
|
||||
const AESState *rk)
|
||||
{
|
||||
aesdec_ISB_ISR_AK_genrev(ret, st, rk);
|
||||
aesdec_IMC_genrev(ret, ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand the cipher key into the encryption key schedule.
|
||||
*/
|
||||
|
||||
@@ -706,14 +706,14 @@ qcrypto_block_luks_store_key(QCryptoBlock *block,
|
||||
|
||||
assert(slot_idx < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS);
|
||||
slot = &luks->header.key_slots[slot_idx];
|
||||
splitkeylen = luks->header.master_key_len * slot->stripes;
|
||||
|
||||
if (qcrypto_random_bytes(slot->salt,
|
||||
QCRYPTO_BLOCK_LUKS_SALT_LEN,
|
||||
errp) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
splitkeylen = luks->header.master_key_len * slot->stripes;
|
||||
|
||||
/*
|
||||
* Determine how many iterations are required to
|
||||
* hash the user password while consuming 1 second of compute
|
||||
|
||||
@@ -6,11 +6,7 @@ common_ss.add(when: 'CONFIG_M68K_DIS', if_true: files('m68k.c'))
|
||||
common_ss.add(when: 'CONFIG_MICROBLAZE_DIS', if_true: files('microblaze.c'))
|
||||
common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c', 'nanomips.c'))
|
||||
common_ss.add(when: 'CONFIG_NIOS2_DIS', if_true: files('nios2.c'))
|
||||
common_ss.add(when: 'CONFIG_RISCV_DIS', if_true: files(
|
||||
'riscv.c',
|
||||
'riscv-xthead.c',
|
||||
'riscv-xventana.c'
|
||||
))
|
||||
common_ss.add(when: 'CONFIG_RISCV_DIS', if_true: files('riscv.c'))
|
||||
common_ss.add(when: 'CONFIG_SH4_DIS', if_true: files('sh4.c'))
|
||||
common_ss.add(when: 'CONFIG_SPARC_DIS', if_true: files('sparc.c'))
|
||||
common_ss.add(when: 'CONFIG_XTENSA_DIS', if_true: files('xtensa.c'))
|
||||
|
||||
@@ -1,707 +0,0 @@
|
||||
/*
|
||||
* QEMU RISC-V Disassembler for xthead.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "disas/riscv.h"
|
||||
#include "disas/riscv-xthead.h"
|
||||
|
||||
typedef enum {
|
||||
/* 0 is reserved for rv_op_illegal. */
|
||||
/* XTheadBa */
|
||||
rv_op_th_addsl = 1,
|
||||
/* XTheadBb */
|
||||
rv_op_th_srri,
|
||||
rv_op_th_srriw,
|
||||
rv_op_th_ext,
|
||||
rv_op_th_extu,
|
||||
rv_op_th_ff0,
|
||||
rv_op_th_ff1,
|
||||
rv_op_th_rev,
|
||||
rv_op_th_revw,
|
||||
rv_op_th_tstnbz,
|
||||
/* XTheadBs */
|
||||
rv_op_th_tst,
|
||||
/* XTheadCmo */
|
||||
rv_op_th_dcache_call,
|
||||
rv_op_th_dcache_ciall,
|
||||
rv_op_th_dcache_iall,
|
||||
rv_op_th_dcache_cpa,
|
||||
rv_op_th_dcache_cipa,
|
||||
rv_op_th_dcache_ipa,
|
||||
rv_op_th_dcache_cva,
|
||||
rv_op_th_dcache_civa,
|
||||
rv_op_th_dcache_iva,
|
||||
rv_op_th_dcache_csw,
|
||||
rv_op_th_dcache_cisw,
|
||||
rv_op_th_dcache_isw,
|
||||
rv_op_th_dcache_cpal1,
|
||||
rv_op_th_dcache_cval1,
|
||||
rv_op_th_icache_iall,
|
||||
rv_op_th_icache_ialls,
|
||||
rv_op_th_icache_ipa,
|
||||
rv_op_th_icache_iva,
|
||||
rv_op_th_l2cache_call,
|
||||
rv_op_th_l2cache_ciall,
|
||||
rv_op_th_l2cache_iall,
|
||||
/* XTheadCondMov */
|
||||
rv_op_th_mveqz,
|
||||
rv_op_th_mvnez,
|
||||
/* XTheadFMemIdx */
|
||||
rv_op_th_flrd,
|
||||
rv_op_th_flrw,
|
||||
rv_op_th_flurd,
|
||||
rv_op_th_flurw,
|
||||
rv_op_th_fsrd,
|
||||
rv_op_th_fsrw,
|
||||
rv_op_th_fsurd,
|
||||
rv_op_th_fsurw,
|
||||
/* XTheadFmv */
|
||||
rv_op_th_fmv_hw_x,
|
||||
rv_op_th_fmv_x_hw,
|
||||
/* XTheadMac */
|
||||
rv_op_th_mula,
|
||||
rv_op_th_mulah,
|
||||
rv_op_th_mulaw,
|
||||
rv_op_th_muls,
|
||||
rv_op_th_mulsw,
|
||||
rv_op_th_mulsh,
|
||||
/* XTheadMemIdx */
|
||||
rv_op_th_lbia,
|
||||
rv_op_th_lbib,
|
||||
rv_op_th_lbuia,
|
||||
rv_op_th_lbuib,
|
||||
rv_op_th_lhia,
|
||||
rv_op_th_lhib,
|
||||
rv_op_th_lhuia,
|
||||
rv_op_th_lhuib,
|
||||
rv_op_th_lwia,
|
||||
rv_op_th_lwib,
|
||||
rv_op_th_lwuia,
|
||||
rv_op_th_lwuib,
|
||||
rv_op_th_ldia,
|
||||
rv_op_th_ldib,
|
||||
rv_op_th_sbia,
|
||||
rv_op_th_sbib,
|
||||
rv_op_th_shia,
|
||||
rv_op_th_shib,
|
||||
rv_op_th_swia,
|
||||
rv_op_th_swib,
|
||||
rv_op_th_sdia,
|
||||
rv_op_th_sdib,
|
||||
rv_op_th_lrb,
|
||||
rv_op_th_lrbu,
|
||||
rv_op_th_lrh,
|
||||
rv_op_th_lrhu,
|
||||
rv_op_th_lrw,
|
||||
rv_op_th_lrwu,
|
||||
rv_op_th_lrd,
|
||||
rv_op_th_srb,
|
||||
rv_op_th_srh,
|
||||
rv_op_th_srw,
|
||||
rv_op_th_srd,
|
||||
rv_op_th_lurb,
|
||||
rv_op_th_lurbu,
|
||||
rv_op_th_lurh,
|
||||
rv_op_th_lurhu,
|
||||
rv_op_th_lurw,
|
||||
rv_op_th_lurwu,
|
||||
rv_op_th_lurd,
|
||||
rv_op_th_surb,
|
||||
rv_op_th_surh,
|
||||
rv_op_th_surw,
|
||||
rv_op_th_surd,
|
||||
/* XTheadMemPair */
|
||||
rv_op_th_ldd,
|
||||
rv_op_th_lwd,
|
||||
rv_op_th_lwud,
|
||||
rv_op_th_sdd,
|
||||
rv_op_th_swd,
|
||||
/* XTheadSync */
|
||||
rv_op_th_sfence_vmas,
|
||||
rv_op_th_sync,
|
||||
rv_op_th_sync_i,
|
||||
rv_op_th_sync_is,
|
||||
rv_op_th_sync_s,
|
||||
} rv_xthead_op;
|
||||
|
||||
const rv_opcode_data xthead_opcode_data[] = {
|
||||
{ "th.illegal", rv_codec_illegal, rv_fmt_none, NULL, 0, 0, 0 },
|
||||
/* XTheadBa */
|
||||
{ "th.addsl", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
/* XTheadBb */
|
||||
{ "th.srri", rv_codec_r2_imm6, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 },
|
||||
{ "th.srriw", rv_codec_r2_imm5, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 },
|
||||
{ "th.ext", rv_codec_r2_immhl, rv_fmt_rd_rs1_immh_imml, NULL, 0, 0, 0 },
|
||||
{ "th.extu", rv_codec_r2_immhl, rv_fmt_rd_rs1_immh_imml, NULL, 0, 0, 0 },
|
||||
{ "th.ff0", rv_codec_r2, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.ff1", rv_codec_r2, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.rev", rv_codec_r2, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.revw", rv_codec_r2, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.tstnbz", rv_codec_r2, rv_fmt_rd_rs1, NULL, 0, 0, 0 },
|
||||
/* XTheadBs */
|
||||
{ "th.tst", rv_codec_r2_imm6, rv_fmt_rd_rs1_imm, NULL, 0, 0, 0 },
|
||||
/* XTheadCmo */
|
||||
{ "th.dcache.call", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
|
||||
{ "th.dcache.ciall", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
|
||||
{ "th.dcache.iall", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
|
||||
{ "th.dcache.cpa", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.dcache.cipa", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.dcache.ipa", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.dcache.cva", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.dcache.civa", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.dcache.iva", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.dcache.csw", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.dcache.cisw", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.dcache.isw", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.dcache.cpal1", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.dcache.cval1", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.icache.iall", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
|
||||
{ "th.icache.ialls", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
|
||||
{ "th.icache.ipa", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.icache.iva", rv_codec_r, rv_fmt_rs1, NULL, 0, 0, 0 },
|
||||
{ "th.l2cache.call", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
|
||||
{ "th.l2cache.ciall", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
|
||||
{ "th.l2cache.iall", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
|
||||
/* XTheadCondMov */
|
||||
{ "th.mveqz", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
{ "th.mvnez", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
/* XTheadFMemIdx */
|
||||
{ "th.flrd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.flrw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.flurd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.flurw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.fsrd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.fsrw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.fsurd", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.fsurw", rv_codec_r_imm2, rv_fmt_frd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
/* XTheadFmv */
|
||||
{ "th.fmv.hw.x", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 },
|
||||
{ "th.fmv.x.hw", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 },
|
||||
/* XTheadMac */
|
||||
{ "th.mula", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
{ "th.mulaw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
{ "th.mulah", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
{ "th.muls", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
{ "th.mulsw", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
{ "th.mulsh", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
/* XTheadMemIdx */
|
||||
{ "th.lbia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.lbib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml, NULL, 0, 0, 0 },
|
||||
{ "th.lbuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.lbuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.lhia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.lhib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.lhuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.lhuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.lwia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.lwib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.lwuia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.lwuib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.ldia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.ldib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.sbia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.sbib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.shia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.shib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.swia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.swib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.sdia", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.sdib", rv_codec_r2_imm2_imm5, rv_fmt_rd_rs1_immh_imml_addr, NULL, 0, 0, 0 },
|
||||
{ "th.lrb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.lrbu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.lrh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.lrhu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.lrw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.lrwu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.lrd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.srb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.srh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.srw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.srd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.lurb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.lurbu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.lurh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.lurhu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.lurw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.lurwu", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.lurd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.surb", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.surh", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.surw", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.surd", rv_codec_r_imm2, rv_fmt_rd_rs1_rs2_imm, NULL, 0, 0, 0 },
|
||||
/* XTheadMemPair */
|
||||
{ "th.ldd", rv_codec_r_imm2, rv_fmt_rd2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.lwd", rv_codec_r_imm2, rv_fmt_rd2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.lwud", rv_codec_r_imm2, rv_fmt_rd2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.sdd", rv_codec_r_imm2, rv_fmt_rd2_imm, NULL, 0, 0, 0 },
|
||||
{ "th.swd", rv_codec_r_imm2, rv_fmt_rd2_imm, NULL, 0, 0, 0 },
|
||||
/* XTheadSync */
|
||||
{ "th.sfence.vmas", rv_codec_r, rv_fmt_rs1_rs2, NULL, 0, 0, 0 },
|
||||
{ "th.sync", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
|
||||
{ "th.sync.i", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
|
||||
{ "th.sync.is", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
|
||||
{ "th.sync.s", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
|
||||
};
|
||||
|
||||
void decode_xtheadba(rv_decode *dec, rv_isa isa)
|
||||
{
|
||||
rv_inst inst = dec->inst;
|
||||
rv_opcode op = rv_op_illegal;
|
||||
|
||||
switch (((inst >> 0) & 0b11)) {
|
||||
case 3:
|
||||
switch (((inst >> 2) & 0b11111)) {
|
||||
case 2:
|
||||
/* custom-0 */
|
||||
switch ((inst >> 12) & 0b111) {
|
||||
case 1:
|
||||
switch ((inst >> 25) & 0b1111111) {
|
||||
case 0b0000000:
|
||||
case 0b0000001:
|
||||
case 0b0000010:
|
||||
case 0b0000011: op = rv_op_th_addsl; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* custom-0 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dec->op = op;
|
||||
}
|
||||
|
||||
void decode_xtheadbb(rv_decode *dec, rv_isa isa)
|
||||
{
|
||||
rv_inst inst = dec->inst;
|
||||
rv_opcode op = rv_op_illegal;
|
||||
|
||||
switch (((inst >> 0) & 0b11)) {
|
||||
case 3:
|
||||
switch (((inst >> 2) & 0b11111)) {
|
||||
case 2:
|
||||
/* custom-0 */
|
||||
switch ((inst >> 12) & 0b111) {
|
||||
case 1:
|
||||
switch ((inst >> 25) & 0b1111111) {
|
||||
case 0b0001010: op = rv_op_th_srriw; break;
|
||||
case 0b1000000:
|
||||
if (((inst >> 20) & 0b11111) == 0) {
|
||||
op = rv_op_th_tstnbz;
|
||||
}
|
||||
break;
|
||||
case 0b1000001:
|
||||
if (((inst >> 20) & 0b11111) == 0) {
|
||||
op = rv_op_th_rev;
|
||||
}
|
||||
break;
|
||||
case 0b1000010:
|
||||
if (((inst >> 20) & 0b11111) == 0) {
|
||||
op = rv_op_th_ff0;
|
||||
}
|
||||
break;
|
||||
case 0b1000011:
|
||||
if (((inst >> 20) & 0b11111) == 0) {
|
||||
op = rv_op_th_ff1;
|
||||
}
|
||||
break;
|
||||
case 0b1000100:
|
||||
case 0b1001000:
|
||||
if (((inst >> 20) & 0b11111) == 0) {
|
||||
op = rv_op_th_revw;
|
||||
}
|
||||
break;
|
||||
case 0b0000100:
|
||||
case 0b0000101: op = rv_op_th_srri; break;
|
||||
}
|
||||
break;
|
||||
case 2: op = rv_op_th_ext; break;
|
||||
case 3: op = rv_op_th_extu; break;
|
||||
}
|
||||
break;
|
||||
/* custom-0 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dec->op = op;
|
||||
}
|
||||
|
||||
void decode_xtheadbs(rv_decode *dec, rv_isa isa)
|
||||
{
|
||||
rv_inst inst = dec->inst;
|
||||
rv_opcode op = rv_op_illegal;
|
||||
|
||||
switch (((inst >> 0) & 0b11)) {
|
||||
case 3:
|
||||
switch (((inst >> 2) & 0b11111)) {
|
||||
case 2:
|
||||
/* custom-0 */
|
||||
switch ((inst >> 12) & 0b111) {
|
||||
case 1:
|
||||
switch ((inst >> 26) & 0b111111) {
|
||||
case 0b100010: op = rv_op_th_tst; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* custom-0 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dec->op = op;
|
||||
}
|
||||
|
||||
void decode_xtheadcmo(rv_decode *dec, rv_isa isa)
|
||||
{
|
||||
rv_inst inst = dec->inst;
|
||||
rv_opcode op = rv_op_illegal;
|
||||
|
||||
switch (((inst >> 0) & 0b11)) {
|
||||
case 3:
|
||||
switch (((inst >> 2) & 0b11111)) {
|
||||
case 2:
|
||||
/* custom-0 */
|
||||
switch ((inst >> 12) & 0b111) {
|
||||
case 0:
|
||||
switch ((inst >> 20 & 0b111111111111)) {
|
||||
case 0b000000000001:
|
||||
if (((inst >> 20) & 0b11111) == 0) {
|
||||
op = rv_op_th_dcache_call;
|
||||
}
|
||||
break;
|
||||
case 0b000000000011:
|
||||
if (((inst >> 20) & 0b11111) == 0) {
|
||||
op = rv_op_th_dcache_ciall;
|
||||
}
|
||||
break;
|
||||
case 0b000000000010:
|
||||
if (((inst >> 20) & 0b11111) == 0) {
|
||||
op = rv_op_th_dcache_iall;
|
||||
}
|
||||
break;
|
||||
case 0b000000101001: op = rv_op_th_dcache_cpa; break;
|
||||
case 0b000000101011: op = rv_op_th_dcache_cipa; break;
|
||||
case 0b000000101010: op = rv_op_th_dcache_ipa; break;
|
||||
case 0b000000100101: op = rv_op_th_dcache_cva; break;
|
||||
case 0b000000100111: op = rv_op_th_dcache_civa; break;
|
||||
case 0b000000100110: op = rv_op_th_dcache_iva; break;
|
||||
case 0b000000100001: op = rv_op_th_dcache_csw; break;
|
||||
case 0b000000100011: op = rv_op_th_dcache_cisw; break;
|
||||
case 0b000000100010: op = rv_op_th_dcache_isw; break;
|
||||
case 0b000000101000: op = rv_op_th_dcache_cpal1; break;
|
||||
case 0b000000100100: op = rv_op_th_dcache_cval1; break;
|
||||
case 0b000000010000:
|
||||
if (((inst >> 20) & 0b11111) == 0) {
|
||||
op = rv_op_th_icache_iall;
|
||||
}
|
||||
break;
|
||||
case 0b000000010001:
|
||||
if (((inst >> 20) & 0b11111) == 0) {
|
||||
op = rv_op_th_icache_ialls;
|
||||
}
|
||||
break;
|
||||
case 0b000000111000: op = rv_op_th_icache_ipa; break;
|
||||
case 0b000000110000: op = rv_op_th_icache_iva; break;
|
||||
case 0b000000010101:
|
||||
if (((inst >> 20) & 0b11111) == 0) {
|
||||
op = rv_op_th_l2cache_call;
|
||||
}
|
||||
break;
|
||||
case 0b000000010111:
|
||||
if (((inst >> 20) & 0b11111) == 0) {
|
||||
op = rv_op_th_l2cache_ciall;
|
||||
}
|
||||
break;
|
||||
case 0b000000010110:
|
||||
if (((inst >> 20) & 0b11111) == 0) {
|
||||
op = rv_op_th_l2cache_iall;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* custom-0 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dec->op = op;
|
||||
}
|
||||
|
||||
void decode_xtheadcondmov(rv_decode *dec, rv_isa isa)
|
||||
{
|
||||
rv_inst inst = dec->inst;
|
||||
rv_opcode op = rv_op_illegal;
|
||||
|
||||
switch (((inst >> 0) & 0b11)) {
|
||||
case 3:
|
||||
switch (((inst >> 2) & 0b11111)) {
|
||||
case 2:
|
||||
/* custom-0 */
|
||||
switch ((inst >> 12) & 0b111) {
|
||||
case 1:
|
||||
switch ((inst >> 25) & 0b1111111) {
|
||||
case 0b0100000: op = rv_op_th_mveqz; break;
|
||||
case 0b0100001: op = rv_op_th_mvnez; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* custom-0 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dec->op = op;
|
||||
}
|
||||
|
||||
void decode_xtheadfmemidx(rv_decode *dec, rv_isa isa)
|
||||
{
|
||||
rv_inst inst = dec->inst;
|
||||
rv_opcode op = rv_op_illegal;
|
||||
|
||||
switch (((inst >> 0) & 0b11)) {
|
||||
case 3:
|
||||
switch (((inst >> 2) & 0b11111)) {
|
||||
case 2:
|
||||
/* custom-0 */
|
||||
switch ((inst >> 12) & 0b111) {
|
||||
case 6:
|
||||
switch ((inst >> 27) & 0b11111) {
|
||||
case 8: op = rv_op_th_flrw; break;
|
||||
case 10: op = rv_op_th_flurw; break;
|
||||
case 12: op = rv_op_th_flrd; break;
|
||||
case 14: op = rv_op_th_flurd; break;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
switch ((inst >> 27) & 0b11111) {
|
||||
case 8: op = rv_op_th_fsrw; break;
|
||||
case 10: op = rv_op_th_fsurw; break;
|
||||
case 12: op = rv_op_th_fsrd; break;
|
||||
case 14: op = rv_op_th_fsurd; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* custom-0 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dec->op = op;
|
||||
}
|
||||
|
||||
void decode_xtheadfmv(rv_decode *dec, rv_isa isa)
|
||||
{
|
||||
rv_inst inst = dec->inst;
|
||||
rv_opcode op = rv_op_illegal;
|
||||
|
||||
switch (((inst >> 0) & 0b11)) {
|
||||
case 3:
|
||||
switch (((inst >> 2) & 0b11111)) {
|
||||
case 2:
|
||||
/* custom-0 */
|
||||
switch ((inst >> 12) & 0b111) {
|
||||
case 1:
|
||||
switch ((inst >> 25) & 0b1111111) {
|
||||
case 0b1010000:
|
||||
if (((inst >> 20) & 0b11111) == 0) {
|
||||
op = rv_op_th_fmv_hw_x;
|
||||
}
|
||||
break;
|
||||
case 0b1100000:
|
||||
if (((inst >> 20) & 0b11111) == 0) {
|
||||
op = rv_op_th_fmv_x_hw;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* custom-0 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dec->op = op;
|
||||
}
|
||||
|
||||
void decode_xtheadmac(rv_decode *dec, rv_isa isa)
|
||||
{
|
||||
rv_inst inst = dec->inst;
|
||||
rv_opcode op = rv_op_illegal;
|
||||
|
||||
switch (((inst >> 0) & 0b11)) {
|
||||
case 3:
|
||||
switch (((inst >> 2) & 0b11111)) {
|
||||
case 2:
|
||||
/* custom-0 */
|
||||
switch ((inst >> 12) & 0b111) {
|
||||
case 1:
|
||||
switch ((inst >> 25) & 0b1111111) {
|
||||
case 0b0010000: op = rv_op_th_mula; break;
|
||||
case 0b0010001: op = rv_op_th_muls; break;
|
||||
case 0b0010010: op = rv_op_th_mulaw; break;
|
||||
case 0b0010011: op = rv_op_th_mulsw; break;
|
||||
case 0b0010100: op = rv_op_th_mulah; break;
|
||||
case 0b0010101: op = rv_op_th_mulsh; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* custom-0 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dec->op = op;
|
||||
}
|
||||
|
||||
void decode_xtheadmemidx(rv_decode *dec, rv_isa isa)
|
||||
{
|
||||
rv_inst inst = dec->inst;
|
||||
rv_opcode op = rv_op_illegal;
|
||||
|
||||
switch (((inst >> 0) & 0b11)) {
|
||||
case 3:
|
||||
switch (((inst >> 2) & 0b11111)) {
|
||||
case 2:
|
||||
/* custom-0 */
|
||||
switch ((inst >> 12) & 0b111) {
|
||||
case 4:
|
||||
switch ((inst >> 27) & 0b11111) {
|
||||
case 0: op = rv_op_th_lrb; break;
|
||||
case 1: op = rv_op_th_lbib; break;
|
||||
case 2: op = rv_op_th_lurb; break;
|
||||
case 3: op = rv_op_th_lbia; break;
|
||||
case 4: op = rv_op_th_lrh; break;
|
||||
case 5: op = rv_op_th_lhib; break;
|
||||
case 6: op = rv_op_th_lurh; break;
|
||||
case 7: op = rv_op_th_lhia; break;
|
||||
case 8: op = rv_op_th_lrw; break;
|
||||
case 9: op = rv_op_th_lwib; break;
|
||||
case 10: op = rv_op_th_lurw; break;
|
||||
case 11: op = rv_op_th_lwia; break;
|
||||
case 12: op = rv_op_th_lrd; break;
|
||||
case 13: op = rv_op_th_ldib; break;
|
||||
case 14: op = rv_op_th_lurd; break;
|
||||
case 15: op = rv_op_th_ldia; break;
|
||||
case 16: op = rv_op_th_lrbu; break;
|
||||
case 17: op = rv_op_th_lbuib; break;
|
||||
case 18: op = rv_op_th_lurbu; break;
|
||||
case 19: op = rv_op_th_lbuia; break;
|
||||
case 20: op = rv_op_th_lrhu; break;
|
||||
case 21: op = rv_op_th_lhuib; break;
|
||||
case 22: op = rv_op_th_lurhu; break;
|
||||
case 23: op = rv_op_th_lhuia; break;
|
||||
case 24: op = rv_op_th_lrwu; break;
|
||||
case 25: op = rv_op_th_lwuib; break;
|
||||
case 26: op = rv_op_th_lurwu; break;
|
||||
case 27: op = rv_op_th_lwuia; break;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
switch ((inst >> 27) & 0b11111) {
|
||||
case 0: op = rv_op_th_srb; break;
|
||||
case 1: op = rv_op_th_sbib; break;
|
||||
case 2: op = rv_op_th_surb; break;
|
||||
case 3: op = rv_op_th_sbia; break;
|
||||
case 4: op = rv_op_th_srh; break;
|
||||
case 5: op = rv_op_th_shib; break;
|
||||
case 6: op = rv_op_th_surh; break;
|
||||
case 7: op = rv_op_th_shia; break;
|
||||
case 8: op = rv_op_th_srw; break;
|
||||
case 9: op = rv_op_th_swib; break;
|
||||
case 10: op = rv_op_th_surw; break;
|
||||
case 11: op = rv_op_th_swia; break;
|
||||
case 12: op = rv_op_th_srd; break;
|
||||
case 13: op = rv_op_th_sdib; break;
|
||||
case 14: op = rv_op_th_surd; break;
|
||||
case 15: op = rv_op_th_sdia; break;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* custom-0 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dec->op = op;
|
||||
}
|
||||
|
||||
void decode_xtheadmempair(rv_decode *dec, rv_isa isa)
|
||||
{
|
||||
rv_inst inst = dec->inst;
|
||||
rv_opcode op = rv_op_illegal;
|
||||
|
||||
switch (((inst >> 0) & 0b11)) {
|
||||
case 3:
|
||||
switch (((inst >> 2) & 0b11111)) {
|
||||
case 2:
|
||||
/* custom-0 */
|
||||
switch ((inst >> 12) & 0b111) {
|
||||
case 4:
|
||||
switch ((inst >> 27) & 0b11111) {
|
||||
case 28: op = rv_op_th_lwd; break;
|
||||
case 30: op = rv_op_th_lwud; break;
|
||||
case 31: op = rv_op_th_ldd; break;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
switch ((inst >> 27) & 0b11111) {
|
||||
case 28: op = rv_op_th_swd; break;
|
||||
case 31: op = rv_op_th_sdd; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* custom-0 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dec->op = op;
|
||||
}
|
||||
|
||||
void decode_xtheadsync(rv_decode *dec, rv_isa isa)
|
||||
{
|
||||
rv_inst inst = dec->inst;
|
||||
rv_opcode op = rv_op_illegal;
|
||||
|
||||
switch (((inst >> 0) & 0b11)) {
|
||||
case 3:
|
||||
switch (((inst >> 2) & 0b11111)) {
|
||||
case 2:
|
||||
/* custom-0 */
|
||||
switch ((inst >> 12) & 0b111) {
|
||||
case 0:
|
||||
switch ((inst >> 25) & 0b1111111) {
|
||||
case 0b0000010: op = rv_op_th_sfence_vmas; break;
|
||||
case 0b0000000:
|
||||
switch ((inst >> 20) & 0b11111) {
|
||||
case 0b11000: op = rv_op_th_sync; break;
|
||||
case 0b11010: op = rv_op_th_sync_i; break;
|
||||
case 0b11011: op = rv_op_th_sync_is; break;
|
||||
case 0b11001: op = rv_op_th_sync_s; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* custom-0 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dec->op = op;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* QEMU disassembler -- RISC-V specific header (xthead*).
|
||||
*
|
||||
* Copyright (c) 2023 VRULL GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef DISAS_RISCV_XTHEAD_H
|
||||
#define DISAS_RISCV_XTHEAD_H
|
||||
|
||||
#include "disas/riscv.h"
|
||||
|
||||
extern const rv_opcode_data xthead_opcode_data[];
|
||||
|
||||
void decode_xtheadba(rv_decode *, rv_isa);
|
||||
void decode_xtheadbb(rv_decode *, rv_isa);
|
||||
void decode_xtheadbs(rv_decode *, rv_isa);
|
||||
void decode_xtheadcmo(rv_decode *, rv_isa);
|
||||
void decode_xtheadcondmov(rv_decode *, rv_isa);
|
||||
void decode_xtheadfmemidx(rv_decode *, rv_isa);
|
||||
void decode_xtheadfmv(rv_decode *, rv_isa);
|
||||
void decode_xtheadmac(rv_decode *, rv_isa);
|
||||
void decode_xtheadmemidx(rv_decode *, rv_isa);
|
||||
void decode_xtheadmempair(rv_decode *, rv_isa);
|
||||
void decode_xtheadsync(rv_decode *, rv_isa);
|
||||
|
||||
#endif /* DISAS_RISCV_XTHEAD_H */
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* QEMU RISC-V Disassembler for xventana.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "disas/riscv.h"
|
||||
#include "disas/riscv-xventana.h"
|
||||
|
||||
typedef enum {
|
||||
/* 0 is reserved for rv_op_illegal. */
|
||||
ventana_op_vt_maskc = 1,
|
||||
ventana_op_vt_maskcn = 2,
|
||||
} rv_ventana_op;
|
||||
|
||||
const rv_opcode_data ventana_opcode_data[] = {
|
||||
{ "vt.illegal", rv_codec_illegal, rv_fmt_none, NULL, 0, 0, 0 },
|
||||
{ "vt.maskc", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
{ "vt.maskcn", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
};
|
||||
|
||||
void decode_xventanacondops(rv_decode *dec, rv_isa isa)
|
||||
{
|
||||
rv_inst inst = dec->inst;
|
||||
rv_opcode op = rv_op_illegal;
|
||||
|
||||
switch (((inst >> 0) & 0b11)) {
|
||||
case 3:
|
||||
switch (((inst >> 2) & 0b11111)) {
|
||||
case 30:
|
||||
switch (((inst >> 22) & 0b1111111000) | ((inst >> 12) & 0b0000000111)) {
|
||||
case 6: op = ventana_op_vt_maskc; break;
|
||||
case 7: op = ventana_op_vt_maskcn; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
dec->op = op;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* QEMU disassembler -- RISC-V specific header (xventana*).
|
||||
*
|
||||
* Copyright (c) 2023 VRULL GmbH
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef DISAS_RISCV_XVENTANA_H
|
||||
#define DISAS_RISCV_XVENTANA_H
|
||||
|
||||
#include "disas/riscv.h"
|
||||
|
||||
extern const rv_opcode_data ventana_opcode_data[];
|
||||
|
||||
void decode_xventanacondops(rv_decode*, rv_isa);
|
||||
|
||||
#endif /* DISAS_RISCV_XVENTANA_H */
|
||||
582
disas/riscv.c
582
disas/riscv.c
@@ -18,17 +18,162 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "disas/dis-asm.h"
|
||||
#include "target/riscv/cpu_cfg.h"
|
||||
#include "disas/riscv.h"
|
||||
|
||||
/* Vendor extensions */
|
||||
#include "disas/riscv-xthead.h"
|
||||
#include "disas/riscv-xventana.h"
|
||||
/* types */
|
||||
|
||||
typedef uint64_t rv_inst;
|
||||
typedef uint16_t rv_opcode;
|
||||
|
||||
/* enums */
|
||||
|
||||
typedef enum {
|
||||
/* 0 is reserved for rv_op_illegal. */
|
||||
rv32,
|
||||
rv64,
|
||||
rv128
|
||||
} rv_isa;
|
||||
|
||||
typedef enum {
|
||||
rv_rm_rne = 0,
|
||||
rv_rm_rtz = 1,
|
||||
rv_rm_rdn = 2,
|
||||
rv_rm_rup = 3,
|
||||
rv_rm_rmm = 4,
|
||||
rv_rm_dyn = 7,
|
||||
} rv_rm;
|
||||
|
||||
typedef enum {
|
||||
rv_fence_i = 8,
|
||||
rv_fence_o = 4,
|
||||
rv_fence_r = 2,
|
||||
rv_fence_w = 1,
|
||||
} rv_fence;
|
||||
|
||||
typedef enum {
|
||||
rv_ireg_zero,
|
||||
rv_ireg_ra,
|
||||
rv_ireg_sp,
|
||||
rv_ireg_gp,
|
||||
rv_ireg_tp,
|
||||
rv_ireg_t0,
|
||||
rv_ireg_t1,
|
||||
rv_ireg_t2,
|
||||
rv_ireg_s0,
|
||||
rv_ireg_s1,
|
||||
rv_ireg_a0,
|
||||
rv_ireg_a1,
|
||||
rv_ireg_a2,
|
||||
rv_ireg_a3,
|
||||
rv_ireg_a4,
|
||||
rv_ireg_a5,
|
||||
rv_ireg_a6,
|
||||
rv_ireg_a7,
|
||||
rv_ireg_s2,
|
||||
rv_ireg_s3,
|
||||
rv_ireg_s4,
|
||||
rv_ireg_s5,
|
||||
rv_ireg_s6,
|
||||
rv_ireg_s7,
|
||||
rv_ireg_s8,
|
||||
rv_ireg_s9,
|
||||
rv_ireg_s10,
|
||||
rv_ireg_s11,
|
||||
rv_ireg_t3,
|
||||
rv_ireg_t4,
|
||||
rv_ireg_t5,
|
||||
rv_ireg_t6,
|
||||
} rv_ireg;
|
||||
|
||||
typedef enum {
|
||||
rvc_end,
|
||||
rvc_rd_eq_ra,
|
||||
rvc_rd_eq_x0,
|
||||
rvc_rs1_eq_x0,
|
||||
rvc_rs2_eq_x0,
|
||||
rvc_rs2_eq_rs1,
|
||||
rvc_rs1_eq_ra,
|
||||
rvc_imm_eq_zero,
|
||||
rvc_imm_eq_n1,
|
||||
rvc_imm_eq_p1,
|
||||
rvc_csr_eq_0x001,
|
||||
rvc_csr_eq_0x002,
|
||||
rvc_csr_eq_0x003,
|
||||
rvc_csr_eq_0xc00,
|
||||
rvc_csr_eq_0xc01,
|
||||
rvc_csr_eq_0xc02,
|
||||
rvc_csr_eq_0xc80,
|
||||
rvc_csr_eq_0xc81,
|
||||
rvc_csr_eq_0xc82,
|
||||
} rvc_constraint;
|
||||
|
||||
typedef enum {
|
||||
rv_codec_illegal,
|
||||
rv_codec_none,
|
||||
rv_codec_u,
|
||||
rv_codec_uj,
|
||||
rv_codec_i,
|
||||
rv_codec_i_sh5,
|
||||
rv_codec_i_sh6,
|
||||
rv_codec_i_sh7,
|
||||
rv_codec_i_csr,
|
||||
rv_codec_s,
|
||||
rv_codec_sb,
|
||||
rv_codec_r,
|
||||
rv_codec_r_m,
|
||||
rv_codec_r4_m,
|
||||
rv_codec_r_a,
|
||||
rv_codec_r_l,
|
||||
rv_codec_r_f,
|
||||
rv_codec_cb,
|
||||
rv_codec_cb_imm,
|
||||
rv_codec_cb_sh5,
|
||||
rv_codec_cb_sh6,
|
||||
rv_codec_ci,
|
||||
rv_codec_ci_sh5,
|
||||
rv_codec_ci_sh6,
|
||||
rv_codec_ci_16sp,
|
||||
rv_codec_ci_lwsp,
|
||||
rv_codec_ci_ldsp,
|
||||
rv_codec_ci_lqsp,
|
||||
rv_codec_ci_li,
|
||||
rv_codec_ci_lui,
|
||||
rv_codec_ci_none,
|
||||
rv_codec_ciw_4spn,
|
||||
rv_codec_cj,
|
||||
rv_codec_cj_jal,
|
||||
rv_codec_cl_lw,
|
||||
rv_codec_cl_ld,
|
||||
rv_codec_cl_lq,
|
||||
rv_codec_cr,
|
||||
rv_codec_cr_mv,
|
||||
rv_codec_cr_jalr,
|
||||
rv_codec_cr_jr,
|
||||
rv_codec_cs,
|
||||
rv_codec_cs_sw,
|
||||
rv_codec_cs_sd,
|
||||
rv_codec_cs_sq,
|
||||
rv_codec_css_swsp,
|
||||
rv_codec_css_sdsp,
|
||||
rv_codec_css_sqsp,
|
||||
rv_codec_k_bs,
|
||||
rv_codec_k_rnum,
|
||||
rv_codec_v_r,
|
||||
rv_codec_v_ldst,
|
||||
rv_codec_v_i,
|
||||
rv_codec_vsetvli,
|
||||
rv_codec_vsetivli,
|
||||
rv_codec_zcb_ext,
|
||||
rv_codec_zcb_mul,
|
||||
rv_codec_zcb_lb,
|
||||
rv_codec_zcb_lh,
|
||||
rv_codec_zcmp_cm_pushpop,
|
||||
rv_codec_zcmp_cm_mv,
|
||||
rv_codec_zcmt_jt,
|
||||
} rv_codec;
|
||||
|
||||
typedef enum {
|
||||
rv_op_illegal = 0,
|
||||
rv_op_lui = 1,
|
||||
rv_op_auipc = 2,
|
||||
rv_op_jal = 3,
|
||||
@@ -819,51 +964,53 @@ typedef enum {
|
||||
rv_op_cm_jalt = 788,
|
||||
rv_op_czero_eqz = 789,
|
||||
rv_op_czero_nez = 790,
|
||||
rv_op_fcvt_bf16_s = 791,
|
||||
rv_op_fcvt_s_bf16 = 792,
|
||||
rv_op_vfncvtbf16_f_f_w = 793,
|
||||
rv_op_vfwcvtbf16_f_f_v = 794,
|
||||
rv_op_vfwmaccbf16_vv = 795,
|
||||
rv_op_vfwmaccbf16_vf = 796,
|
||||
rv_op_flh = 797,
|
||||
rv_op_fsh = 798,
|
||||
rv_op_fmv_h_x = 799,
|
||||
rv_op_fmv_x_h = 800,
|
||||
rv_op_fli_s = 801,
|
||||
rv_op_fli_d = 802,
|
||||
rv_op_fli_q = 803,
|
||||
rv_op_fli_h = 804,
|
||||
rv_op_fminm_s = 805,
|
||||
rv_op_fmaxm_s = 806,
|
||||
rv_op_fminm_d = 807,
|
||||
rv_op_fmaxm_d = 808,
|
||||
rv_op_fminm_q = 809,
|
||||
rv_op_fmaxm_q = 810,
|
||||
rv_op_fminm_h = 811,
|
||||
rv_op_fmaxm_h = 812,
|
||||
rv_op_fround_s = 813,
|
||||
rv_op_froundnx_s = 814,
|
||||
rv_op_fround_d = 815,
|
||||
rv_op_froundnx_d = 816,
|
||||
rv_op_fround_q = 817,
|
||||
rv_op_froundnx_q = 818,
|
||||
rv_op_fround_h = 819,
|
||||
rv_op_froundnx_h = 820,
|
||||
rv_op_fcvtmod_w_d = 821,
|
||||
rv_op_fmvh_x_d = 822,
|
||||
rv_op_fmvp_d_x = 823,
|
||||
rv_op_fmvh_x_q = 824,
|
||||
rv_op_fmvp_q_x = 825,
|
||||
rv_op_fleq_s = 826,
|
||||
rv_op_fltq_s = 827,
|
||||
rv_op_fleq_d = 828,
|
||||
rv_op_fltq_d = 829,
|
||||
rv_op_fleq_q = 830,
|
||||
rv_op_fltq_q = 831,
|
||||
rv_op_fleq_h = 832,
|
||||
rv_op_fltq_h = 833,
|
||||
} rv_op;
|
||||
|
||||
/* structures */
|
||||
|
||||
typedef struct {
|
||||
RISCVCPUConfig *cfg;
|
||||
uint64_t pc;
|
||||
uint64_t inst;
|
||||
int32_t imm;
|
||||
uint16_t op;
|
||||
uint8_t codec;
|
||||
uint8_t rd;
|
||||
uint8_t rs1;
|
||||
uint8_t rs2;
|
||||
uint8_t rs3;
|
||||
uint8_t rm;
|
||||
uint8_t pred;
|
||||
uint8_t succ;
|
||||
uint8_t aq;
|
||||
uint8_t rl;
|
||||
uint8_t bs;
|
||||
uint8_t rnum;
|
||||
uint8_t vm;
|
||||
uint32_t vzimm;
|
||||
uint8_t rlist;
|
||||
} rv_decode;
|
||||
|
||||
typedef struct {
|
||||
const int op;
|
||||
const rvc_constraint *constraints;
|
||||
} rv_comp_data;
|
||||
|
||||
enum {
|
||||
rvcd_imm_nz = 0x1
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char * const name;
|
||||
const rv_codec codec;
|
||||
const char * const format;
|
||||
const rv_comp_data *pseudo;
|
||||
const short decomp_rv32;
|
||||
const short decomp_rv64;
|
||||
const short decomp_rv128;
|
||||
const short decomp_data;
|
||||
} rv_opcode_data;
|
||||
|
||||
/* register names */
|
||||
|
||||
static const char rv_ireg_name_sym[32][5] = {
|
||||
@@ -887,22 +1034,78 @@ static const char rv_vreg_name_sym[32][4] = {
|
||||
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
|
||||
};
|
||||
|
||||
/* The FLI.[HSDQ] numeric constants (0.0 for symbolic constants).
|
||||
* The constants use the hex floating-point literal representation
|
||||
* that is printed when using the printf %a format specifier,
|
||||
* which matches the output that is generated by the disassembler.
|
||||
*/
|
||||
static const char rv_fli_name_const[32][9] =
|
||||
{
|
||||
"0x1p+0", "min", "0x1p-16", "0x1p-15",
|
||||
"0x1p-8", "0x1p-7", "0x1p-4", "0x1p-3",
|
||||
"0x1p-2", "0x1.4p-2", "0x1.8p-2", "0x1.cp-2",
|
||||
"0x1p-1", "0x1.4p-1", "0x1.8p-1", "0x1.cp-1",
|
||||
"0x1p+0", "0x1.4p+0", "0x1.8p+0", "0x1.cp+0",
|
||||
"0x1p+1", "0x1.4p+1", "0x1.8p+1", "0x1p+2",
|
||||
"0x1p+3", "0x1p+4", "0x1p+7", "0x1p+8",
|
||||
"0x1p+15", "0x1p+16", "inf", "nan"
|
||||
};
|
||||
/* instruction formats */
|
||||
|
||||
#define rv_fmt_none "O\t"
|
||||
#define rv_fmt_rs1 "O\t1"
|
||||
#define rv_fmt_offset "O\to"
|
||||
#define rv_fmt_pred_succ "O\tp,s"
|
||||
#define rv_fmt_rs1_rs2 "O\t1,2"
|
||||
#define rv_fmt_rd_imm "O\t0,i"
|
||||
#define rv_fmt_rd_offset "O\t0,o"
|
||||
#define rv_fmt_rd_rs1_rs2 "O\t0,1,2"
|
||||
#define rv_fmt_frd_rs1 "O\t3,1"
|
||||
#define rv_fmt_frd_frs1 "O\t3,4"
|
||||
#define rv_fmt_rd_frs1 "O\t0,4"
|
||||
#define rv_fmt_rd_frs1_frs2 "O\t0,4,5"
|
||||
#define rv_fmt_frd_frs1_frs2 "O\t3,4,5"
|
||||
#define rv_fmt_rm_frd_frs1 "O\tr,3,4"
|
||||
#define rv_fmt_rm_frd_rs1 "O\tr,3,1"
|
||||
#define rv_fmt_rm_rd_frs1 "O\tr,0,4"
|
||||
#define rv_fmt_rm_frd_frs1_frs2 "O\tr,3,4,5"
|
||||
#define rv_fmt_rm_frd_frs1_frs2_frs3 "O\tr,3,4,5,6"
|
||||
#define rv_fmt_rd_rs1_imm "O\t0,1,i"
|
||||
#define rv_fmt_rd_rs1_offset "O\t0,1,i"
|
||||
#define rv_fmt_rd_offset_rs1 "O\t0,i(1)"
|
||||
#define rv_fmt_frd_offset_rs1 "O\t3,i(1)"
|
||||
#define rv_fmt_rd_csr_rs1 "O\t0,c,1"
|
||||
#define rv_fmt_rd_csr_zimm "O\t0,c,7"
|
||||
#define rv_fmt_rs2_offset_rs1 "O\t2,i(1)"
|
||||
#define rv_fmt_frs2_offset_rs1 "O\t5,i(1)"
|
||||
#define rv_fmt_rs1_rs2_offset "O\t1,2,o"
|
||||
#define rv_fmt_rs2_rs1_offset "O\t2,1,o"
|
||||
#define rv_fmt_aqrl_rd_rs2_rs1 "OAR\t0,2,(1)"
|
||||
#define rv_fmt_aqrl_rd_rs1 "OAR\t0,(1)"
|
||||
#define rv_fmt_rd "O\t0"
|
||||
#define rv_fmt_rd_zimm "O\t0,7"
|
||||
#define rv_fmt_rd_rs1 "O\t0,1"
|
||||
#define rv_fmt_rd_rs2 "O\t0,2"
|
||||
#define rv_fmt_rs1_offset "O\t1,o"
|
||||
#define rv_fmt_rs2_offset "O\t2,o"
|
||||
#define rv_fmt_rs1_rs2_bs "O\t1,2,b"
|
||||
#define rv_fmt_rd_rs1_rnum "O\t0,1,n"
|
||||
#define rv_fmt_ldst_vd_rs1_vm "O\tD,(1)m"
|
||||
#define rv_fmt_ldst_vd_rs1_rs2_vm "O\tD,(1),2m"
|
||||
#define rv_fmt_ldst_vd_rs1_vs2_vm "O\tD,(1),Fm"
|
||||
#define rv_fmt_vd_vs2_vs1 "O\tD,F,E"
|
||||
#define rv_fmt_vd_vs2_vs1_vl "O\tD,F,El"
|
||||
#define rv_fmt_vd_vs2_vs1_vm "O\tD,F,Em"
|
||||
#define rv_fmt_vd_vs2_rs1_vl "O\tD,F,1l"
|
||||
#define rv_fmt_vd_vs2_fs1_vl "O\tD,F,4l"
|
||||
#define rv_fmt_vd_vs2_rs1_vm "O\tD,F,1m"
|
||||
#define rv_fmt_vd_vs2_fs1_vm "O\tD,F,4m"
|
||||
#define rv_fmt_vd_vs2_imm_vl "O\tD,F,il"
|
||||
#define rv_fmt_vd_vs2_imm_vm "O\tD,F,im"
|
||||
#define rv_fmt_vd_vs2_uimm_vm "O\tD,F,um"
|
||||
#define rv_fmt_vd_vs1_vs2_vm "O\tD,E,Fm"
|
||||
#define rv_fmt_vd_rs1_vs2_vm "O\tD,1,Fm"
|
||||
#define rv_fmt_vd_fs1_vs2_vm "O\tD,4,Fm"
|
||||
#define rv_fmt_vd_vs1 "O\tD,E"
|
||||
#define rv_fmt_vd_rs1 "O\tD,1"
|
||||
#define rv_fmt_vd_fs1 "O\tD,4"
|
||||
#define rv_fmt_vd_imm "O\tD,i"
|
||||
#define rv_fmt_vd_vs2 "O\tD,F"
|
||||
#define rv_fmt_vd_vs2_vm "O\tD,Fm"
|
||||
#define rv_fmt_rd_vs2_vm "O\t0,Fm"
|
||||
#define rv_fmt_rd_vs2 "O\t0,F"
|
||||
#define rv_fmt_fd_vs2 "O\t3,F"
|
||||
#define rv_fmt_vd_vm "O\tDm"
|
||||
#define rv_fmt_vsetvli "O\t0,1,v"
|
||||
#define rv_fmt_vsetivli "O\t0,u,v"
|
||||
#define rv_fmt_rs1_rs2_zce_ldst "O\t2,i(1)"
|
||||
#define rv_fmt_push_rlist "O\tx,-i"
|
||||
#define rv_fmt_pop_rlist "O\tx,i"
|
||||
#define rv_fmt_zcmt_index "O\ti"
|
||||
|
||||
/* pseudo-instruction constraints */
|
||||
|
||||
@@ -1133,10 +1336,10 @@ static const rv_comp_data rvcp_fsgnjx_q[] = {
|
||||
|
||||
/* instruction metadata */
|
||||
|
||||
const rv_opcode_data rvi_opcode_data[] = {
|
||||
const rv_opcode_data opcode_data[] = {
|
||||
{ "illegal", rv_codec_illegal, rv_fmt_none, NULL, 0, 0, 0 },
|
||||
{ "lui", rv_codec_u, rv_fmt_rd_uimm, NULL, 0, 0, 0 },
|
||||
{ "auipc", rv_codec_u, rv_fmt_rd_uoffset, NULL, 0, 0, 0 },
|
||||
{ "lui", rv_codec_u, rv_fmt_rd_imm, NULL, 0, 0, 0 },
|
||||
{ "auipc", rv_codec_u, rv_fmt_rd_offset, NULL, 0, 0, 0 },
|
||||
{ "jal", rv_codec_uj, rv_fmt_rd_offset, rvcp_jal, 0, 0, 0 },
|
||||
{ "jalr", rv_codec_i, rv_fmt_rd_rs1_offset, rvcp_jalr, 0, 0, 0 },
|
||||
{ "beq", rv_codec_sb, rv_fmt_rs1_rs2_offset, rvcp_beq, 0, 0, 0 },
|
||||
@@ -1382,7 +1585,7 @@ const rv_opcode_data rvi_opcode_data[] = {
|
||||
rv_op_addi },
|
||||
{ "c.addi16sp", rv_codec_ci_16sp, rv_fmt_rd_rs1_imm, NULL, rv_op_addi,
|
||||
rv_op_addi, rv_op_addi, rvcd_imm_nz },
|
||||
{ "c.lui", rv_codec_ci_lui, rv_fmt_rd_uimm, NULL, rv_op_lui, rv_op_lui,
|
||||
{ "c.lui", rv_codec_ci_lui, rv_fmt_rd_imm, NULL, rv_op_lui, rv_op_lui,
|
||||
rv_op_lui, rvcd_imm_nz },
|
||||
{ "c.srli", rv_codec_cb_sh6, rv_fmt_rd_rs1_imm, NULL, rv_op_srli,
|
||||
rv_op_srli, rv_op_srli, rvcd_imm_nz },
|
||||
@@ -1965,49 +2168,6 @@ const rv_opcode_data rvi_opcode_data[] = {
|
||||
{ "cm.jalt", rv_codec_zcmt_jt, rv_fmt_zcmt_index, NULL, 0 },
|
||||
{ "czero.eqz", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
{ "czero.nez", rv_codec_r, rv_fmt_rd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
{ "fcvt.bf16.s", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 },
|
||||
{ "fcvt.s.bf16", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 },
|
||||
{ "vfncvtbf16.f.f.w", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 },
|
||||
{ "vfwcvtbf16.f.f.v", rv_codec_v_r, rv_fmt_vd_vs2_vm, NULL, 0, 0, 0 },
|
||||
{ "vfwmaccbf16.vv", rv_codec_v_r, rv_fmt_vd_vs1_vs2_vm, NULL, 0, 0, 0 },
|
||||
{ "vfwmaccbf16.vf", rv_codec_v_r, rv_fmt_vd_fs1_vs2_vm, NULL, 0, 0, 0 },
|
||||
{ "flh", rv_codec_i, rv_fmt_frd_offset_rs1, NULL, 0, 0, 0 },
|
||||
{ "fsh", rv_codec_s, rv_fmt_frs2_offset_rs1, NULL, 0, 0, 0 },
|
||||
{ "fmv.h.x", rv_codec_r, rv_fmt_frd_rs1, NULL, 0, 0, 0 },
|
||||
{ "fmv.x.h", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 },
|
||||
{ "fli.s", rv_codec_fli, rv_fmt_fli, NULL, 0, 0, 0 },
|
||||
{ "fli.d", rv_codec_fli, rv_fmt_fli, NULL, 0, 0, 0 },
|
||||
{ "fli.q", rv_codec_fli, rv_fmt_fli, NULL, 0, 0, 0 },
|
||||
{ "fli.h", rv_codec_fli, rv_fmt_fli, NULL, 0, 0, 0 },
|
||||
{ "fminm.s", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
{ "fmaxm.s", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
{ "fminm.d", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
{ "fmaxm.d", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
{ "fminm.q", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
{ "fmaxm.q", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
{ "fminm.h", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
{ "fmaxm.h", rv_codec_r, rv_fmt_frd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
{ "fround.s", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 },
|
||||
{ "froundnx.s", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 },
|
||||
{ "fround.d", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 },
|
||||
{ "froundnx.d", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 },
|
||||
{ "fround.q", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 },
|
||||
{ "froundnx.q", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 },
|
||||
{ "fround.h", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 },
|
||||
{ "froundnx.h", rv_codec_r_m, rv_fmt_rm_frd_frs1, NULL, 0, 0, 0 },
|
||||
{ "fcvtmod.w.d", rv_codec_r_m, rv_fmt_rm_rd_frs1, NULL, 0, 0, 0 },
|
||||
{ "fmvh.x.d", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 },
|
||||
{ "fmvp.d.x", rv_codec_r, rv_fmt_frd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
{ "fmvh.x.q", rv_codec_r, rv_fmt_rd_frs1, NULL, 0, 0, 0 },
|
||||
{ "fmvp.q.x", rv_codec_r, rv_fmt_frd_rs1_rs2, NULL, 0, 0, 0 },
|
||||
{ "fleq.s", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
{ "fltq.s", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
{ "fleq.d", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
{ "fltq.d", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
{ "fleq.q", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
{ "fltq.q", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
{ "fleq.h", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
{ "fltq.h", rv_codec_r, rv_fmt_rd_frs1_frs2, NULL, 0, 0, 0 },
|
||||
};
|
||||
|
||||
/* CSR names */
|
||||
@@ -2116,8 +2276,8 @@ static const char *csr_name(int csrno)
|
||||
case 0x03ba: return "pmpaddr10";
|
||||
case 0x03bb: return "pmpaddr11";
|
||||
case 0x03bc: return "pmpaddr12";
|
||||
case 0x03bd: return "pmpaddr13";
|
||||
case 0x03be: return "pmpaddr14";
|
||||
case 0x03bd: return "pmpaddr14";
|
||||
case 0x03be: return "pmpaddr13";
|
||||
case 0x03bf: return "pmpaddr15";
|
||||
case 0x0780: return "mtohost";
|
||||
case 0x0781: return "mfromhost";
|
||||
@@ -2483,7 +2643,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
case 3: op = rv_op_vloxei8_v; break;
|
||||
}
|
||||
break;
|
||||
case 1: op = rv_op_flh; break;
|
||||
case 2: op = rv_op_flw; break;
|
||||
case 3: op = rv_op_fld; break;
|
||||
case 4: op = rv_op_flq; break;
|
||||
@@ -2687,7 +2846,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
case 3: op = rv_op_vsoxei8_v; break;
|
||||
}
|
||||
break;
|
||||
case 1: op = rv_op_fsh; break;
|
||||
case 2: op = rv_op_fsw; break;
|
||||
case 3: op = rv_op_fsd; break;
|
||||
case 4: op = rv_op_fsq; break;
|
||||
@@ -2947,62 +3105,36 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
switch ((inst >> 12) & 0b111) {
|
||||
case 0: op = rv_op_fmin_s; break;
|
||||
case 1: op = rv_op_fmax_s; break;
|
||||
case 2: op = rv_op_fminm_s; break;
|
||||
case 3: op = rv_op_fmaxm_s; break;
|
||||
}
|
||||
break;
|
||||
case 21:
|
||||
switch ((inst >> 12) & 0b111) {
|
||||
case 0: op = rv_op_fmin_d; break;
|
||||
case 1: op = rv_op_fmax_d; break;
|
||||
case 2: op = rv_op_fminm_d; break;
|
||||
case 3: op = rv_op_fmaxm_d; break;
|
||||
}
|
||||
break;
|
||||
case 22:
|
||||
switch (((inst >> 12) & 0b111)) {
|
||||
case 2: op = rv_op_fminm_h; break;
|
||||
case 3: op = rv_op_fmaxm_h; break;
|
||||
}
|
||||
break;
|
||||
case 23:
|
||||
switch ((inst >> 12) & 0b111) {
|
||||
case 0: op = rv_op_fmin_q; break;
|
||||
case 1: op = rv_op_fmax_q; break;
|
||||
case 2: op = rv_op_fminm_q; break;
|
||||
case 3: op = rv_op_fmaxm_q; break;
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
switch ((inst >> 20) & 0b11111) {
|
||||
case 1: op = rv_op_fcvt_s_d; break;
|
||||
case 3: op = rv_op_fcvt_s_q; break;
|
||||
case 4: op = rv_op_fround_s; break;
|
||||
case 5: op = rv_op_froundnx_s; break;
|
||||
case 6: op = rv_op_fcvt_s_bf16; break;
|
||||
}
|
||||
break;
|
||||
case 33:
|
||||
switch ((inst >> 20) & 0b11111) {
|
||||
case 0: op = rv_op_fcvt_d_s; break;
|
||||
case 3: op = rv_op_fcvt_d_q; break;
|
||||
case 4: op = rv_op_fround_d; break;
|
||||
case 5: op = rv_op_froundnx_d; break;
|
||||
}
|
||||
break;
|
||||
case 34:
|
||||
switch (((inst >> 20) & 0b11111)) {
|
||||
case 4: op = rv_op_fround_h; break;
|
||||
case 5: op = rv_op_froundnx_h; break;
|
||||
case 8: op = rv_op_fcvt_bf16_s; break;
|
||||
}
|
||||
break;
|
||||
case 35:
|
||||
switch ((inst >> 20) & 0b11111) {
|
||||
case 0: op = rv_op_fcvt_q_s; break;
|
||||
case 1: op = rv_op_fcvt_q_d; break;
|
||||
case 4: op = rv_op_fround_q; break;
|
||||
case 5: op = rv_op_froundnx_q; break;
|
||||
}
|
||||
break;
|
||||
case 44:
|
||||
@@ -3025,8 +3157,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
case 0: op = rv_op_fle_s; break;
|
||||
case 1: op = rv_op_flt_s; break;
|
||||
case 2: op = rv_op_feq_s; break;
|
||||
case 4: op = rv_op_fleq_s; break;
|
||||
case 5: op = rv_op_fltq_s; break;
|
||||
}
|
||||
break;
|
||||
case 81:
|
||||
@@ -3034,14 +3164,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
case 0: op = rv_op_fle_d; break;
|
||||
case 1: op = rv_op_flt_d; break;
|
||||
case 2: op = rv_op_feq_d; break;
|
||||
case 4: op = rv_op_fleq_d; break;
|
||||
case 5: op = rv_op_fltq_d; break;
|
||||
}
|
||||
break;
|
||||
case 82:
|
||||
switch (((inst >> 12) & 0b111)) {
|
||||
case 4: op = rv_op_fleq_h; break;
|
||||
case 5: op = rv_op_fltq_h; break;
|
||||
}
|
||||
break;
|
||||
case 83:
|
||||
@@ -3049,18 +3171,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
case 0: op = rv_op_fle_q; break;
|
||||
case 1: op = rv_op_flt_q; break;
|
||||
case 2: op = rv_op_feq_q; break;
|
||||
case 4: op = rv_op_fleq_q; break;
|
||||
case 5: op = rv_op_fltq_q; break;
|
||||
}
|
||||
break;
|
||||
case 89:
|
||||
switch (((inst >> 12) & 0b111)) {
|
||||
case 0: op = rv_op_fmvp_d_x; break;
|
||||
}
|
||||
break;
|
||||
case 91:
|
||||
switch (((inst >> 12) & 0b111)) {
|
||||
case 0: op = rv_op_fmvp_q_x; break;
|
||||
}
|
||||
break;
|
||||
case 96:
|
||||
@@ -3077,7 +3187,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
case 1: op = rv_op_fcvt_wu_d; break;
|
||||
case 2: op = rv_op_fcvt_l_d; break;
|
||||
case 3: op = rv_op_fcvt_lu_d; break;
|
||||
case 8: op = rv_op_fcvtmod_w_d; break;
|
||||
}
|
||||
break;
|
||||
case 99:
|
||||
@@ -3124,13 +3233,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
((inst >> 12) & 0b00000111)) {
|
||||
case 0: op = rv_op_fmv_x_d; break;
|
||||
case 1: op = rv_op_fclass_d; break;
|
||||
case 8: op = rv_op_fmvh_x_d; break;
|
||||
}
|
||||
break;
|
||||
case 114:
|
||||
switch (((inst >> 17) & 0b11111000) |
|
||||
((inst >> 12) & 0b00000111)) {
|
||||
case 0: op = rv_op_fmv_x_h; break;
|
||||
}
|
||||
break;
|
||||
case 115:
|
||||
@@ -3138,35 +3240,24 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
((inst >> 12) & 0b00000111)) {
|
||||
case 0: op = rv_op_fmv_x_q; break;
|
||||
case 1: op = rv_op_fclass_q; break;
|
||||
case 8: op = rv_op_fmvh_x_q; break;
|
||||
}
|
||||
break;
|
||||
case 120:
|
||||
switch (((inst >> 17) & 0b11111000) |
|
||||
((inst >> 12) & 0b00000111)) {
|
||||
case 0: op = rv_op_fmv_s_x; break;
|
||||
case 8: op = rv_op_fli_s; break;
|
||||
}
|
||||
break;
|
||||
case 121:
|
||||
switch (((inst >> 17) & 0b11111000) |
|
||||
((inst >> 12) & 0b00000111)) {
|
||||
case 0: op = rv_op_fmv_d_x; break;
|
||||
case 8: op = rv_op_fli_d; break;
|
||||
}
|
||||
break;
|
||||
case 122:
|
||||
switch (((inst >> 17) & 0b11111000) |
|
||||
((inst >> 12) & 0b00000111)) {
|
||||
case 0: op = rv_op_fmv_h_x; break;
|
||||
case 8: op = rv_op_fli_h; break;
|
||||
}
|
||||
break;
|
||||
case 123:
|
||||
switch (((inst >> 17) & 0b11111000) |
|
||||
((inst >> 12) & 0b00000111)) {
|
||||
case 0: op = rv_op_fmv_q_x; break;
|
||||
case 8: op = rv_op_fli_q; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3259,7 +3350,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
case 10: op = rv_op_vfwcvt_f_xu_v; break;
|
||||
case 11: op = rv_op_vfwcvt_f_x_v; break;
|
||||
case 12: op = rv_op_vfwcvt_f_f_v; break;
|
||||
case 13: op = rv_op_vfwcvtbf16_f_f_v; break;
|
||||
case 14: op = rv_op_vfwcvt_rtz_xu_f_v; break;
|
||||
case 15: op = rv_op_vfwcvt_rtz_x_f_v; break;
|
||||
case 16: op = rv_op_vfncvt_xu_f_w; break;
|
||||
@@ -3270,7 +3360,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
case 21: op = rv_op_vfncvt_rod_f_f_w; break;
|
||||
case 22: op = rv_op_vfncvt_rtz_xu_f_w; break;
|
||||
case 23: op = rv_op_vfncvt_rtz_x_f_w; break;
|
||||
case 29: op = rv_op_vfncvtbf16_f_f_w; break;
|
||||
}
|
||||
break;
|
||||
case 19:
|
||||
@@ -3302,7 +3391,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
case 52: op = rv_op_vfwadd_wv; break;
|
||||
case 54: op = rv_op_vfwsub_wv; break;
|
||||
case 56: op = rv_op_vfwmul_vv; break;
|
||||
case 59: op = rv_op_vfwmaccbf16_vv; break;
|
||||
case 60: op = rv_op_vfwmacc_vv; break;
|
||||
case 61: op = rv_op_vfwnmacc_vv; break;
|
||||
case 62: op = rv_op_vfwmsac_vv; break;
|
||||
@@ -3541,7 +3629,6 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
case 52: op = rv_op_vfwadd_wf; break;
|
||||
case 54: op = rv_op_vfwsub_wf; break;
|
||||
case 56: op = rv_op_vfwmul_vf; break;
|
||||
case 59: op = rv_op_vfwmaccbf16_vf; break;
|
||||
case 60: op = rv_op_vfwmacc_vf; break;
|
||||
case 61: op = rv_op_vfwnmacc_vf; break;
|
||||
case 62: op = rv_op_vfwmsac_vf; break;
|
||||
@@ -4047,26 +4134,6 @@ static uint32_t operand_zcmp_rlist(rv_inst inst)
|
||||
return ((inst << 56) >> 60);
|
||||
}
|
||||
|
||||
static uint32_t operand_imm6(rv_inst inst)
|
||||
{
|
||||
return (inst << 38) >> 60;
|
||||
}
|
||||
|
||||
static uint32_t operand_imm2(rv_inst inst)
|
||||
{
|
||||
return (inst << 37) >> 62;
|
||||
}
|
||||
|
||||
static uint32_t operand_immh(rv_inst inst)
|
||||
{
|
||||
return (inst << 32) >> 58;
|
||||
}
|
||||
|
||||
static uint32_t operand_imml(rv_inst inst)
|
||||
{
|
||||
return (inst << 38) >> 58;
|
||||
}
|
||||
|
||||
static uint32_t calculate_stack_adj(rv_isa isa, uint32_t rlist, uint32_t spimm)
|
||||
{
|
||||
int xlen_bytes_log2 = isa == rv64 ? 3 : 2;
|
||||
@@ -4090,7 +4157,6 @@ static uint32_t operand_tbl_index(rv_inst inst)
|
||||
|
||||
static void decode_inst_operands(rv_decode *dec, rv_isa isa)
|
||||
{
|
||||
const rv_opcode_data *opcode_data = dec->opcode_data;
|
||||
rv_inst inst = dec->inst;
|
||||
dec->codec = opcode_data[dec->op].codec;
|
||||
switch (dec->codec) {
|
||||
@@ -4430,42 +4496,6 @@ static void decode_inst_operands(rv_decode *dec, rv_isa isa)
|
||||
break;
|
||||
case rv_codec_zcmt_jt:
|
||||
dec->imm = operand_tbl_index(inst);
|
||||
break;
|
||||
case rv_codec_fli:
|
||||
dec->rd = operand_rd(inst);
|
||||
dec->imm = operand_rs1(inst);
|
||||
break;
|
||||
case rv_codec_r2_imm5:
|
||||
dec->rd = operand_rd(inst);
|
||||
dec->rs1 = operand_rs1(inst);
|
||||
dec->imm = operand_rs2(inst);
|
||||
break;
|
||||
case rv_codec_r2:
|
||||
dec->rd = operand_rd(inst);
|
||||
dec->rs1 = operand_rs1(inst);
|
||||
break;
|
||||
case rv_codec_r2_imm6:
|
||||
dec->rd = operand_rd(inst);
|
||||
dec->rs1 = operand_rs1(inst);
|
||||
dec->imm = operand_imm6(inst);
|
||||
break;
|
||||
case rv_codec_r_imm2:
|
||||
dec->rd = operand_rd(inst);
|
||||
dec->rs1 = operand_rs1(inst);
|
||||
dec->rs2 = operand_rs2(inst);
|
||||
dec->imm = operand_imm2(inst);
|
||||
break;
|
||||
case rv_codec_r2_immhl:
|
||||
dec->rd = operand_rd(inst);
|
||||
dec->rs1 = operand_rs1(inst);
|
||||
dec->imm = operand_immh(inst);
|
||||
dec->imm1 = operand_imml(inst);
|
||||
break;
|
||||
case rv_codec_r2_imm2_imm5:
|
||||
dec->rd = operand_rd(inst);
|
||||
dec->rs1 = operand_rs1(inst);
|
||||
dec->imm = sextract32(operand_rs2(inst), 0, 5);
|
||||
dec->imm1 = operand_imm2(inst);
|
||||
break;
|
||||
};
|
||||
}
|
||||
@@ -4609,7 +4639,6 @@ static void append(char *s1, const char *s2, size_t n)
|
||||
|
||||
static void format_inst(char *buf, size_t buflen, size_t tab, rv_decode *dec)
|
||||
{
|
||||
const rv_opcode_data *opcode_data = dec->opcode_data;
|
||||
char tmp[64];
|
||||
const char *fmt;
|
||||
|
||||
@@ -4680,10 +4709,6 @@ static void format_inst(char *buf, size_t buflen, size_t tab, rv_decode *dec)
|
||||
snprintf(tmp, sizeof(tmp), "%u", ((uint32_t)dec->imm & 0b11111));
|
||||
append(buf, tmp, buflen);
|
||||
break;
|
||||
case 'j':
|
||||
snprintf(tmp, sizeof(tmp), "%d", dec->imm1);
|
||||
append(buf, tmp, buflen);
|
||||
break;
|
||||
case 'o':
|
||||
snprintf(tmp, sizeof(tmp), "%d", dec->imm);
|
||||
append(buf, tmp, buflen);
|
||||
@@ -4694,19 +4719,6 @@ static void format_inst(char *buf, size_t buflen, size_t tab, rv_decode *dec)
|
||||
dec->pc + dec->imm);
|
||||
append(buf, tmp, buflen);
|
||||
break;
|
||||
case 'U':
|
||||
fmt++;
|
||||
snprintf(tmp, sizeof(tmp), "%d", dec->imm >> 12);
|
||||
append(buf, tmp, buflen);
|
||||
if (*fmt == 'o') {
|
||||
while (strlen(buf) < tab * 2) {
|
||||
append(buf, " ", buflen);
|
||||
}
|
||||
snprintf(tmp, sizeof(tmp), "# 0x%" PRIx64,
|
||||
dec->pc + dec->imm);
|
||||
append(buf, tmp, buflen);
|
||||
}
|
||||
break;
|
||||
case 'c': {
|
||||
const char *name = csr_name(dec->imm & 0xfff);
|
||||
if (name) {
|
||||
@@ -4857,9 +4869,6 @@ static void format_inst(char *buf, size_t buflen, size_t tab, rv_decode *dec)
|
||||
append(buf, tmp, buflen);
|
||||
break;
|
||||
}
|
||||
case 'h':
|
||||
append(buf, rv_fli_name_const[dec->imm], buflen);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -4871,7 +4880,6 @@ static void format_inst(char *buf, size_t buflen, size_t tab, rv_decode *dec)
|
||||
|
||||
static void decode_inst_lift_pseudo(rv_decode *dec)
|
||||
{
|
||||
const rv_opcode_data *opcode_data = dec->opcode_data;
|
||||
const rv_comp_data *comp_data = opcode_data[dec->op].pseudo;
|
||||
if (!comp_data) {
|
||||
return;
|
||||
@@ -4890,7 +4898,6 @@ static void decode_inst_lift_pseudo(rv_decode *dec)
|
||||
|
||||
static void decode_inst_decompress_rv32(rv_decode *dec)
|
||||
{
|
||||
const rv_opcode_data *opcode_data = dec->opcode_data;
|
||||
int decomp_op = opcode_data[dec->op].decomp_rv32;
|
||||
if (decomp_op != rv_op_illegal) {
|
||||
if ((opcode_data[dec->op].decomp_data & rvcd_imm_nz)
|
||||
@@ -4905,7 +4912,6 @@ static void decode_inst_decompress_rv32(rv_decode *dec)
|
||||
|
||||
static void decode_inst_decompress_rv64(rv_decode *dec)
|
||||
{
|
||||
const rv_opcode_data *opcode_data = dec->opcode_data;
|
||||
int decomp_op = opcode_data[dec->op].decomp_rv64;
|
||||
if (decomp_op != rv_op_illegal) {
|
||||
if ((opcode_data[dec->op].decomp_data & rvcd_imm_nz)
|
||||
@@ -4920,7 +4926,6 @@ static void decode_inst_decompress_rv64(rv_decode *dec)
|
||||
|
||||
static void decode_inst_decompress_rv128(rv_decode *dec)
|
||||
{
|
||||
const rv_opcode_data *opcode_data = dec->opcode_data;
|
||||
int decomp_op = opcode_data[dec->op].decomp_rv128;
|
||||
if (decomp_op != rv_op_illegal) {
|
||||
if ((opcode_data[dec->op].decomp_data & rvcd_imm_nz)
|
||||
@@ -4958,44 +4963,7 @@ disasm_inst(char *buf, size_t buflen, rv_isa isa, uint64_t pc, rv_inst inst,
|
||||
dec.pc = pc;
|
||||
dec.inst = inst;
|
||||
dec.cfg = cfg;
|
||||
|
||||
static const struct {
|
||||
bool (*guard_func)(const RISCVCPUConfig *);
|
||||
const rv_opcode_data *opcode_data;
|
||||
void (*decode_func)(rv_decode *, rv_isa);
|
||||
} decoders[] = {
|
||||
{ always_true_p, rvi_opcode_data, decode_inst_opcode },
|
||||
{ has_xtheadba_p, xthead_opcode_data, decode_xtheadba },
|
||||
{ has_xtheadbb_p, xthead_opcode_data, decode_xtheadbb },
|
||||
{ has_xtheadbs_p, xthead_opcode_data, decode_xtheadbs },
|
||||
{ has_xtheadcmo_p, xthead_opcode_data, decode_xtheadcmo },
|
||||
{ has_xtheadcondmov_p, xthead_opcode_data, decode_xtheadcondmov },
|
||||
{ has_xtheadfmemidx_p, xthead_opcode_data, decode_xtheadfmemidx },
|
||||
{ has_xtheadfmv_p, xthead_opcode_data, decode_xtheadfmv },
|
||||
{ has_xtheadmac_p, xthead_opcode_data, decode_xtheadmac },
|
||||
{ has_xtheadmemidx_p, xthead_opcode_data, decode_xtheadmemidx },
|
||||
{ has_xtheadmempair_p, xthead_opcode_data, decode_xtheadmempair },
|
||||
{ has_xtheadsync_p, xthead_opcode_data, decode_xtheadsync },
|
||||
{ has_XVentanaCondOps_p, ventana_opcode_data, decode_xventanacondops },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(decoders); i++) {
|
||||
bool (*guard_func)(const RISCVCPUConfig *) = decoders[i].guard_func;
|
||||
const rv_opcode_data *opcode_data = decoders[i].opcode_data;
|
||||
void (*decode_func)(rv_decode *, rv_isa) = decoders[i].decode_func;
|
||||
|
||||
if (guard_func(cfg)) {
|
||||
dec.opcode_data = opcode_data;
|
||||
decode_func(&dec, isa);
|
||||
if (dec.op != rv_op_illegal)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dec.op == rv_op_illegal) {
|
||||
dec.opcode_data = rvi_opcode_data;
|
||||
}
|
||||
|
||||
decode_inst_opcode(&dec, isa);
|
||||
decode_inst_operands(&dec, isa);
|
||||
decode_inst_decompress(&dec, isa);
|
||||
decode_inst_lift_pseudo(&dec);
|
||||
|
||||
304
disas/riscv.h
304
disas/riscv.h
@@ -1,304 +0,0 @@
|
||||
/*
|
||||
* QEMU disassembler -- RISC-V specific header.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef DISAS_RISCV_H
|
||||
#define DISAS_RISCV_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "target/riscv/cpu_cfg.h"
|
||||
|
||||
/* types */
|
||||
|
||||
typedef uint64_t rv_inst;
|
||||
typedef uint16_t rv_opcode;
|
||||
|
||||
/* enums */
|
||||
|
||||
typedef enum {
|
||||
rv32,
|
||||
rv64,
|
||||
rv128
|
||||
} rv_isa;
|
||||
|
||||
typedef enum {
|
||||
rv_rm_rne = 0,
|
||||
rv_rm_rtz = 1,
|
||||
rv_rm_rdn = 2,
|
||||
rv_rm_rup = 3,
|
||||
rv_rm_rmm = 4,
|
||||
rv_rm_dyn = 7,
|
||||
} rv_rm;
|
||||
|
||||
typedef enum {
|
||||
rv_fence_i = 8,
|
||||
rv_fence_o = 4,
|
||||
rv_fence_r = 2,
|
||||
rv_fence_w = 1,
|
||||
} rv_fence;
|
||||
|
||||
typedef enum {
|
||||
rv_ireg_zero,
|
||||
rv_ireg_ra,
|
||||
rv_ireg_sp,
|
||||
rv_ireg_gp,
|
||||
rv_ireg_tp,
|
||||
rv_ireg_t0,
|
||||
rv_ireg_t1,
|
||||
rv_ireg_t2,
|
||||
rv_ireg_s0,
|
||||
rv_ireg_s1,
|
||||
rv_ireg_a0,
|
||||
rv_ireg_a1,
|
||||
rv_ireg_a2,
|
||||
rv_ireg_a3,
|
||||
rv_ireg_a4,
|
||||
rv_ireg_a5,
|
||||
rv_ireg_a6,
|
||||
rv_ireg_a7,
|
||||
rv_ireg_s2,
|
||||
rv_ireg_s3,
|
||||
rv_ireg_s4,
|
||||
rv_ireg_s5,
|
||||
rv_ireg_s6,
|
||||
rv_ireg_s7,
|
||||
rv_ireg_s8,
|
||||
rv_ireg_s9,
|
||||
rv_ireg_s10,
|
||||
rv_ireg_s11,
|
||||
rv_ireg_t3,
|
||||
rv_ireg_t4,
|
||||
rv_ireg_t5,
|
||||
rv_ireg_t6,
|
||||
} rv_ireg;
|
||||
|
||||
typedef enum {
|
||||
rvc_end,
|
||||
rvc_rd_eq_ra,
|
||||
rvc_rd_eq_x0,
|
||||
rvc_rs1_eq_x0,
|
||||
rvc_rs2_eq_x0,
|
||||
rvc_rs2_eq_rs1,
|
||||
rvc_rs1_eq_ra,
|
||||
rvc_imm_eq_zero,
|
||||
rvc_imm_eq_n1,
|
||||
rvc_imm_eq_p1,
|
||||
rvc_csr_eq_0x001,
|
||||
rvc_csr_eq_0x002,
|
||||
rvc_csr_eq_0x003,
|
||||
rvc_csr_eq_0xc00,
|
||||
rvc_csr_eq_0xc01,
|
||||
rvc_csr_eq_0xc02,
|
||||
rvc_csr_eq_0xc80,
|
||||
rvc_csr_eq_0xc81,
|
||||
rvc_csr_eq_0xc82,
|
||||
} rvc_constraint;
|
||||
|
||||
typedef enum {
|
||||
rv_codec_illegal,
|
||||
rv_codec_none,
|
||||
rv_codec_u,
|
||||
rv_codec_uj,
|
||||
rv_codec_i,
|
||||
rv_codec_i_sh5,
|
||||
rv_codec_i_sh6,
|
||||
rv_codec_i_sh7,
|
||||
rv_codec_i_csr,
|
||||
rv_codec_s,
|
||||
rv_codec_sb,
|
||||
rv_codec_r,
|
||||
rv_codec_r_m,
|
||||
rv_codec_r4_m,
|
||||
rv_codec_r_a,
|
||||
rv_codec_r_l,
|
||||
rv_codec_r_f,
|
||||
rv_codec_cb,
|
||||
rv_codec_cb_imm,
|
||||
rv_codec_cb_sh5,
|
||||
rv_codec_cb_sh6,
|
||||
rv_codec_ci,
|
||||
rv_codec_ci_sh5,
|
||||
rv_codec_ci_sh6,
|
||||
rv_codec_ci_16sp,
|
||||
rv_codec_ci_lwsp,
|
||||
rv_codec_ci_ldsp,
|
||||
rv_codec_ci_lqsp,
|
||||
rv_codec_ci_li,
|
||||
rv_codec_ci_lui,
|
||||
rv_codec_ci_none,
|
||||
rv_codec_ciw_4spn,
|
||||
rv_codec_cj,
|
||||
rv_codec_cj_jal,
|
||||
rv_codec_cl_lw,
|
||||
rv_codec_cl_ld,
|
||||
rv_codec_cl_lq,
|
||||
rv_codec_cr,
|
||||
rv_codec_cr_mv,
|
||||
rv_codec_cr_jalr,
|
||||
rv_codec_cr_jr,
|
||||
rv_codec_cs,
|
||||
rv_codec_cs_sw,
|
||||
rv_codec_cs_sd,
|
||||
rv_codec_cs_sq,
|
||||
rv_codec_css_swsp,
|
||||
rv_codec_css_sdsp,
|
||||
rv_codec_css_sqsp,
|
||||
rv_codec_k_bs,
|
||||
rv_codec_k_rnum,
|
||||
rv_codec_v_r,
|
||||
rv_codec_v_ldst,
|
||||
rv_codec_v_i,
|
||||
rv_codec_vsetvli,
|
||||
rv_codec_vsetivli,
|
||||
rv_codec_zcb_ext,
|
||||
rv_codec_zcb_mul,
|
||||
rv_codec_zcb_lb,
|
||||
rv_codec_zcb_lh,
|
||||
rv_codec_zcmp_cm_pushpop,
|
||||
rv_codec_zcmp_cm_mv,
|
||||
rv_codec_zcmt_jt,
|
||||
rv_codec_r2_imm5,
|
||||
rv_codec_r2,
|
||||
rv_codec_r2_imm6,
|
||||
rv_codec_r_imm2,
|
||||
rv_codec_r2_immhl,
|
||||
rv_codec_r2_imm2_imm5,
|
||||
rv_codec_fli,
|
||||
} rv_codec;
|
||||
|
||||
/* structures */
|
||||
|
||||
typedef struct {
|
||||
const int op;
|
||||
const rvc_constraint *constraints;
|
||||
} rv_comp_data;
|
||||
|
||||
typedef struct {
|
||||
const char * const name;
|
||||
const rv_codec codec;
|
||||
const char * const format;
|
||||
const rv_comp_data *pseudo;
|
||||
const short decomp_rv32;
|
||||
const short decomp_rv64;
|
||||
const short decomp_rv128;
|
||||
const short decomp_data;
|
||||
} rv_opcode_data;
|
||||
|
||||
typedef struct {
|
||||
RISCVCPUConfig *cfg;
|
||||
uint64_t pc;
|
||||
uint64_t inst;
|
||||
const rv_opcode_data *opcode_data;
|
||||
int32_t imm;
|
||||
int32_t imm1;
|
||||
uint16_t op;
|
||||
uint8_t codec;
|
||||
uint8_t rd;
|
||||
uint8_t rs1;
|
||||
uint8_t rs2;
|
||||
uint8_t rs3;
|
||||
uint8_t rm;
|
||||
uint8_t pred;
|
||||
uint8_t succ;
|
||||
uint8_t aq;
|
||||
uint8_t rl;
|
||||
uint8_t bs;
|
||||
uint8_t rnum;
|
||||
uint8_t vm;
|
||||
uint32_t vzimm;
|
||||
uint8_t rlist;
|
||||
} rv_decode;
|
||||
|
||||
enum {
|
||||
rv_op_illegal = 0
|
||||
};
|
||||
|
||||
enum {
|
||||
rvcd_imm_nz = 0x1
|
||||
};
|
||||
|
||||
/* instruction formats */
|
||||
|
||||
#define rv_fmt_none "O\t"
|
||||
#define rv_fmt_rs1 "O\t1"
|
||||
#define rv_fmt_offset "O\to"
|
||||
#define rv_fmt_pred_succ "O\tp,s"
|
||||
#define rv_fmt_rs1_rs2 "O\t1,2"
|
||||
#define rv_fmt_rd_imm "O\t0,i"
|
||||
#define rv_fmt_rd_uimm "O\t0,Ui"
|
||||
#define rv_fmt_rd_offset "O\t0,o"
|
||||
#define rv_fmt_rd_uoffset "O\t0,Uo"
|
||||
#define rv_fmt_rd_rs1_rs2 "O\t0,1,2"
|
||||
#define rv_fmt_frd_rs1 "O\t3,1"
|
||||
#define rv_fmt_frd_rs1_rs2 "O\t3,1,2"
|
||||
#define rv_fmt_frd_frs1 "O\t3,4"
|
||||
#define rv_fmt_rd_frs1 "O\t0,4"
|
||||
#define rv_fmt_rd_frs1_frs2 "O\t0,4,5"
|
||||
#define rv_fmt_frd_frs1_frs2 "O\t3,4,5"
|
||||
#define rv_fmt_rm_frd_frs1 "O\tr,3,4"
|
||||
#define rv_fmt_rm_frd_rs1 "O\tr,3,1"
|
||||
#define rv_fmt_rm_rd_frs1 "O\tr,0,4"
|
||||
#define rv_fmt_rm_frd_frs1_frs2 "O\tr,3,4,5"
|
||||
#define rv_fmt_rm_frd_frs1_frs2_frs3 "O\tr,3,4,5,6"
|
||||
#define rv_fmt_rd_rs1_imm "O\t0,1,i"
|
||||
#define rv_fmt_rd_rs1_offset "O\t0,1,i"
|
||||
#define rv_fmt_rd_offset_rs1 "O\t0,i(1)"
|
||||
#define rv_fmt_frd_offset_rs1 "O\t3,i(1)"
|
||||
#define rv_fmt_rd_csr_rs1 "O\t0,c,1"
|
||||
#define rv_fmt_rd_csr_zimm "O\t0,c,7"
|
||||
#define rv_fmt_rs2_offset_rs1 "O\t2,i(1)"
|
||||
#define rv_fmt_frs2_offset_rs1 "O\t5,i(1)"
|
||||
#define rv_fmt_rs1_rs2_offset "O\t1,2,o"
|
||||
#define rv_fmt_rs2_rs1_offset "O\t2,1,o"
|
||||
#define rv_fmt_aqrl_rd_rs2_rs1 "OAR\t0,2,(1)"
|
||||
#define rv_fmt_aqrl_rd_rs1 "OAR\t0,(1)"
|
||||
#define rv_fmt_rd "O\t0"
|
||||
#define rv_fmt_rd_zimm "O\t0,7"
|
||||
#define rv_fmt_rd_rs1 "O\t0,1"
|
||||
#define rv_fmt_rd_rs2 "O\t0,2"
|
||||
#define rv_fmt_rs1_offset "O\t1,o"
|
||||
#define rv_fmt_rs2_offset "O\t2,o"
|
||||
#define rv_fmt_rs1_rs2_bs "O\t1,2,b"
|
||||
#define rv_fmt_rd_rs1_rnum "O\t0,1,n"
|
||||
#define rv_fmt_ldst_vd_rs1_vm "O\tD,(1)m"
|
||||
#define rv_fmt_ldst_vd_rs1_rs2_vm "O\tD,(1),2m"
|
||||
#define rv_fmt_ldst_vd_rs1_vs2_vm "O\tD,(1),Fm"
|
||||
#define rv_fmt_vd_vs2_vs1 "O\tD,F,E"
|
||||
#define rv_fmt_vd_vs2_vs1_vl "O\tD,F,El"
|
||||
#define rv_fmt_vd_vs2_vs1_vm "O\tD,F,Em"
|
||||
#define rv_fmt_vd_vs2_rs1_vl "O\tD,F,1l"
|
||||
#define rv_fmt_vd_vs2_fs1_vl "O\tD,F,4l"
|
||||
#define rv_fmt_vd_vs2_rs1_vm "O\tD,F,1m"
|
||||
#define rv_fmt_vd_vs2_fs1_vm "O\tD,F,4m"
|
||||
#define rv_fmt_vd_vs2_imm_vl "O\tD,F,il"
|
||||
#define rv_fmt_vd_vs2_imm_vm "O\tD,F,im"
|
||||
#define rv_fmt_vd_vs2_uimm_vm "O\tD,F,um"
|
||||
#define rv_fmt_vd_vs1_vs2_vm "O\tD,E,Fm"
|
||||
#define rv_fmt_vd_rs1_vs2_vm "O\tD,1,Fm"
|
||||
#define rv_fmt_vd_fs1_vs2_vm "O\tD,4,Fm"
|
||||
#define rv_fmt_vd_vs1 "O\tD,E"
|
||||
#define rv_fmt_vd_rs1 "O\tD,1"
|
||||
#define rv_fmt_vd_fs1 "O\tD,4"
|
||||
#define rv_fmt_vd_imm "O\tD,i"
|
||||
#define rv_fmt_vd_vs2 "O\tD,F"
|
||||
#define rv_fmt_vd_vs2_vm "O\tD,Fm"
|
||||
#define rv_fmt_rd_vs2_vm "O\t0,Fm"
|
||||
#define rv_fmt_rd_vs2 "O\t0,F"
|
||||
#define rv_fmt_fd_vs2 "O\t3,F"
|
||||
#define rv_fmt_vd_vm "O\tDm"
|
||||
#define rv_fmt_vsetvli "O\t0,1,v"
|
||||
#define rv_fmt_vsetivli "O\t0,u,v"
|
||||
#define rv_fmt_rs1_rs2_zce_ldst "O\t2,i(1)"
|
||||
#define rv_fmt_push_rlist "O\tx,-i"
|
||||
#define rv_fmt_pop_rlist "O\tx,i"
|
||||
#define rv_fmt_zcmt_index "O\ti"
|
||||
#define rv_fmt_rd_rs1_rs2_imm "O\t0,1,2,i"
|
||||
#define rv_fmt_frd_rs1_rs2_imm "O\t3,1,2,i"
|
||||
#define rv_fmt_rd_rs1_immh_imml "O\t0,1,i,j"
|
||||
#define rv_fmt_rd_rs1_immh_imml_addr "O\t0,(1),i,j"
|
||||
#define rv_fmt_rd2_imm "O\t0,2,(1),i"
|
||||
#define rv_fmt_fli "O\t3,h"
|
||||
|
||||
#endif /* DISAS_RISCV_H */
|
||||
@@ -116,11 +116,6 @@ Use "whpx" (on Windows) or "hvf" (on macOS) instead.
|
||||
|
||||
Use ``-run-with async-teardown=on`` instead.
|
||||
|
||||
``-chroot`` (since 8.1)
|
||||
'''''''''''''''''''''''
|
||||
|
||||
Use ``-run-with chroot=dir`` instead.
|
||||
|
||||
``-singlestep`` (since 8.1)
|
||||
'''''''''''''''''''''''''''
|
||||
|
||||
@@ -348,29 +343,6 @@ the addition of volatile memory support, it is now necessary to distinguish
|
||||
between persistent and volatile memory backends. As such, memdev is deprecated
|
||||
in favor of persistent-memdev.
|
||||
|
||||
``-fsdev proxy`` and ``-virtfs proxy`` (since 8.1)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The 9p ``proxy`` filesystem backend driver has been deprecated and will be
|
||||
removed (along with its proxy helper daemon) in a future version of QEMU. Please
|
||||
use ``-fsdev local`` or ``-virtfs local`` for using the 9p ``local`` filesystem
|
||||
backend, or alternatively consider deploying virtiofsd instead.
|
||||
|
||||
The 9p ``proxy`` backend was originally developed as an alternative to the 9p
|
||||
``local`` backend. The idea was to enhance security by dispatching actual low
|
||||
level filesystem operations from 9p server (QEMU process) over to a separate
|
||||
process (the virtfs-proxy-helper binary). However this alternative never gained
|
||||
momentum. The proxy backend is much slower than the local backend, hasn't seen
|
||||
any development in years, and showed to be less secure, especially due to the
|
||||
fact that its helper daemon must be run as root, whereas with the local backend
|
||||
QEMU is typically run as unprivileged user and allows to tighten behaviour by
|
||||
mapping permissions et al by using its 'mapped' security model option.
|
||||
|
||||
Nowadays it would make sense to reimplement the ``proxy`` backend by using
|
||||
QEMU's ``vhost`` feature, which would eliminate the high latency costs under
|
||||
which the 9p ``proxy`` backend currently suffers. However as of to date nobody
|
||||
has indicated plans for such kind of reimplementation unfortunately.
|
||||
|
||||
|
||||
Block device options
|
||||
''''''''''''''''''''
|
||||
@@ -451,13 +423,3 @@ both, older and future versions of QEMU.
|
||||
The ``blacklist`` config file option has been renamed to ``block-rpcs``
|
||||
(to be in sync with the renaming of the corresponding command line
|
||||
option).
|
||||
|
||||
Migration
|
||||
---------
|
||||
|
||||
``skipped`` MigrationStats field (since 8.1)
|
||||
''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
``skipped`` field in Migration stats has been deprecated. It hasn't
|
||||
been used for more than 10 years.
|
||||
|
||||
|
||||
@@ -8,4 +8,4 @@ QEMU is a trademark of Fabrice Bellard.
|
||||
QEMU is released under the `GNU General Public
|
||||
License <https://www.gnu.org/licenses/gpl-2.0.txt>`__, version 2. Parts
|
||||
of QEMU have specific licenses, see file
|
||||
`LICENSE <https://gitlab.com/qemu-project/qemu/-/raw/master/LICENSE>`__.
|
||||
`LICENSE <https://git.qemu.org/?p=qemu.git;a=blob_plain;f=LICENSE>`__.
|
||||
|
||||
@@ -11,7 +11,5 @@ generated from in-code annotations to function prototypes.
|
||||
loads-stores
|
||||
memory
|
||||
modules
|
||||
qom-api
|
||||
qdev-api
|
||||
ui
|
||||
zoned-storage
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
.. _development_process:
|
||||
|
||||
QEMU Community Processes
|
||||
------------------------
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
.. _tcg:
|
||||
|
||||
TCG Emulation
|
||||
-------------
|
||||
|
||||
|
||||
@@ -2,30 +2,10 @@
|
||||
Developer Information
|
||||
---------------------
|
||||
|
||||
This section of the manual documents various parts of the internals of
|
||||
QEMU. You only need to read it if you are interested in reading or
|
||||
This section of the manual documents various parts of the internals of QEMU.
|
||||
You only need to read it if you are interested in reading or
|
||||
modifying QEMU's source code.
|
||||
|
||||
QEMU is a large and mature project with a number of complex subsystems
|
||||
that can be overwhelming to understand. The development documentation
|
||||
is not comprehensive but hopefully presents enough to get you started.
|
||||
If there are areas that are unclear please reach out either via the
|
||||
IRC channel or mailing list and hopefully we can improve the
|
||||
documentation for future developers.
|
||||
|
||||
All developers will want to familiarise themselves with
|
||||
:ref:`development_process` and how the community interacts. Please pay
|
||||
particular attention to the :ref:`coding-style` and
|
||||
:ref:`submitting-a-patch` sections to avoid common pitfalls.
|
||||
|
||||
If you wish to implement a new hardware model you will want to read
|
||||
through the :ref:`qom` documentation to understand how QEMU's object
|
||||
model works.
|
||||
|
||||
Those wishing to enhance or add new CPU emulation capabilities will
|
||||
want to read our :ref:`tcg` documentation, especially the overview of
|
||||
the :ref:`tcg_internals`.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
|
||||
@@ -594,7 +594,8 @@ Postcopy
|
||||
'Postcopy' migration is a way to deal with migrations that refuse to converge
|
||||
(or take too long to converge) its plus side is that there is an upper bound on
|
||||
the amount of migration traffic and time it takes, the down side is that during
|
||||
the postcopy phase, a failure of *either* side causes the guest to be lost.
|
||||
the postcopy phase, a failure of *either* side or the network connection causes
|
||||
the guest to be lost.
|
||||
|
||||
In postcopy the destination CPUs are started before all the memory has been
|
||||
transferred, and accesses to pages that are yet to be transferred cause
|
||||
@@ -720,42 +721,6 @@ processing.
|
||||
is no longer used by migration, while the listen thread carries on servicing
|
||||
page data until the end of migration.
|
||||
|
||||
Postcopy Recovery
|
||||
-----------------
|
||||
|
||||
Comparing to precopy, postcopy is special on error handlings. When any
|
||||
error happens (in this case, mostly network errors), QEMU cannot easily
|
||||
fail a migration because VM data resides in both source and destination
|
||||
QEMU instances. On the other hand, when issue happens QEMU on both sides
|
||||
will go into a paused state. It'll need a recovery phase to continue a
|
||||
paused postcopy migration.
|
||||
|
||||
The recovery phase normally contains a few steps:
|
||||
|
||||
- When network issue occurs, both QEMU will go into PAUSED state
|
||||
|
||||
- When the network is recovered (or a new network is provided), the admin
|
||||
can setup the new channel for migration using QMP command
|
||||
'migrate-recover' on destination node, preparing for a resume.
|
||||
|
||||
- On source host, the admin can continue the interrupted postcopy
|
||||
migration using QMP command 'migrate' with resume=true flag set.
|
||||
|
||||
- After the connection is re-established, QEMU will continue the postcopy
|
||||
migration on both sides.
|
||||
|
||||
During a paused postcopy migration, the VM can logically still continue
|
||||
running, and it will not be impacted from any page access to pages that
|
||||
were already migrated to destination VM before the interruption happens.
|
||||
However, if any of the missing pages got accessed on destination VM, the VM
|
||||
thread will be halted waiting for the page to be migrated, it means it can
|
||||
be halted until the recovery is complete.
|
||||
|
||||
The impact of accessing missing pages can be relevant to different
|
||||
configurations of the guest. For example, when with async page fault
|
||||
enabled, logically the guest can proactively schedule out the threads
|
||||
accessing missing pages.
|
||||
|
||||
Postcopy states
|
||||
---------------
|
||||
|
||||
@@ -800,31 +765,36 @@ ADVISE->DISCARD->LISTEN->RUNNING->END
|
||||
(although it can't do the cleanup it would do as it
|
||||
finishes a normal migration).
|
||||
|
||||
- Paused
|
||||
|
||||
Postcopy can run into a paused state (normally on both sides when
|
||||
happens), where all threads will be temporarily halted mostly due to
|
||||
network errors. When reaching paused state, migration will make sure
|
||||
the qemu binary on both sides maintain the data without corrupting
|
||||
the VM. To continue the migration, the admin needs to fix the
|
||||
migration channel using the QMP command 'migrate-recover' on the
|
||||
destination node, then resume the migration using QMP command 'migrate'
|
||||
again on source node, with resume=true flag set.
|
||||
|
||||
- End
|
||||
|
||||
The listen thread can now quit, and perform the cleanup of migration
|
||||
state, the migration is now complete.
|
||||
|
||||
Source side page map
|
||||
--------------------
|
||||
Source side page maps
|
||||
---------------------
|
||||
|
||||
The 'migration bitmap' in postcopy is basically the same as in the precopy,
|
||||
where each of the bit to indicate that page is 'dirty' - i.e. needs
|
||||
sending. During the precopy phase this is updated as the CPU dirties
|
||||
pages, however during postcopy the CPUs are stopped and nothing should
|
||||
dirty anything any more. Instead, dirty bits are cleared when the relevant
|
||||
pages are sent during postcopy.
|
||||
The source side keeps two bitmaps during postcopy; 'the migration bitmap'
|
||||
and 'unsent map'. The 'migration bitmap' is basically the same as in
|
||||
the precopy case, and holds a bit to indicate that page is 'dirty' -
|
||||
i.e. needs sending. During the precopy phase this is updated as the CPU
|
||||
dirties pages, however during postcopy the CPUs are stopped and nothing
|
||||
should dirty anything any more.
|
||||
|
||||
The 'unsent map' is used for the transition to postcopy. It is a bitmap that
|
||||
has a bit cleared whenever a page is sent to the destination, however during
|
||||
the transition to postcopy mode it is combined with the migration bitmap
|
||||
to form a set of pages that:
|
||||
|
||||
a) Have been sent but then redirtied (which must be discarded)
|
||||
b) Have not yet been sent - which also must be discarded to cause any
|
||||
transparent huge pages built during precopy to be broken.
|
||||
|
||||
Note that the contents of the unsentmap are sacrificed during the calculation
|
||||
of the discard set and thus aren't valid once in postcopy. The dirtymap
|
||||
is still valid and is used to ensure that no page is sent more than once. Any
|
||||
request for a page that has already been sent is ignored. Duplicate requests
|
||||
such as this can happen as a page is sent at about the same time the
|
||||
destination accesses it.
|
||||
|
||||
Postcopy with hugepages
|
||||
-----------------------
|
||||
@@ -883,16 +853,6 @@ Retro-fitting postcopy to existing clients is possible:
|
||||
guest memory access is made while holding a lock then all other
|
||||
threads waiting for that lock will also be blocked.
|
||||
|
||||
Postcopy Preemption Mode
|
||||
------------------------
|
||||
|
||||
Postcopy preempt is a new capability introduced in 8.0 QEMU release, it
|
||||
allows urgent pages (those got page fault requested from destination QEMU
|
||||
explicitly) to be sent in a separate preempt channel, rather than queued in
|
||||
the background migration channel. Anyone who cares about latencies of page
|
||||
faults during a postcopy migration should enable this feature. By default,
|
||||
it's not enabled.
|
||||
|
||||
Firmware
|
||||
========
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
.. _qdev-api:
|
||||
|
||||
================================
|
||||
QEMU Device (qdev) API Reference
|
||||
================================
|
||||
|
||||
.. kernel-doc:: include/hw/qdev-core.h
|
||||
@@ -1,9 +0,0 @@
|
||||
.. _qom-api:
|
||||
|
||||
=====================================
|
||||
QEMU Object Model (QOM) API Reference
|
||||
=====================================
|
||||
|
||||
This is the complete API documentation for :ref:`qom`.
|
||||
|
||||
.. kernel-doc:: include/qom/object.h
|
||||
@@ -13,24 +13,6 @@ features:
|
||||
- System for dynamically registering types
|
||||
- Support for single-inheritance of types
|
||||
- Multiple inheritance of stateless interfaces
|
||||
- Mapping internal members to publicly exposed properties
|
||||
|
||||
The root object class is TYPE_OBJECT which provides for the basic
|
||||
object methods.
|
||||
|
||||
The QOM tree
|
||||
============
|
||||
|
||||
The QOM tree is a composition tree which represents all of the objects
|
||||
that make up a QEMU "machine". You can view this tree by running
|
||||
``info qom-tree`` in the :ref:`QEMU monitor`. It will contain both
|
||||
objects created by the machine itself as well those created due to
|
||||
user configuration.
|
||||
|
||||
Creating a QOM class
|
||||
====================
|
||||
|
||||
A simple minimal device implementation may look something like below:
|
||||
|
||||
.. code-block:: c
|
||||
:caption: Creating a minimal type
|
||||
@@ -44,7 +26,7 @@ A simple minimal device implementation may look something like below:
|
||||
typedef DeviceClass MyDeviceClass;
|
||||
typedef struct MyDevice
|
||||
{
|
||||
DeviceState parent_obj;
|
||||
DeviceState parent;
|
||||
|
||||
int reg0, reg1, reg2;
|
||||
} MyDevice;
|
||||
@@ -66,12 +48,6 @@ In the above example, we create a simple type that is described by #TypeInfo.
|
||||
#TypeInfo describes information about the type including what it inherits
|
||||
from, the instance and class size, and constructor/destructor hooks.
|
||||
|
||||
The TYPE_DEVICE class is the parent class for all modern devices
|
||||
implemented in QEMU and adds some specific methods to handle QEMU
|
||||
device model. This includes managing the lifetime of devices from
|
||||
creation through to when they become visible to the guest and
|
||||
eventually unrealized.
|
||||
|
||||
Alternatively several static types could be registered using helper macro
|
||||
DEFINE_TYPES()
|
||||
|
||||
@@ -122,7 +98,7 @@ when the object is needed.
|
||||
module_obj(TYPE_MY_DEVICE);
|
||||
|
||||
Class Initialization
|
||||
--------------------
|
||||
====================
|
||||
|
||||
Before an object is initialized, the class for the object must be
|
||||
initialized. There is only one class object for all instance objects
|
||||
@@ -171,7 +147,7 @@ will also have a wrapper function to call it easily:
|
||||
|
||||
typedef struct MyDeviceClass
|
||||
{
|
||||
DeviceClass parent_class;
|
||||
DeviceClass parent;
|
||||
|
||||
void (*frobnicate) (MyDevice *obj);
|
||||
} MyDeviceClass;
|
||||
@@ -192,7 +168,7 @@ will also have a wrapper function to call it easily:
|
||||
}
|
||||
|
||||
Interfaces
|
||||
----------
|
||||
==========
|
||||
|
||||
Interfaces allow a limited form of multiple inheritance. Instances are
|
||||
similar to normal types except for the fact that are only defined by
|
||||
@@ -206,7 +182,7 @@ an argument to a method on its corresponding SomethingIfClass, or to
|
||||
dynamically cast it to an object that implements the interface.
|
||||
|
||||
Methods
|
||||
-------
|
||||
=======
|
||||
|
||||
A *method* is a function within the namespace scope of
|
||||
a class. It usually operates on the object instance by passing it as a
|
||||
@@ -299,8 +275,8 @@ Alternatively, object_class_by_name() can be used to obtain the class and
|
||||
its non-overridden methods for a specific type. This would correspond to
|
||||
``MyClass::method(...)`` in C++.
|
||||
|
||||
One example of such methods is ``DeviceClass.reset``. More examples
|
||||
can be found at :ref:`device-life-cycle`.
|
||||
The first example of such a QOM method was #CPUClass.reset,
|
||||
another example is #DeviceClass.realize.
|
||||
|
||||
Standard type declaration and definition macros
|
||||
===============================================
|
||||
@@ -406,32 +382,9 @@ OBJECT_DEFINE_ABSTRACT_TYPE() macro can be used instead:
|
||||
OBJECT_DEFINE_ABSTRACT_TYPE(MyDevice, my_device,
|
||||
MY_DEVICE, DEVICE)
|
||||
|
||||
.. _device-life-cycle:
|
||||
|
||||
Device Life-cycle
|
||||
=================
|
||||
|
||||
As class initialisation cannot fail devices have an two additional
|
||||
methods to handle the creation of dynamic devices. The ``realize``
|
||||
function is called with ``Error **`` pointer which should be set if
|
||||
the device cannot complete its setup. Otherwise on successful
|
||||
completion of the ``realize`` method the device object is added to the
|
||||
QOM tree and made visible to the guest.
|
||||
|
||||
The reverse function is ``unrealize`` and should be were clean-up
|
||||
code lives to tidy up after the system is done with the device.
|
||||
|
||||
All devices can be instantiated by C code, however only some can
|
||||
created dynamically via the command line or monitor.
|
||||
|
||||
Likewise only some can be unplugged after creation and need an
|
||||
explicit ``unrealize`` implementation. This is determined by the
|
||||
``user_creatable`` variable in the root ``DeviceClass`` structure.
|
||||
Devices can only be unplugged if their ``parent_bus`` has a registered
|
||||
``HotplugHandler``.
|
||||
|
||||
API Reference
|
||||
=============
|
||||
-------------
|
||||
|
||||
See the :ref:`QOM API<qom-api>` and :ref:`QDEV API<qdev-api>`
|
||||
documents for the complete API description.
|
||||
.. kernel-doc:: include/qom/object.h
|
||||
|
||||
@@ -567,8 +567,7 @@ For example, instead of
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int somefunc(void)
|
||||
{
|
||||
int somefunc(void) {
|
||||
int ret = -1;
|
||||
char *foo = g_strdup_printf("foo%", "wibble");
|
||||
GList *bar = .....
|
||||
@@ -589,8 +588,7 @@ Using g_autofree/g_autoptr enables the code to be written as:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int somefunc(void)
|
||||
{
|
||||
int somefunc(void) {
|
||||
g_autofree char *foo = g_strdup_printf("foo%", "wibble");
|
||||
g_autoptr (GList) bar = .....
|
||||
|
||||
@@ -615,8 +613,7 @@ are still some caveats to beware of
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
char *somefunc(void)
|
||||
{
|
||||
char *somefunc(void) {
|
||||
g_autofree char *foo = g_strdup_printf("foo%", "wibble");
|
||||
g_autoptr (GList) bar = .....
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
.. _tcg_internals:
|
||||
|
||||
====================
|
||||
Translator Internals
|
||||
====================
|
||||
|
||||
@@ -485,12 +485,6 @@ first to contribute the mapping to the ``libvirt-ci`` project:
|
||||
`CI <https://www.qemu.org/docs/master/devel/ci.html>`__ documentation
|
||||
page on how to trigger gitlab CI pipelines on your change.
|
||||
|
||||
* Please also trigger gitlab container generation pipelines on your change
|
||||
for as many OS distros as practical to make sure that there are no
|
||||
obvious breakages when adding the new pre-requisite. Please see
|
||||
`CI <https://www.qemu.org/docs/master/devel/ci.html>`__ documentation
|
||||
page on how to trigger gitlab CI pipelines on your change.
|
||||
|
||||
For enterprise distros that default to old, end-of-life versions of the
|
||||
Python runtime, QEMU uses a separate set of mappings that work with more
|
||||
recent versions. These can be found in ``tests/lcitool/mappings.yml``.
|
||||
@@ -1384,11 +1378,6 @@ variable as shown on the code snippet below to skip the test:
|
||||
def test(self):
|
||||
do_something()
|
||||
|
||||
QEMU_TEST_FLAKY_TESTS
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
Some tests are not working reliably and thus are disabled by default.
|
||||
Set this environment variable to enable them.
|
||||
|
||||
Uninstalling Avocado
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -84,11 +84,6 @@ Options
|
||||
Comma-separated list of RPCs to disable (no spaces, use ``help`` to
|
||||
list available RPCs).
|
||||
|
||||
.. option:: -a, --allow-rpcs=LIST
|
||||
|
||||
Comma-separated list of RPCs to enable (no spaces, use ``help`` to
|
||||
list available RPCs).
|
||||
|
||||
.. option:: -D, --dump-conf
|
||||
|
||||
Dump the configuration in a format compatible with ``qemu-ga.conf``
|
||||
|
||||
@@ -124,16 +124,6 @@ VhostUserGpuDMABUFScanout
|
||||
:fourcc: ``i32``, the DMABUF fourcc
|
||||
|
||||
|
||||
VhostUserGpuEdidRequest
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
+------------+
|
||||
| scanout-id |
|
||||
+------------+
|
||||
|
||||
:scanout-id: ``u32``, the scanout to get edid from
|
||||
|
||||
|
||||
C structure
|
||||
-----------
|
||||
|
||||
@@ -151,8 +141,6 @@ In QEMU the vhost-user-gpu message is implemented with the following struct:
|
||||
VhostUserGpuScanout scanout;
|
||||
VhostUserGpuUpdate update;
|
||||
VhostUserGpuDMABUFScanout dmabuf_scanout;
|
||||
VhostUserGpuEdidRequest edid_req;
|
||||
struct virtio_gpu_resp_edid resp_edid;
|
||||
struct virtio_gpu_resp_display_info display_info;
|
||||
uint64_t u64;
|
||||
} payload;
|
||||
@@ -161,11 +149,10 @@ In QEMU the vhost-user-gpu message is implemented with the following struct:
|
||||
Protocol features
|
||||
-----------------
|
||||
|
||||
.. code:: c
|
||||
None yet.
|
||||
|
||||
#define VHOST_USER_GPU_PROTOCOL_F_EDID 0
|
||||
|
||||
New messages and communication changes are negotiated thanks to the
|
||||
As the protocol may need to evolve, new messages and communication
|
||||
changes are negotiated thanks to preliminary
|
||||
``VHOST_USER_GPU_GET_PROTOCOL_FEATURES`` and
|
||||
``VHOST_USER_GPU_SET_PROTOCOL_FEATURES`` requests.
|
||||
|
||||
@@ -254,12 +241,3 @@ Message types
|
||||
Note: there is no data payload, since the scanout is shared thanks
|
||||
to DMABUF, that must have been set previously with
|
||||
``VHOST_USER_GPU_DMABUF_SCANOUT``.
|
||||
|
||||
``VHOST_USER_GPU_GET_EDID``
|
||||
:id: 11
|
||||
:request payload: ``struct VhostUserGpuEdidRequest``
|
||||
:reply payload: ``struct virtio_gpu_resp_edid`` (from virtio specification)
|
||||
|
||||
Retrieve the EDID data for a given scanout.
|
||||
This message requires the ``VHOST_USER_GPU_PROTOCOL_F_EDID`` protocol
|
||||
feature to be supported.
|
||||
|
||||
@@ -117,13 +117,13 @@ to support the multiple thread compression migration:
|
||||
{qemu} migrate_set_capability compress on
|
||||
|
||||
3. Set the compression thread count on source:
|
||||
{qemu} migrate_set_parameter compress-threads 12
|
||||
{qemu} migrate_set_parameter compress_threads 12
|
||||
|
||||
4. Set the compression level on the source:
|
||||
{qemu} migrate_set_parameter compress-level 1
|
||||
{qemu} migrate_set_parameter compress_level 1
|
||||
|
||||
5. Set the decompression thread count on destination:
|
||||
{qemu} migrate_set_parameter decompress-threads 3
|
||||
{qemu} migrate_set_parameter decompress_threads 3
|
||||
|
||||
6. Start outgoing migration:
|
||||
{qemu} migrate -d tcp:destination.host:4444
|
||||
@@ -133,9 +133,9 @@ to support the multiple thread compression migration:
|
||||
|
||||
The following are the default settings:
|
||||
compress: off
|
||||
compress-threads: 8
|
||||
decompress-threads: 2
|
||||
compress-level: 1 (which means best speed)
|
||||
compress_threads: 8
|
||||
decompress_threads: 2
|
||||
compress_level: 1 (which means best speed)
|
||||
|
||||
So, only the first two steps are required to use the multiple
|
||||
thread compression in migration. You can do more if the default
|
||||
|
||||
@@ -48,7 +48,7 @@ setting up a BAR for a VF.
|
||||
...
|
||||
int ret = pcie_endpoint_cap_init(d, 0x70);
|
||||
...
|
||||
pcie_ari_init(d, 0x100);
|
||||
pcie_ari_init(d, 0x100, 1);
|
||||
...
|
||||
|
||||
/* Add and initialize the SR/IOV capability */
|
||||
@@ -78,7 +78,7 @@ setting up a BAR for a VF.
|
||||
...
|
||||
int ret = pcie_endpoint_cap_init(d, 0x60);
|
||||
...
|
||||
pcie_ari_init(d, 0x100);
|
||||
pcie_ari_init(d, 0x100, 1);
|
||||
...
|
||||
memory_region_init(mr, ... )
|
||||
pcie_sriov_vf_register_bar(d, bar_nr, mr);
|
||||
|
||||
@@ -89,7 +89,7 @@ RUNNING:
|
||||
First, set the migration speed to match your hardware's capabilities:
|
||||
|
||||
QEMU Monitor Command:
|
||||
$ migrate_set_parameter max-bandwidth 40g # or whatever is the MAX of your RDMA device
|
||||
$ migrate_set_parameter max_bandwidth 40g # or whatever is the MAX of your RDMA device
|
||||
|
||||
Next, on the destination machine, add the following to the QEMU command line:
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ the following architecture extensions:
|
||||
- FEAT_BBM at level 2 (Translation table break-before-make levels)
|
||||
- FEAT_BF16 (AArch64 BFloat16 instructions)
|
||||
- FEAT_BTI (Branch Target Identification)
|
||||
- FEAT_CRC32 (CRC32 instructions)
|
||||
- FEAT_CSV2 (Cache speculation variant 2)
|
||||
- FEAT_CSV2_1p1 (Cache speculation variant 2, version 1.1)
|
||||
- FEAT_CSV2_1p2 (Cache speculation variant 2, version 1.2)
|
||||
|
||||
@@ -19,7 +19,7 @@ The ``sbsa-ref`` board supports:
|
||||
- A configurable number of AArch64 CPUs
|
||||
- GIC version 3
|
||||
- System bus AHCI controller
|
||||
- System bus XHCI controller
|
||||
- System bus EHCI controller
|
||||
- CDROM and hard disc on AHCI bus
|
||||
- E1000E ethernet card on PCIe bus
|
||||
- Bochs display adapter on PCIe bus
|
||||
@@ -68,6 +68,3 @@ Platform version changes:
|
||||
|
||||
0.2
|
||||
GIC ITS information is present in devicetree.
|
||||
|
||||
0.3
|
||||
The USB controller is an XHCI device, not EHCI
|
||||
|
||||
@@ -61,7 +61,6 @@ Supported guest CPU types:
|
||||
- ``a64fx`` (64-bit)
|
||||
- ``host`` (with KVM only)
|
||||
- ``neoverse-n1`` (64-bit)
|
||||
- ``neoverse-v1`` (64-bit)
|
||||
- ``max`` (same as ``host`` for KVM; best possible emulation with TCG)
|
||||
|
||||
Note that the default is ``cortex-a15``, so for an AArch64 guest you must
|
||||
|
||||
@@ -232,7 +232,7 @@ parameters:
|
||||
Set the number of Reclaim Groups.
|
||||
|
||||
``fdp.nruh`` (default: ``0``)
|
||||
Set the number of Reclaim Unit Handles. This is a mandatory parameter and
|
||||
Set the number of Reclaim Unit Handles. This is a mandatory paramater and
|
||||
must be non-zero.
|
||||
|
||||
``fdp.runs`` (default: ``96M``)
|
||||
@@ -271,15 +271,9 @@ The virtual namespace device supports DIF- and DIX-based protection information
|
||||
|
||||
``pil=UINT8`` (default: ``0``)
|
||||
Controls the location of the protection information within the metadata. Set
|
||||
to ``1`` to transfer protection information as the first bytes of metadata.
|
||||
Otherwise, the protection information is transferred as the last bytes of
|
||||
metadata.
|
||||
|
||||
``pif=UINT8`` (default: ``0``)
|
||||
By default, the namespace device uses 16 bit guard protection information
|
||||
format (``pif=0``). Set to ``2`` to enable 64 bit guard protection
|
||||
information format. This requires at least 16 bytes of metadata. Note that
|
||||
``pif=1`` (32 bit guards) is currently not supported.
|
||||
to ``1`` to transfer protection information as the first eight bytes of
|
||||
metadata. Otherwise, the protection information is transferred as the last
|
||||
eight bytes.
|
||||
|
||||
Virtualization Enhancements and SR-IOV (Experimental Support)
|
||||
-------------------------------------------------------------
|
||||
|
||||
@@ -214,18 +214,3 @@ The memory mode can be checked by sending the following command:
|
||||
|
||||
``maintenance packet Qqemu.PhyMemMode:0``
|
||||
This will change it back to normal memory mode.
|
||||
|
||||
Security considerations
|
||||
=======================
|
||||
|
||||
Connecting to the GDB socket allows running arbitrary code inside the guest;
|
||||
in case of the TCG emulation, which is not considered a security boundary, this
|
||||
also means running arbitrary code on the host. Additionally, when debugging
|
||||
qemu-user, it allows directly downloading any file readable by QEMU from the
|
||||
host.
|
||||
|
||||
The GDB socket is not protected by authentication, authorization or encryption.
|
||||
It is therefore a responsibility of the user to make sure that only authorized
|
||||
clients can connect to it, e.g., by using a unix socket with proper
|
||||
permissions, or by opening a TCP socket only on interfaces that are not
|
||||
reachable by potential attackers.
|
||||
|
||||
@@ -195,6 +195,11 @@ Use a MTD drive to add a PNOR to the machine, and get a NVRAM :
|
||||
|
||||
-drive file=./witherspoon.pnor,format=raw,if=mtd
|
||||
|
||||
CAVEATS
|
||||
-------
|
||||
|
||||
* No support for multiple HW threads (SMT=1). Same as pseries.
|
||||
|
||||
Maintainer contact information
|
||||
------------------------------
|
||||
|
||||
|
||||
@@ -93,7 +93,6 @@ The following machine-specific options are supported:
|
||||
|
||||
When this option is "on", ACLINT devices will be emulated instead of
|
||||
SiFive CLINT. When not specified, this option is assumed to be "off".
|
||||
This option is restricted to the TCG accelerator.
|
||||
|
||||
- aia=[none|aplic|aplic-imsic]
|
||||
|
||||
|
||||
@@ -76,19 +76,11 @@ RISC-V CPU firmware
|
||||
|
||||
When using the ``sifive_u`` or ``virt`` machine there are three different
|
||||
firmware boot options:
|
||||
|
||||
* ``-bios default``
|
||||
|
||||
This is the default behaviour if no ``-bios`` option is included. This option
|
||||
will load the default OpenSBI firmware automatically. The firmware is included
|
||||
with the QEMU release and no user interaction is required. All a user needs to
|
||||
do is specify the kernel they want to boot with the ``-kernel`` option
|
||||
|
||||
* ``-bios none``
|
||||
|
||||
QEMU will not automatically load any firmware. It is up to the user to load all
|
||||
the images they need.
|
||||
|
||||
* ``-bios <file>``
|
||||
|
||||
Tells QEMU to load the specified file as the firmware.
|
||||
1. ``-bios default`` - This is the default behaviour if no -bios option
|
||||
is included. This option will load the default OpenSBI firmware automatically.
|
||||
The firmware is included with the QEMU release and no user interaction is
|
||||
required. All a user needs to do is specify the kernel they want to boot
|
||||
with the -kernel option
|
||||
2. ``-bios none`` - QEMU will not automatically load any firmware. It is up
|
||||
to the user to load all the images they need.
|
||||
3. ``-bios <file>`` - Tells QEMU to load the specified file as the firmware.
|
||||
|
||||
@@ -9,9 +9,6 @@ Synopsis
|
||||
Description
|
||||
-----------
|
||||
|
||||
NOTE: The 9p 'proxy' backend is deprecated (since QEMU 8.1) and will be
|
||||
removed, along with this daemon, in a future version of QEMU!
|
||||
|
||||
Pass-through security model in QEMU 9p server needs root privilege to do
|
||||
few file operations (like chown, chmod to any mode/uid:gid). There are two
|
||||
issues in pass-through security model:
|
||||
|
||||
@@ -1293,8 +1293,8 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr,
|
||||
|
||||
memcpy(buf + addr % page_size, hbuf, n);
|
||||
addr += n;
|
||||
if (addr % page_size == 0 || addr >= block->target_end) {
|
||||
/* we filled up the page or the current block is finished */
|
||||
if (addr % page_size == 0) {
|
||||
/* we filled up the page */
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1181,84 +1181,6 @@ static uint64_t partsN(float_to_uint)(FloatPartsN *p, FloatRoundMode rmode,
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like partsN(float_to_sint), except do not saturate the result.
|
||||
* Instead, return the rounded unbounded precision two's compliment result,
|
||||
* modulo 2**(bitsm1 + 1).
|
||||
*/
|
||||
static int64_t partsN(float_to_sint_modulo)(FloatPartsN *p,
|
||||
FloatRoundMode rmode,
|
||||
int bitsm1, float_status *s)
|
||||
{
|
||||
int flags = 0;
|
||||
uint64_t r;
|
||||
bool overflow = false;
|
||||
|
||||
switch (p->cls) {
|
||||
case float_class_snan:
|
||||
flags |= float_flag_invalid_snan;
|
||||
/* fall through */
|
||||
case float_class_qnan:
|
||||
flags |= float_flag_invalid;
|
||||
r = 0;
|
||||
break;
|
||||
|
||||
case float_class_inf:
|
||||
overflow = true;
|
||||
r = 0;
|
||||
break;
|
||||
|
||||
case float_class_zero:
|
||||
return 0;
|
||||
|
||||
case float_class_normal:
|
||||
/* TODO: N - 2 is frac_size for rounding; could use input fmt. */
|
||||
if (parts_round_to_int_normal(p, rmode, 0, N - 2)) {
|
||||
flags = float_flag_inexact;
|
||||
}
|
||||
|
||||
if (p->exp <= DECOMPOSED_BINARY_POINT) {
|
||||
/*
|
||||
* Because we rounded to integral, and exp < 64,
|
||||
* we know frac_low is zero.
|
||||
*/
|
||||
r = p->frac_hi >> (DECOMPOSED_BINARY_POINT - p->exp);
|
||||
if (p->exp < bitsm1) {
|
||||
/* Result in range. */
|
||||
} else if (p->exp == bitsm1) {
|
||||
/* The only in-range value is INT_MIN. */
|
||||
overflow = !p->sign || p->frac_hi != DECOMPOSED_IMPLICIT_BIT;
|
||||
} else {
|
||||
overflow = true;
|
||||
}
|
||||
} else {
|
||||
/* Overflow, but there might still be bits to return. */
|
||||
int shl = p->exp - DECOMPOSED_BINARY_POINT;
|
||||
if (shl < N) {
|
||||
frac_shl(p, shl);
|
||||
r = p->frac_hi;
|
||||
} else {
|
||||
r = 0;
|
||||
}
|
||||
overflow = true;
|
||||
}
|
||||
|
||||
if (p->sign) {
|
||||
r = -r;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (overflow) {
|
||||
flags = float_flag_invalid | float_flag_invalid_cvti;
|
||||
}
|
||||
float_raise(flags, s);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Integer to float conversions
|
||||
*
|
||||
|
||||
@@ -852,24 +852,11 @@ static uint64_t parts128_float_to_uint(FloatParts128 *p, FloatRoundMode rmode,
|
||||
#define parts_float_to_uint(P, R, Z, M, S) \
|
||||
PARTS_GENERIC_64_128(float_to_uint, P)(P, R, Z, M, S)
|
||||
|
||||
static int64_t parts64_float_to_sint_modulo(FloatParts64 *p,
|
||||
FloatRoundMode rmode,
|
||||
int bitsm1, float_status *s);
|
||||
static int64_t parts128_float_to_sint_modulo(FloatParts128 *p,
|
||||
FloatRoundMode rmode,
|
||||
int bitsm1, float_status *s);
|
||||
|
||||
#define parts_float_to_sint_modulo(P, R, M, S) \
|
||||
PARTS_GENERIC_64_128(float_to_sint_modulo, P)(P, R, M, S)
|
||||
|
||||
static void parts64_sint_to_float(FloatParts64 *p, int64_t a,
|
||||
int scale, float_status *s);
|
||||
static void parts128_sint_to_float(FloatParts128 *p, int64_t a,
|
||||
int scale, float_status *s);
|
||||
|
||||
#define parts_float_to_sint(P, R, Z, MN, MX, S) \
|
||||
PARTS_GENERIC_64_128(float_to_sint, P)(P, R, Z, MN, MX, S)
|
||||
|
||||
#define parts_sint_to_float(P, I, Z, S) \
|
||||
PARTS_GENERIC_64_128(sint_to_float, P)(P, I, Z, S)
|
||||
|
||||
@@ -3422,24 +3409,6 @@ int64_t bfloat16_to_int64_round_to_zero(bfloat16 a, float_status *s)
|
||||
return bfloat16_to_int64_scalbn(a, float_round_to_zero, 0, s);
|
||||
}
|
||||
|
||||
int32_t float64_to_int32_modulo(float64 a, FloatRoundMode rmode,
|
||||
float_status *s)
|
||||
{
|
||||
FloatParts64 p;
|
||||
|
||||
float64_unpack_canonical(&p, a, s);
|
||||
return parts_float_to_sint_modulo(&p, rmode, 31, s);
|
||||
}
|
||||
|
||||
int64_t float64_to_int64_modulo(float64 a, FloatRoundMode rmode,
|
||||
float_status *s)
|
||||
{
|
||||
FloatParts64 p;
|
||||
|
||||
float64_unpack_canonical(&p, a, s);
|
||||
return parts_float_to_sint_modulo(&p, rmode, 63, s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Floating-point to unsigned integer conversions
|
||||
*/
|
||||
|
||||
@@ -133,14 +133,6 @@ int qemu_fsdev_add(QemuOpts *opts, Error **errp)
|
||||
}
|
||||
|
||||
if (fsdriver) {
|
||||
if (strncmp(fsdriver, "proxy", 5) == 0) {
|
||||
warn_report(
|
||||
"'-fsdev proxy' and '-virtfs proxy' are deprecated, use "
|
||||
"'local' instead of 'proxy, or consider deploying virtiofsd "
|
||||
"as alternative to 9p"
|
||||
);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(FsDrivers); i++) {
|
||||
if (strcmp(FsDrivers[i].name, fsdriver) == 0) {
|
||||
break;
|
||||
|
||||
@@ -9,11 +9,6 @@
|
||||
* the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE: The 9p 'proxy' backend is deprecated (since QEMU 8.1) and will be
|
||||
* removed in a future version of QEMU!
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include <glib/gstdio.h>
|
||||
#include <sys/resource.h>
|
||||
@@ -1062,10 +1057,6 @@ int main(int argc, char **argv)
|
||||
struct statfs st_fs;
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "NOTE: The 9p 'proxy' backend is deprecated (since "
|
||||
"QEMU 8.1) and will be removed in a future version of "
|
||||
"QEMU!\n");
|
||||
|
||||
prog_name = g_path_get_basename(argv[0]);
|
||||
|
||||
is_daemon = true;
|
||||
|
||||
@@ -202,19 +202,16 @@ void gdb_memtox(GString *buf, const char *mem, int len)
|
||||
|
||||
static uint32_t gdb_get_cpu_pid(CPUState *cpu)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
return getpid();
|
||||
#else
|
||||
/* TODO: In user mode, we should use the task state PID */
|
||||
if (cpu->cluster_index == UNASSIGNED_CLUSTER_INDEX) {
|
||||
/* Return the default process' PID */
|
||||
int index = gdbserver_state.process_num - 1;
|
||||
return gdbserver_state.processes[index].pid;
|
||||
}
|
||||
return cpu->cluster_index + 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
GDBProcess *gdb_get_process(uint32_t pid)
|
||||
static GDBProcess *gdb_get_process(uint32_t pid)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -250,7 +247,7 @@ static CPUState *find_cpu(uint32_t thread_id)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CPUState *gdb_get_first_cpu_in_process(GDBProcess *process)
|
||||
static CPUState *get_first_cpu_in_process(GDBProcess *process)
|
||||
{
|
||||
CPUState *cpu;
|
||||
|
||||
@@ -328,7 +325,7 @@ static CPUState *gdb_get_cpu(uint32_t pid, uint32_t tid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return gdb_get_first_cpu_in_process(process);
|
||||
return get_first_cpu_in_process(process);
|
||||
} else {
|
||||
/* a specific thread */
|
||||
cpu = find_cpu(tid);
|
||||
@@ -357,7 +354,7 @@ static const char *get_feature_xml(const char *p, const char **newp,
|
||||
size_t len;
|
||||
int i;
|
||||
const char *name;
|
||||
CPUState *cpu = gdb_get_first_cpu_in_process(process);
|
||||
CPUState *cpu = get_first_cpu_in_process(process);
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
len = 0;
|
||||
@@ -493,7 +490,7 @@ void gdb_register_coprocessor(CPUState *cpu,
|
||||
|
||||
static void gdb_process_breakpoint_remove_all(GDBProcess *p)
|
||||
{
|
||||
CPUState *cpu = gdb_get_first_cpu_in_process(p);
|
||||
CPUState *cpu = get_first_cpu_in_process(p);
|
||||
|
||||
while (cpu) {
|
||||
gdb_breakpoint_remove_all(cpu);
|
||||
@@ -537,7 +534,7 @@ static GDBThreadIdKind read_thread_id(const char *buf, const char **end_buf,
|
||||
/* Skip '.' */
|
||||
buf++;
|
||||
} else {
|
||||
p = 0;
|
||||
p = 1;
|
||||
}
|
||||
|
||||
ret = qemu_strtoul(buf, &buf, 16, &t);
|
||||
@@ -576,6 +573,7 @@ static int gdb_handle_vcont(const char *p)
|
||||
{
|
||||
int res, signal = 0;
|
||||
char cur_action;
|
||||
char *newstates;
|
||||
unsigned long tmp;
|
||||
uint32_t pid, tid;
|
||||
GDBProcess *process;
|
||||
@@ -583,7 +581,7 @@ static int gdb_handle_vcont(const char *p)
|
||||
GDBThreadIdKind kind;
|
||||
unsigned int max_cpus = gdb_get_max_cpus();
|
||||
/* uninitialised CPUs stay 0 */
|
||||
g_autofree char *newstates = g_new0(char, max_cpus);
|
||||
newstates = g_new0(char, max_cpus);
|
||||
|
||||
/* mark valid CPUs with 1 */
|
||||
CPU_FOREACH(cpu) {
|
||||
@@ -599,7 +597,8 @@ static int gdb_handle_vcont(const char *p)
|
||||
res = 0;
|
||||
while (*p) {
|
||||
if (*p++ != ';') {
|
||||
return -ENOTSUP;
|
||||
res = -ENOTSUP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cur_action = *p++;
|
||||
@@ -607,12 +606,13 @@ static int gdb_handle_vcont(const char *p)
|
||||
cur_action = qemu_tolower(cur_action);
|
||||
res = qemu_strtoul(p, &p, 16, &tmp);
|
||||
if (res) {
|
||||
return res;
|
||||
goto out;
|
||||
}
|
||||
signal = gdb_signal_to_target(tmp);
|
||||
} else if (cur_action != 'c' && cur_action != 's') {
|
||||
/* unknown/invalid/unsupported command */
|
||||
return -ENOTSUP;
|
||||
res = -ENOTSUP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (*p == '\0' || *p == ';') {
|
||||
@@ -625,12 +625,14 @@ static int gdb_handle_vcont(const char *p)
|
||||
} else if (*p++ == ':') {
|
||||
kind = read_thread_id(p, &p, &pid, &tid);
|
||||
} else {
|
||||
return -ENOTSUP;
|
||||
res = -ENOTSUP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (kind) {
|
||||
case GDB_READ_THREAD_ERR:
|
||||
return -EINVAL;
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
|
||||
case GDB_ALL_PROCESSES:
|
||||
cpu = gdb_first_attached_cpu();
|
||||
@@ -647,10 +649,11 @@ static int gdb_handle_vcont(const char *p)
|
||||
process = gdb_get_process(pid);
|
||||
|
||||
if (!process->attached) {
|
||||
return -EINVAL;
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cpu = gdb_get_first_cpu_in_process(process);
|
||||
cpu = get_first_cpu_in_process(process);
|
||||
while (cpu) {
|
||||
if (newstates[cpu->cpu_index] == 1) {
|
||||
newstates[cpu->cpu_index] = cur_action;
|
||||
@@ -665,7 +668,8 @@ static int gdb_handle_vcont(const char *p)
|
||||
|
||||
/* invalid CPU/thread specified */
|
||||
if (!cpu) {
|
||||
return -EINVAL;
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* only use if no previous match occourred */
|
||||
@@ -675,9 +679,12 @@ static int gdb_handle_vcont(const char *p)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gdbserver_state.signal = signal;
|
||||
gdb_continue_partial(newstates);
|
||||
|
||||
out:
|
||||
g_free(newstates);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1273,7 +1280,7 @@ static void handle_v_attach(GArray *params, void *user_ctx)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cpu = gdb_get_first_cpu_in_process(process);
|
||||
cpu = get_first_cpu_in_process(process);
|
||||
if (!cpu) {
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -1327,36 +1334,6 @@ static const GdbCmdParseEntry gdb_v_commands_table[] = {
|
||||
.cmd = "Kill;",
|
||||
.cmd_startswith = 1
|
||||
},
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/*
|
||||
* Host I/O Packets. See [1] for details.
|
||||
* [1] https://sourceware.org/gdb/onlinedocs/gdb/Host-I_002fO-Packets.html
|
||||
*/
|
||||
{
|
||||
.handler = gdb_handle_v_file_open,
|
||||
.cmd = "File:open:",
|
||||
.cmd_startswith = 1,
|
||||
.schema = "s,L,L0"
|
||||
},
|
||||
{
|
||||
.handler = gdb_handle_v_file_close,
|
||||
.cmd = "File:close:",
|
||||
.cmd_startswith = 1,
|
||||
.schema = "l0"
|
||||
},
|
||||
{
|
||||
.handler = gdb_handle_v_file_pread,
|
||||
.cmd = "File:pread:",
|
||||
.cmd_startswith = 1,
|
||||
.schema = "l,L,L0"
|
||||
},
|
||||
{
|
||||
.handler = gdb_handle_v_file_readlink,
|
||||
.cmd = "File:readlink:",
|
||||
.cmd_startswith = 1,
|
||||
.schema = "s0"
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static void handle_v_commands(GArray *params, void *user_ctx)
|
||||
@@ -1426,7 +1403,7 @@ static void handle_query_curr_tid(GArray *params, void *user_ctx)
|
||||
* first thread).
|
||||
*/
|
||||
process = gdb_get_cpu_process(gdbserver_state.g_cpu);
|
||||
cpu = gdb_get_first_cpu_in_process(process);
|
||||
cpu = get_first_cpu_in_process(process);
|
||||
g_string_assign(gdbserver_state.str_buf, "QC");
|
||||
gdb_append_thread_id(cpu, gdbserver_state.str_buf);
|
||||
gdb_put_strbuf();
|
||||
@@ -1502,14 +1479,11 @@ static void handle_query_supported(GArray *params, void *user_ctx)
|
||||
";ReverseStep+;ReverseContinue+");
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#if defined(CONFIG_LINUX)
|
||||
#if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX)
|
||||
if (gdbserver_state.c_cpu->opaque) {
|
||||
g_string_append(gdbserver_state.str_buf, ";qXfer:auxv:read+");
|
||||
}
|
||||
#endif
|
||||
g_string_append(gdbserver_state.str_buf, ";qXfer:exec-file:read+");
|
||||
#endif
|
||||
|
||||
if (params->len &&
|
||||
strstr(get_param(params, 0)->data, "multiprocess+")) {
|
||||
@@ -1648,21 +1622,13 @@ static const GdbCmdParseEntry gdb_gen_query_table[] = {
|
||||
.cmd_startswith = 1,
|
||||
.schema = "s:l,l0"
|
||||
},
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
#if defined(CONFIG_LINUX)
|
||||
#if defined(CONFIG_USER_ONLY) && defined(CONFIG_LINUX)
|
||||
{
|
||||
.handler = gdb_handle_query_xfer_auxv,
|
||||
.cmd = "Xfer:auxv:read::",
|
||||
.cmd_startswith = 1,
|
||||
.schema = "l,l0"
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.handler = gdb_handle_query_xfer_exec_file,
|
||||
.cmd = "Xfer:exec-file:read:",
|
||||
.cmd_startswith = 1,
|
||||
.schema = "l:l,l0"
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.handler = gdb_handle_query_attached,
|
||||
@@ -1848,7 +1814,6 @@ static int gdb_handle_packet(const char *line_buf)
|
||||
.handler = handle_backward,
|
||||
.cmd = "b",
|
||||
.cmd_startswith = 1,
|
||||
.allow_stop_reply = true,
|
||||
.schema = "o0"
|
||||
};
|
||||
cmd_parser = &backward_cmd_desc;
|
||||
@@ -2051,18 +2016,8 @@ void gdb_read_byte(uint8_t ch)
|
||||
return;
|
||||
}
|
||||
if (runstate_is_running()) {
|
||||
/*
|
||||
* When the CPU is running, we cannot do anything except stop
|
||||
* it when receiving a char. This is expected on a Ctrl-C in the
|
||||
* gdb client. Because we are in all-stop mode, gdb sends a
|
||||
* 0x03 byte which is not a usual packet, so we handle it specially
|
||||
* here, but it does expect a stop reply.
|
||||
*/
|
||||
if (ch != 0x03) {
|
||||
trace_gdbstub_err_unexpected_runpkt(ch);
|
||||
} else {
|
||||
gdbserver_state.allow_stop_reply = true;
|
||||
}
|
||||
/* when the CPU is running, we cannot do anything except stop
|
||||
it when receiving a char */
|
||||
vm_stop(RUN_STATE_PAUSED);
|
||||
} else
|
||||
#endif
|
||||
@@ -2074,11 +2029,6 @@ void gdb_read_byte(uint8_t ch)
|
||||
gdbserver_state.line_buf_index = 0;
|
||||
gdbserver_state.line_sum = 0;
|
||||
gdbserver_state.state = RS_GETLINE;
|
||||
} else if (ch == '+') {
|
||||
/*
|
||||
* do nothing, gdb may preemptively send out ACKs on
|
||||
* initial connection
|
||||
*/
|
||||
} else {
|
||||
trace_gdbstub_err_garbage(ch);
|
||||
}
|
||||
@@ -2196,25 +2146,19 @@ void gdb_read_byte(uint8_t ch)
|
||||
void gdb_create_default_process(GDBState *s)
|
||||
{
|
||||
GDBProcess *process;
|
||||
int pid;
|
||||
int max_pid = 0;
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
assert(gdbserver_state.process_num == 0);
|
||||
pid = getpid();
|
||||
#else
|
||||
if (gdbserver_state.process_num) {
|
||||
pid = s->processes[s->process_num - 1].pid;
|
||||
} else {
|
||||
pid = 0;
|
||||
max_pid = s->processes[s->process_num - 1].pid;
|
||||
}
|
||||
/* We need an available PID slot for this process */
|
||||
assert(pid < UINT32_MAX);
|
||||
pid++;
|
||||
#endif
|
||||
|
||||
s->processes = g_renew(GDBProcess, s->processes, ++s->process_num);
|
||||
process = &s->processes[s->process_num - 1];
|
||||
process->pid = pid;
|
||||
|
||||
/* We need an available PID slot for this process */
|
||||
assert(max_pid < UINT32_MAX);
|
||||
|
||||
process->pid = max_pid + 1;
|
||||
process->attached = false;
|
||||
process->target_xml[0] = '\0';
|
||||
}
|
||||
|
||||
@@ -129,8 +129,6 @@ void gdb_read_byte(uint8_t ch);
|
||||
*/
|
||||
bool gdb_got_immediate_ack(void);
|
||||
/* utility helpers */
|
||||
GDBProcess *gdb_get_process(uint32_t pid);
|
||||
CPUState *gdb_get_first_cpu_in_process(GDBProcess *process);
|
||||
CPUState *gdb_first_attached_cpu(void);
|
||||
void gdb_append_thread_id(CPUState *cpu, GString *buf);
|
||||
int gdb_get_cpu_index(CPUState *cpu);
|
||||
@@ -189,11 +187,6 @@ typedef union GdbCmdVariant {
|
||||
void gdb_handle_query_rcmd(GArray *params, void *user_ctx); /* softmmu */
|
||||
void gdb_handle_query_offsets(GArray *params, void *user_ctx); /* user */
|
||||
void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx); /*user */
|
||||
void gdb_handle_v_file_open(GArray *params, void *user_ctx); /* user */
|
||||
void gdb_handle_v_file_close(GArray *params, void *user_ctx); /* user */
|
||||
void gdb_handle_v_file_pread(GArray *params, void *user_ctx); /* user */
|
||||
void gdb_handle_v_file_readlink(GArray *params, void *user_ctx); /* user */
|
||||
void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx); /* user */
|
||||
|
||||
void gdb_handle_query_attached(GArray *params, void *user_ctx); /* both */
|
||||
|
||||
|
||||
@@ -332,9 +332,11 @@ static void create_processes(GDBState *s)
|
||||
|
||||
int gdbserver_start(const char *device)
|
||||
{
|
||||
trace_gdbstub_op_start(device);
|
||||
|
||||
char gdbstub_device_name[128];
|
||||
Chardev *chr = NULL;
|
||||
Chardev *mon_chr;
|
||||
g_autoptr(GString) cs = g_string_new(device);
|
||||
|
||||
if (!first_cpu) {
|
||||
error_report("gdbstub: meaningless to attach gdb to a "
|
||||
@@ -348,16 +350,15 @@ int gdbserver_start(const char *device)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cs->len == 0) {
|
||||
if (!device) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
trace_gdbstub_op_start(cs->str);
|
||||
|
||||
if (g_strcmp0(cs->str, "none") != 0) {
|
||||
if (g_str_has_prefix(cs->str, "tcp:")) {
|
||||
if (strcmp(device, "none") != 0) {
|
||||
if (strstart(device, "tcp:", NULL)) {
|
||||
/* enforce required TCP attributes */
|
||||
g_string_append_printf(cs, ",wait=off,nodelay=on,server=on");
|
||||
snprintf(gdbstub_device_name, sizeof(gdbstub_device_name),
|
||||
"%s,wait=off,nodelay=on,server=on", device);
|
||||
device = gdbstub_device_name;
|
||||
}
|
||||
#ifndef _WIN32
|
||||
else if (strcmp(device, "stdio") == 0) {
|
||||
@@ -372,7 +373,7 @@ int gdbserver_start(const char *device)
|
||||
* FIXME: it's a bit weird to allow using a mux chardev here
|
||||
* and implicitly setup a monitor. We may want to break this.
|
||||
*/
|
||||
chr = qemu_chr_new_noreplay("gdb", cs->str, true, NULL);
|
||||
chr = qemu_chr_new_noreplay("gdb", device, true, NULL);
|
||||
if (!chr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ gdbstub_err_invalid_repeat(uint8_t ch) "got invalid RLE count: 0x%02x"
|
||||
gdbstub_err_invalid_rle(void) "got invalid RLE sequence"
|
||||
gdbstub_err_checksum_invalid(uint8_t ch) "got invalid command checksum digit: 0x%02x"
|
||||
gdbstub_err_checksum_incorrect(uint8_t expected, uint8_t got) "got command packet with incorrect checksum, expected=0x%02x, received=0x%02x"
|
||||
gdbstub_err_unexpected_runpkt(uint8_t ch) "unexpected packet (0x%02x) while target running"
|
||||
|
||||
# softmmu.c
|
||||
gdbstub_hit_watchpoint(const char *type, int cpu_gdb_index, uint64_t vaddr) "Watchpoint hit, type=\"%s\" cpu=%d, vaddr=0x%" PRIx64 ""
|
||||
|
||||
@@ -11,10 +11,6 @@
|
||||
#include "exec/gdbstub.h"
|
||||
#include "qemu.h"
|
||||
#include "internals.h"
|
||||
#ifdef CONFIG_LINUX
|
||||
#include "linux-user/loader.h"
|
||||
#include "linux-user/qemu.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Map target signal numbers to GDB protocol signal numbers and vice
|
||||
@@ -285,136 +281,3 @@ void gdb_handle_query_xfer_auxv(GArray *params, void *user_ctx)
|
||||
gdbserver_state.str_buf->len, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char *get_filename_param(GArray *params, int i)
|
||||
{
|
||||
const char *hex_filename = get_param(params, i)->data;
|
||||
gdb_hextomem(gdbserver_state.mem_buf, hex_filename,
|
||||
strlen(hex_filename) / 2);
|
||||
g_byte_array_append(gdbserver_state.mem_buf, (const guint8 *)"", 1);
|
||||
return (const char *)gdbserver_state.mem_buf->data;
|
||||
}
|
||||
|
||||
static void hostio_reply_with_data(const void *buf, size_t n)
|
||||
{
|
||||
g_string_printf(gdbserver_state.str_buf, "F%zx;", n);
|
||||
gdb_memtox(gdbserver_state.str_buf, buf, n);
|
||||
gdb_put_packet_binary(gdbserver_state.str_buf->str,
|
||||
gdbserver_state.str_buf->len, true);
|
||||
}
|
||||
|
||||
void gdb_handle_v_file_open(GArray *params, void *user_ctx)
|
||||
{
|
||||
const char *filename = get_filename_param(params, 0);
|
||||
uint64_t flags = get_param(params, 1)->val_ull;
|
||||
uint64_t mode = get_param(params, 2)->val_ull;
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
int fd = do_guest_openat(gdbserver_state.g_cpu->env_ptr, 0, filename,
|
||||
flags, mode, false);
|
||||
#else
|
||||
int fd = open(filename, flags, mode);
|
||||
#endif
|
||||
if (fd < 0) {
|
||||
g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
|
||||
} else {
|
||||
g_string_printf(gdbserver_state.str_buf, "F%d", fd);
|
||||
}
|
||||
gdb_put_strbuf();
|
||||
}
|
||||
|
||||
void gdb_handle_v_file_close(GArray *params, void *user_ctx)
|
||||
{
|
||||
int fd = get_param(params, 0)->val_ul;
|
||||
|
||||
if (close(fd) == -1) {
|
||||
g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
|
||||
gdb_put_strbuf();
|
||||
return;
|
||||
}
|
||||
|
||||
gdb_put_packet("F00");
|
||||
}
|
||||
|
||||
void gdb_handle_v_file_pread(GArray *params, void *user_ctx)
|
||||
{
|
||||
int fd = get_param(params, 0)->val_ul;
|
||||
size_t count = get_param(params, 1)->val_ull;
|
||||
off_t offset = get_param(params, 2)->val_ull;
|
||||
|
||||
size_t bufsiz = MIN(count, BUFSIZ);
|
||||
g_autofree char *buf = g_try_malloc(bufsiz);
|
||||
if (buf == NULL) {
|
||||
gdb_put_packet("E12");
|
||||
return;
|
||||
}
|
||||
|
||||
ssize_t n = pread(fd, buf, bufsiz, offset);
|
||||
if (n < 0) {
|
||||
g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
|
||||
gdb_put_strbuf();
|
||||
return;
|
||||
}
|
||||
hostio_reply_with_data(buf, n);
|
||||
}
|
||||
|
||||
void gdb_handle_v_file_readlink(GArray *params, void *user_ctx)
|
||||
{
|
||||
const char *filename = get_filename_param(params, 0);
|
||||
|
||||
g_autofree char *buf = g_try_malloc(BUFSIZ);
|
||||
if (buf == NULL) {
|
||||
gdb_put_packet("E12");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
ssize_t n = do_guest_readlink(filename, buf, BUFSIZ);
|
||||
#else
|
||||
ssize_t n = readlink(filename, buf, BUFSIZ);
|
||||
#endif
|
||||
if (n < 0) {
|
||||
g_string_printf(gdbserver_state.str_buf, "F-1,%d", errno);
|
||||
gdb_put_strbuf();
|
||||
return;
|
||||
}
|
||||
hostio_reply_with_data(buf, n);
|
||||
}
|
||||
|
||||
void gdb_handle_query_xfer_exec_file(GArray *params, void *user_ctx)
|
||||
{
|
||||
uint32_t pid = get_param(params, 0)->val_ul;
|
||||
uint32_t offset = get_param(params, 1)->val_ul;
|
||||
uint32_t length = get_param(params, 2)->val_ul;
|
||||
|
||||
GDBProcess *process = gdb_get_process(pid);
|
||||
if (!process) {
|
||||
gdb_put_packet("E00");
|
||||
return;
|
||||
}
|
||||
|
||||
CPUState *cpu = gdb_get_first_cpu_in_process(process);
|
||||
if (!cpu) {
|
||||
gdb_put_packet("E00");
|
||||
return;
|
||||
}
|
||||
|
||||
TaskState *ts = cpu->opaque;
|
||||
if (!ts || !ts->bprm || !ts->bprm->filename) {
|
||||
gdb_put_packet("E00");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t total_length = strlen(ts->bprm->filename);
|
||||
if (offset > total_length) {
|
||||
gdb_put_packet("E00");
|
||||
return;
|
||||
}
|
||||
if (offset + length > total_length) {
|
||||
length = total_length - offset;
|
||||
}
|
||||
|
||||
g_string_printf(gdbserver_state.str_buf, "l%.*s", length,
|
||||
ts->bprm->filename + offset);
|
||||
gdb_put_strbuf();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Host specific cpu identification for AArch64.
|
||||
* Host specific cpu indentification for AArch64.
|
||||
*/
|
||||
|
||||
#ifndef HOST_CPUINFO_H
|
||||
@@ -9,7 +9,6 @@
|
||||
#define CPUINFO_ALWAYS (1u << 0) /* so cpuinfo is nonzero */
|
||||
#define CPUINFO_LSE (1u << 1)
|
||||
#define CPUINFO_LSE2 (1u << 2)
|
||||
#define CPUINFO_AES (1u << 3)
|
||||
|
||||
/* Initialized with a constructor. */
|
||||
extern unsigned cpuinfo;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user