aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-01-19 15:47:23 +0000
committerPeter Maydell <peter.maydell@linaro.org>2021-01-19 15:47:23 +0000
commit48202c712412c803ddb56365c7bca322aa4e7506 (patch)
treed619d954218fd9e75a193d1372e5c34dffe5ae72
parentf1fcb6851aba6dd9838886dc179717a11e344a1c (diff)
parentb93f4fbdc48283a39089469c44a5529d79dc40a8 (diff)
downloadqemu-48202c712412c803ddb56365c7bca322aa4e7506.zip
qemu-48202c712412c803ddb56365c7bca322aa4e7506.tar.gz
qemu-48202c712412c803ddb56365c7bca322aa4e7506.tar.bz2
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210119-1' into staging
target-arm queue: * Implement IMPDEF pauth algorithm * Support ARMv8.4-SEL2 * Fix bug where we were truncating predicate vector lengths in SVE insns * npcm7xx_adc-test: Fix memleak in adc_qom_set * target/arm/m_helper: Silence GCC 10 maybe-uninitialized error * docs: Build and install all the docs in a single manual # gpg: Signature made Tue 19 Jan 2021 15:46:34 GMT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20210119-1: (29 commits) docs: Build and install all the docs in a single manual target/arm/m_helper: Silence GCC 10 maybe-uninitialized error npcm7xx_adc-test: Fix memleak in adc_qom_set target/arm: Update REV, PUNPK for pred_desc target/arm: Update ZIP, UZP, TRN for pred_desc target/arm: Update PFIRST, PNEXT for pred_desc target/arm: Introduce PREDDESC field definitions target/arm: refactor vae1_tlbmask() target/arm: enable Secure EL2 in max CPU target/arm: Implement SCR_EL2.EEL2 target/arm: revector to run-time pick target EL target/arm: set HPFAR_EL2.NS on secure stage 2 faults target/arm: secure stage 2 translation regime target/arm: generalize 2-stage page-walk condition target/arm: translate NS bit in page-walks target/arm: do S1_ptw_translate() before address space lookup target/arm: handle VMID change in secure state target/arm: add ARMv8.4-SEL2 system registers target/arm: add MMU stage 1 for Secure EL2 target/arm: add 64-bit S-EL2 to EL exception table ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--.gitlab-ci.yml4
-rw-r--r--docs/conf.py46
-rw-r--r--docs/devel/conf.py15
-rw-r--r--docs/index.html.in17
-rw-r--r--docs/interop/conf.py28
-rw-r--r--docs/meson.build64
-rw-r--r--docs/specs/conf.py16
-rw-r--r--docs/system/arm/cpu-features.rst21
-rw-r--r--docs/system/conf.py28
-rw-r--r--docs/tools/conf.py37
-rw-r--r--docs/user/conf.py15
-rw-r--r--include/qemu/xxhash.h98
-rw-r--r--target/arm/cpu-param.h2
-rw-r--r--target/arm/cpu.c23
-rw-r--r--target/arm/cpu.h109
-rw-r--r--target/arm/cpu64.c65
-rw-r--r--target/arm/helper-a64.c8
-rw-r--r--target/arm/helper.c414
-rw-r--r--target/arm/internals.h45
-rw-r--r--target/arm/m_helper.c2
-rw-r--r--target/arm/monitor.c1
-rw-r--r--target/arm/op_helper.c4
-rw-r--r--target/arm/pauth_helper.c27
-rw-r--r--target/arm/sve_helper.c33
-rw-r--r--target/arm/tlb_helper.c3
-rw-r--r--target/arm/translate-a64.c4
-rw-r--r--target/arm/translate-sve.c31
-rw-r--r--target/arm/translate.c36
-rw-r--r--tests/qtest/arm-cpu-features.c13
-rw-r--r--tests/qtest/npcm7xx_adc-test.c1
30 files changed, 771 insertions, 439 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index fd0162a..203b167 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -622,8 +622,8 @@ pages:
-t "Welcome to the QEMU sourcecode"
- mv HTML public/src
# Project documentation
- - mv build/docs/index.html public/
- - for i in devel interop specs system tools user ; do mv build/docs/$i public/ ; done
+ - make -C build install DESTDIR=$(pwd)/temp-install
+ - mv temp-install/usr/local/share/doc/qemu/* public/
artifacts:
paths:
- public
diff --git a/docs/conf.py b/docs/conf.py
index d40d8ff..2ee6111 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -224,7 +224,51 @@ latex_documents = [
# -- Options for manual page output ---------------------------------------
# Individual manual/conf.py can override this to create man pages
-man_pages = []
+man_pages = [
+ ('interop/qemu-ga', 'qemu-ga',
+ 'QEMU Guest Agent',
+ ['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
+ ('interop/qemu-ga-ref', 'qemu-ga-ref',
+ 'QEMU Guest Agent Protocol Reference',
+ [], 7),
+ ('interop/qemu-qmp-ref', 'qemu-qmp-ref',
+ 'QEMU QMP Reference Manual',
+ [], 7),
+ ('interop/qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref',
+ 'QEMU Storage Daemon QMP Reference Manual',
+ [], 7),
+ ('system/qemu-manpage', 'qemu',
+ 'QEMU User Documentation',
+ ['Fabrice Bellard'], 1),
+ ('system/qemu-block-drivers', 'qemu-block-drivers',
+ 'QEMU block drivers reference',
+ ['Fabrice Bellard and the QEMU Project developers'], 7),
+ ('system/qemu-cpu-models', 'qemu-cpu-models',
+ 'QEMU CPU Models',
+ ['The QEMU Project developers'], 7),
+ ('tools/qemu-img', 'qemu-img',
+ 'QEMU disk image utility',
+ ['Fabrice Bellard'], 1),
+ ('tools/qemu-nbd', 'qemu-nbd',
+ 'QEMU Disk Network Block Device Server',
+ ['Anthony Liguori <anthony@codemonkey.ws>'], 8),
+ ('tools/qemu-pr-helper', 'qemu-pr-helper',
+ 'QEMU persistent reservation helper',
+ [], 8),
+ ('tools/qemu-storage-daemon', 'qemu-storage-daemon',
+ 'QEMU storage daemon',
+ [], 1),
+ ('tools/qemu-trace-stap', 'qemu-trace-stap',
+ 'QEMU SystemTap trace tool',
+ [], 1),
+ ('tools/virtfs-proxy-helper', 'virtfs-proxy-helper',
+ 'QEMU 9p virtfs proxy filesystem helper',
+ ['M. Mohan Kumar'], 1),
+ ('tools/virtiofsd', 'virtiofsd',
+ 'QEMU virtio-fs shared file system daemon',
+ ['Stefan Hajnoczi <stefanha@redhat.com>',
+ 'Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>'], 1),
+]
# -- Options for Texinfo output -------------------------------------------
diff --git a/docs/devel/conf.py b/docs/devel/conf.py
deleted file mode 100644
index 7441f87..0000000
--- a/docs/devel/conf.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# QEMU documentation build configuration file for the 'devel' manual.
-#
-# This includes the top level conf file and then makes any necessary tweaks.
-import sys
-import os
-
-qemu_docdir = os.path.abspath("..")
-parent_config = os.path.join(qemu_docdir, "conf.py")
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
-
-# This slightly misuses the 'description', but is the best way to get
-# the manual title to appear in the sidebar.
-html_theme_options['description'] = u'Developer''s Guide'
diff --git a/docs/index.html.in b/docs/index.html.in
deleted file mode 100644
index 33db439..0000000
--- a/docs/index.html.in
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>QEMU @VERSION@ Documentation</title>
- </head>
- <body>
- <h1>QEMU @VERSION@ Documentation</h1>
- <ul>
- <li><a href="system/index.html">System Emulation User's Guide</a></li>
- <li><a href="user/index.html">User Mode Emulation User's Guide</a></li>
- <li><a href="tools/index.html">Tools Guide</a></li>
- <li><a href="interop/index.html">System Emulation Management and Interoperability Guide</a></li>
- <li><a href="specs/index.html">System Emulation Guest Hardware Specifications</a></li>
- </ul>
- </body>
-</html>
diff --git a/docs/interop/conf.py b/docs/interop/conf.py
deleted file mode 100644
index f4370aa..0000000
--- a/docs/interop/conf.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# QEMU documentation build configuration file for the 'interop' manual.
-#
-# This includes the top level conf file and then makes any necessary tweaks.
-import sys
-import os
-
-qemu_docdir = os.path.abspath("..")
-parent_config = os.path.join(qemu_docdir, "conf.py")
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
-
-# This slightly misuses the 'description', but is the best way to get
-# the manual title to appear in the sidebar.
-html_theme_options['description'] = u'System Emulation Management and Interoperability Guide'
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
- ('qemu-ga', 'qemu-ga', u'QEMU Guest Agent',
- ['Michael Roth <mdroth@linux.vnet.ibm.com>'], 8),
- ('qemu-ga-ref', 'qemu-ga-ref', 'QEMU Guest Agent Protocol Reference',
- [], 7),
- ('qemu-qmp-ref', 'qemu-qmp-ref', 'QEMU QMP Reference Manual',
- [], 7),
- ('qemu-storage-daemon-qmp-ref', 'qemu-storage-daemon-qmp-ref',
- 'QEMU Storage Daemon QMP Reference Manual', [], 7),
-]
diff --git a/docs/meson.build b/docs/meson.build
index fae9849..bb14eae 100644
--- a/docs/meson.build
+++ b/docs/meson.build
@@ -46,19 +46,11 @@ if build_docs
meson.source_root() / 'docs/sphinx/qmp_lexer.py',
qapi_gen_depends ]
- configure_file(output: 'index.html',
- input: files('index.html.in'),
- configuration: {'VERSION': meson.project_version()},
- install_dir: qemu_docdir)
- manuals = [ 'devel', 'interop', 'tools', 'specs', 'system', 'user' ]
man_pages = {
- 'interop' : {
'qemu-ga.8': (have_tools ? 'man8' : ''),
'qemu-ga-ref.7': 'man7',
'qemu-qmp-ref.7': 'man7',
'qemu-storage-daemon-qmp-ref.7': (have_tools ? 'man7' : ''),
- },
- 'tools': {
'qemu-img.1': (have_tools ? 'man1' : ''),
'qemu-nbd.8': (have_tools ? 'man8' : ''),
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
@@ -66,53 +58,47 @@ if build_docs
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
- },
- 'system': {
'qemu.1': 'man1',
'qemu-block-drivers.7': 'man7',
'qemu-cpu-models.7': 'man7'
- },
}
sphinxdocs = []
sphinxmans = []
- foreach manual : manuals
- private_dir = meson.current_build_dir() / (manual + '.p')
- output_dir = meson.current_build_dir() / manual
- input_dir = meson.current_source_dir() / manual
- this_manual = custom_target(manual + ' manual',
+ private_dir = meson.current_build_dir() / 'manual.p'
+ output_dir = meson.current_build_dir() / 'manual'
+ input_dir = meson.current_source_dir()
+
+ this_manual = custom_target('QEMU manual',
build_by_default: build_docs,
- output: [manual + '.stamp'],
- input: [files('conf.py'), files(manual / 'conf.py')],
- depfile: manual + '.d',
+ output: 'docs.stamp',
+ input: files('conf.py'),
+ depfile: 'docs.d',
depend_files: sphinx_extn_depends,
command: [SPHINX_ARGS, '-Ddepfile=@DEPFILE@',
'-Ddepfile_stamp=@OUTPUT0@',
'-b', 'html', '-d', private_dir,
input_dir, output_dir])
- sphinxdocs += this_manual
- if build_docs and manual != 'devel'
- install_subdir(output_dir, install_dir: qemu_docdir)
- endif
+ sphinxdocs += this_manual
+ install_subdir(output_dir, install_dir: qemu_docdir, strip_directory: true)
- these_man_pages = []
- install_dirs = []
- foreach page, section : man_pages.get(manual, {})
- these_man_pages += page
- install_dirs += section == '' ? false : get_option('mandir') / section
- endforeach
- if these_man_pages.length() > 0
- sphinxmans += custom_target(manual + ' man pages',
- build_by_default: build_docs,
- output: these_man_pages,
- input: this_manual,
- install: build_docs,
- install_dir: install_dirs,
- command: [SPHINX_ARGS, '-b', 'man', '-d', private_dir,
- input_dir, meson.current_build_dir()])
- endif
+ these_man_pages = []
+ install_dirs = []
+ foreach page, section : man_pages
+ these_man_pages += page
+ install_dirs += section == '' ? false : get_option('mandir') / section
endforeach
+
+ sphinxmans += custom_target('QEMU man pages',
+ build_by_default: build_docs,
+ output: these_man_pages,
+ input: this_manual,
+ install: build_docs,
+ install_dir: install_dirs,
+ command: [SPHINX_ARGS, '-b', 'man', '-d', private_dir,
+ input_dir, meson.current_build_dir()])
+
alias_target('sphinxdocs', sphinxdocs)
alias_target('html', sphinxdocs)
alias_target('man', sphinxmans)
diff --git a/docs/specs/conf.py b/docs/specs/conf.py
deleted file mode 100644
index 4d56f3a..0000000
--- a/docs/specs/conf.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# QEMU documentation build configuration file for the 'specs' manual.
-#
-# This includes the top level conf file and then makes any necessary tweaks.
-import sys
-import os
-
-qemu_docdir = os.path.abspath("..")
-parent_config = os.path.join(qemu_docdir, "conf.py")
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
-
-# This slightly misuses the 'description', but is the best way to get
-# the manual title to appear in the sidebar.
-html_theme_options['description'] = \
- u'System Emulation Guest Hardware Specifications'
diff --git a/docs/system/arm/cpu-features.rst b/docs/system/arm/cpu-features.rst
index 35196a6..c455442 100644
--- a/docs/system/arm/cpu-features.rst
+++ b/docs/system/arm/cpu-features.rst
@@ -211,6 +211,27 @@ the list of KVM VCPU features and their descriptions.
influence the guest scheduler behavior and/or be
exposed to the guest userspace.
+TCG VCPU Features
+=================
+
+TCG VCPU features are CPU features that are specific to TCG.
+Below is the list of TCG VCPU features and their descriptions.
+
+ pauth Enable or disable `FEAT_Pauth`, pointer
+ authentication. By default, the feature is
+ enabled with `-cpu max`.
+
+ pauth-impdef When `FEAT_Pauth` is enabled, either the
+ *impdef* (Implementation Defined) algorithm
+ is enabled or the *architected* QARMA algorithm
+ is enabled. By default the impdef algorithm
+ is disabled, and QARMA is enabled.
+
+ The architected QARMA algorithm has good
+ cryptographic properties, but can be quite slow
+ to emulate. The impdef algorithm used by QEMU
+ is non-cryptographic but significantly faster.
+
SVE CPU Properties
==================
diff --git a/docs/system/conf.py b/docs/system/conf.py
deleted file mode 100644
index 6251849..0000000
--- a/docs/system/conf.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# QEMU documentation build configuration file for the 'system' manual.
-#
-# This includes the top level conf file and then makes any necessary tweaks.
-import sys
-import os
-
-qemu_docdir = os.path.abspath("..")
-parent_config = os.path.join(qemu_docdir, "conf.py")
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
-
-# This slightly misuses the 'description', but is the best way to get
-# the manual title to appear in the sidebar.
-html_theme_options['description'] = u'System Emulation User''s Guide'
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
- ('qemu-manpage', 'qemu', u'QEMU User Documentation',
- ['Fabrice Bellard'], 1),
- ('qemu-block-drivers', 'qemu-block-drivers',
- u'QEMU block drivers reference',
- ['Fabrice Bellard and the QEMU Project developers'], 7),
- ('qemu-cpu-models', 'qemu-cpu-models',
- u'QEMU CPU Models',
- ['The QEMU Project developers'], 7)
-]
diff --git a/docs/tools/conf.py b/docs/tools/conf.py
deleted file mode 100644
index 7072d99..0000000
--- a/docs/tools/conf.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# QEMU documentation build configuration file for the 'tools' manual.
-#
-# This includes the top level conf file and then makes any necessary tweaks.
-import sys
-import os
-
-qemu_docdir = os.path.abspath("..")
-parent_config = os.path.join(qemu_docdir, "conf.py")
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
-
-# This slightly misuses the 'description', but is the best way to get
-# the manual title to appear in the sidebar.
-html_theme_options['description'] = \
- u'Tools Guide'
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
- ('qemu-img', 'qemu-img', u'QEMU disk image utility',
- ['Fabrice Bellard'], 1),
- ('qemu-storage-daemon', 'qemu-storage-daemon', u'QEMU storage daemon',
- [], 1),
- ('qemu-nbd', 'qemu-nbd', u'QEMU Disk Network Block Device Server',
- ['Anthony Liguori <anthony@codemonkey.ws>'], 8),
- ('qemu-pr-helper', 'qemu-pr-helper', 'QEMU persistent reservation helper',
- [], 8),
- ('qemu-trace-stap', 'qemu-trace-stap', u'QEMU SystemTap trace tool',
- [], 1),
- ('virtfs-proxy-helper', 'virtfs-proxy-helper',
- u'QEMU 9p virtfs proxy filesystem helper',
- ['M. Mohan Kumar'], 1),
- ('virtiofsd', 'virtiofsd', u'QEMU virtio-fs shared file system daemon',
- ['Stefan Hajnoczi <stefanha@redhat.com>',
- 'Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>'], 1),
-]
diff --git a/docs/user/conf.py b/docs/user/conf.py
deleted file mode 100644
index 4b09aed..0000000
--- a/docs/user/conf.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# QEMU documentation build configuration file for the 'user' manual.
-#
-# This includes the top level conf file and then makes any necessary tweaks.
-import sys
-import os
-
-qemu_docdir = os.path.abspath("..")
-parent_config = os.path.join(qemu_docdir, "conf.py")
-exec(compile(open(parent_config, "rb").read(), parent_config, 'exec'))
-
-# This slightly misuses the 'description', but is the best way to get
-# the manual title to appear in the sidebar.
-html_theme_options['description'] = u'User Mode Emulation User''s Guide'
diff --git a/include/qemu/xxhash.h b/include/qemu/xxhash.h
index 076f1f6..c2dccca 100644
--- a/include/qemu/xxhash.h
+++ b/include/qemu/xxhash.h
@@ -119,4 +119,102 @@ static inline uint32_t qemu_xxhash6(uint64_t ab, uint64_t cd, uint32_t e,
return qemu_xxhash7(ab, cd, e, f, 0);
}
+/*
+ * Component parts of the XXH64 algorithm from
+ * https://github.com/Cyan4973/xxHash/blob/v0.8.0/xxhash.h
+ *
+ * The complete algorithm looks like
+ *
+ * i = 0;
+ * if (len >= 32) {
+ * v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2;
+ * v2 = seed + XXH_PRIME64_2;
+ * v3 = seed + 0;
+ * v4 = seed - XXH_PRIME64_1;
+ * do {
+ * v1 = XXH64_round(v1, get64bits(input + i));
+ * v2 = XXH64_round(v2, get64bits(input + i + 8));
+ * v3 = XXH64_round(v3, get64bits(input + i + 16));
+ * v4 = XXH64_round(v4, get64bits(input + i + 24));
+ * } while ((i += 32) <= len);
+ * h64 = XXH64_mergerounds(v1, v2, v3, v4);
+ * } else {
+ * h64 = seed + XXH_PRIME64_5;
+ * }
+ * h64 += len;
+ *
+ * for (; i + 8 <= len; i += 8) {
+ * h64 ^= XXH64_round(0, get64bits(input + i));
+ * h64 = rol64(h64, 27) * XXH_PRIME64_1 + XXH_PRIME64_4;
+ * }
+ * for (; i + 4 <= len; i += 4) {
+ * h64 ^= get32bits(input + i) * PRIME64_1;
+ * h64 = rol64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
+ * }
+ * for (; i < len; i += 1) {
+ * h64 ^= get8bits(input + i) * XXH_PRIME64_5;
+ * h64 = rol64(h64, 11) * XXH_PRIME64_1;
+ * }
+ *
+ * return XXH64_avalanche(h64)
+ *
+ * Exposing the pieces instead allows for simplified usage when
+ * the length is a known constant and the inputs are in registers.
+ */
+#define XXH_PRIME64_1 0x9E3779B185EBCA87ULL
+#define XXH_PRIME64_2 0xC2B2AE3D27D4EB4FULL
+#define XXH_PRIME64_3 0x165667B19E3779F9ULL
+#define XXH_PRIME64_4 0x85EBCA77C2B2AE63ULL
+#define XXH_PRIME64_5 0x27D4EB2F165667C5ULL
+
+static inline uint64_t XXH64_round(uint64_t acc, uint64_t input)
+{
+ return rol64(acc + input * XXH_PRIME64_2, 31) * XXH_PRIME64_1;
+}
+
+static inline uint64_t XXH64_mergeround(uint64_t acc, uint64_t val)
+{
+ return (acc ^ XXH64_round(0, val)) * XXH_PRIME64_1 + XXH_PRIME64_4;
+}
+
+static inline uint64_t XXH64_mergerounds(uint64_t v1, uint64_t v2,
+ uint64_t v3, uint64_t v4)
+{
+ uint64_t h64;
+
+ h64 = rol64(v1, 1) + rol64(v2, 7) + rol64(v3, 12) + rol64(v4, 18);
+ h64 = XXH64_mergeround(h64, v1);
+ h64 = XXH64_mergeround(h64, v2);
+ h64 = XXH64_mergeround(h64, v3);
+ h64 = XXH64_mergeround(h64, v4);
+
+ return h64;
+}
+
+static inline uint64_t XXH64_avalanche(uint64_t h64)
+{
+ h64 ^= h64 >> 33;
+ h64 *= XXH_PRIME64_2;
+ h64 ^= h64 >> 29;
+ h64 *= XXH_PRIME64_3;
+ h64 ^= h64 >> 32;
+ return h64;
+}
+
+static inline uint64_t qemu_xxhash64_4(uint64_t a, uint64_t b,
+ uint64_t c, uint64_t d)
+{
+ uint64_t v1 = QEMU_XXHASH_SEED + XXH_PRIME64_1 + XXH_PRIME64_2;
+ uint64_t v2 = QEMU_XXHASH_SEED + XXH_PRIME64_2;
+ uint64_t v3 = QEMU_XXHASH_SEED + 0;
+ uint64_t v4 = QEMU_XXHASH_SEED - XXH_PRIME64_1;
+
+ v1 = XXH64_round(v1, a);
+ v2 = XXH64_round(v2, b);
+ v3 = XXH64_round(v3, c);
+ v4 = XXH64_round(v4, d);
+
+ return XXH64_avalanche(XXH64_mergerounds(v1, v2, v3, v4));
+}
+
#endif /* QEMU_XXHASH_H */
diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h
index 6321385..00e7d9e 100644
--- a/target/arm/cpu-param.h
+++ b/target/arm/cpu-param.h
@@ -29,6 +29,6 @@
# define TARGET_PAGE_BITS_MIN 10
#endif
-#define NB_MMU_MODES 11
+#define NB_MMU_MODES 15
#endif
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 8387e94..40142ac 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -451,14 +451,14 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
break;
case EXCP_VFIQ:
- if (secure || !(hcr_el2 & HCR_FMO) || (hcr_el2 & HCR_TGE)) {
- /* VFIQs are only taken when hypervized and non-secure. */
+ if (!(hcr_el2 & HCR_FMO) || (hcr_el2 & HCR_TGE)) {
+ /* VFIQs are only taken when hypervized. */
return false;
}
return !(env->daif & PSTATE_F);
case EXCP_VIRQ:
- if (secure || !(hcr_el2 & HCR_IMO) || (hcr_el2 & HCR_TGE)) {
- /* VIRQs are only taken when hypervized and non-secure. */
+ if (!(hcr_el2 & HCR_IMO) || (hcr_el2 & HCR_TGE)) {
+ /* VIRQs are only taken when hypervized. */
return false;
}
return !(env->daif & PSTATE_I);
@@ -480,7 +480,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx,
* masked from Secure state. The HCR and SCR settings
* don't affect the masking logic, only the interrupt routing.
*/
- if (target_el == 3 || !secure) {
+ if (target_el == 3 || !secure || (env->cp15.scr_el3 & SCR_EEL2)) {
unmasked = true;
}
} else {
@@ -1320,6 +1320,19 @@ void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp)
error_propagate(errp, local_err);
return;
}
+
+ /*
+ * KVM does not support modifications to this feature.
+ * We have not registered the cpu properties when KVM
+ * is in use, so the user will not be able to set them.
+ */
+ if (!kvm_enabled()) {
+ arm_cpu_pauth_finalize(cpu, &local_err);
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ }
}
if (kvm_enabled()) {
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 84cc2de..df0d677 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -168,6 +168,11 @@ typedef struct {
uint32_t base_mask;
} TCR;
+#define VTCR_NSW (1u << 29)
+#define VTCR_NSA (1u << 30)
+#define VSTCR_SW VTCR_NSW
+#define VSTCR_SA VTCR_NSA
+
/* Define a maximum sized vector register.
* For 32-bit, this is a 128-bit NEON/AdvSIMD register.
* For 64-bit, this is a 2048-bit SVE register.
@@ -197,9 +202,11 @@ typedef struct {
#ifdef TARGET_AARCH64
# define ARM_MAX_VQ 16
void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp);
+void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp);
#else
# define ARM_MAX_VQ 1
static inline void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) { }
+static inline void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp) { }
#endif
typedef struct ARMVectorReg {
@@ -323,9 +330,11 @@ typedef struct CPUARMState {
uint64_t ttbr1_el[4];
};
uint64_t vttbr_el2; /* Virtualization Translation Table Base. */
+ uint64_t vsttbr_el2; /* Secure Virtualization Translation Table. */
/* MMU translation table base control. */
TCR tcr_el[4];
TCR vtcr_el2; /* Virtualization Translation Control. */
+ TCR vstcr_el2; /* Secure Virtualization Translation Control. */
uint32_t c2_data; /* MPU data cacheable bits. */
uint32_t c2_insn; /* MPU instruction cacheable bits. */
union { /* MMU domain access control register
@@ -947,6 +956,14 @@ struct ARMCPU {
uint64_t reset_cbar;
uint32_t reset_auxcr;
bool reset_hivecs;
+
+ /*
+ * Intermediate values used during property parsing.
+ * Once finalized, the values should be read from ID_AA64ISAR1.
+ */
+ bool prop_pauth;
+ bool prop_pauth_impdef;
+
/* DCZ blocksize, in log_2(words), ie low 4 bits of DCZID_EL0 */
uint32_t dcz_blocksize;
uint64_t rvbar;
@@ -1467,6 +1484,8 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask)
#define HCR_TWEDEN (1ULL << 59)
#define HCR_TWEDEL MAKE_64BIT_MASK(60, 4)
+#define HPFAR_NS (1ULL << 63)
+
#define SCR_NS (1U << 0)
#define SCR_IRQ (1U << 1)
#define SCR_FIQ (1U << 2)
@@ -2138,6 +2157,21 @@ static inline bool arm_is_secure(CPUARMState *env)
return arm_is_secure_below_el3(env);
}
+/*
+ * Return true if the current security state has AArch64 EL2 or AArch32 Hyp.
+ * This corresponds to the pseudocode EL2Enabled()
+ */
+static inline bool arm_is_el2_enabled(CPUARMState *env)
+{
+ if (arm_feature(env, ARM_FEATURE_EL2)) {
+ if (arm_is_secure_below_el3(env)) {
+ return (env->cp15.scr_el3 & SCR_EEL2) != 0;
+ }
+ return true;
+ }
+ return false;
+}
+
#else
static inline bool arm_is_secure_below_el3(CPUARMState *env)
{
@@ -2148,6 +2182,11 @@ static inline bool arm_is_secure(CPUARMState *env)
{
return false;
}
+
+static inline bool arm_is_el2_enabled(CPUARMState *env)
+{
+ return false;
+}
#endif
/**
@@ -2175,7 +2214,8 @@ static inline bool arm_el_is_aa64(CPUARMState *env, int el)
return aa64;
}
- if (arm_feature(env, ARM_FEATURE_EL3)) {
+ if (arm_feature(env, ARM_FEATURE_EL3) &&
+ ((env->cp15.scr_el3 & SCR_NS) || !(env->cp15.scr_el3 & SCR_EEL2))) {
aa64 = aa64 && (env->cp15.scr_el3 & SCR_RW);
}
@@ -2183,7 +2223,7 @@ static inline bool arm_el_is_aa64(CPUARMState *env, int el)
return aa64;
}
- if (arm_feature(env, ARM_FEATURE_EL2) && !arm_is_secure_below_el3(env)) {
+ if (arm_is_el2_enabled(env)) {
aa64 = aa64 && (env->cp15.hcr_el2 & HCR_RW);
}
@@ -3022,6 +3062,9 @@ bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync);
#define ARM_MMU_IDX_NOTLB 0x20 /* does not have a TLB */
#define ARM_MMU_IDX_M 0x40 /* M profile */
+/* Meanings of the bits for A profile mmu idx values */
+#define ARM_MMU_IDX_A_NS 0x8
+
/* Meanings of the bits for M profile mmu idx values */
#define ARM_MMU_IDX_M_PRIV 0x1
#define ARM_MMU_IDX_M_NEGPRI 0x2
@@ -3035,20 +3078,22 @@ typedef enum ARMMMUIdx {
/*
* A-profile.
*/
- ARMMMUIdx_E10_0 = 0 | ARM_MMU_IDX_A,
- ARMMMUIdx_E20_0 = 1 | ARM_MMU_IDX_A,
-
- ARMMMUIdx_E10_1 = 2 | ARM_MMU_IDX_A,
- ARMMMUIdx_E10_1_PAN = 3 | ARM_MMU_IDX_A,
-
- ARMMMUIdx_E2 = 4 | ARM_MMU_IDX_A,
- ARMMMUIdx_E20_2 = 5 | ARM_MMU_IDX_A,
- ARMMMUIdx_E20_2_PAN = 6 | ARM_MMU_IDX_A,
-
- ARMMMUIdx_SE10_0 = 7 | ARM_MMU_IDX_A,
- ARMMMUIdx_SE10_1 = 8 | ARM_MMU_IDX_A,
- ARMMMUIdx_SE10_1_PAN = 9 | ARM_MMU_IDX_A,
- ARMMMUIdx_SE3 = 10 | ARM_MMU_IDX_A,
+ ARMMMUIdx_SE10_0 = 0 | ARM_MMU_IDX_A,
+ ARMMMUIdx_SE20_0 = 1 | ARM_MMU_IDX_A,
+ ARMMMUIdx_SE10_1 = 2 | ARM_MMU_IDX_A,
+ ARMMMUIdx_SE20_2 = 3 | ARM_MMU_IDX_A,
+ ARMMMUIdx_SE10_1_PAN = 4 | ARM_MMU_IDX_A,
+ ARMMMUIdx_SE20_2_PAN = 5 | ARM_MMU_IDX_A,
+ ARMMMUIdx_SE2 = 6 | ARM_MMU_IDX_A,
+ ARMMMUIdx_SE3 = 7 | ARM_MMU_IDX_A,
+
+ ARMMMUIdx_E10_0 = ARMMMUIdx_SE10_0 | ARM_MMU_IDX_A_NS,
+ ARMMMUIdx_E20_0 = ARMMMUIdx_SE20_0 | ARM_MMU_IDX_A_NS,
+ ARMMMUIdx_E10_1 = ARMMMUIdx_SE10_1 | ARM_MMU_IDX_A_NS,
+ ARMMMUIdx_E20_2 = ARMMMUIdx_SE20_2 | ARM_MMU_IDX_A_NS,
+ ARMMMUIdx_E10_1_PAN = ARMMMUIdx_SE10_1_PAN | ARM_MMU_IDX_A_NS,
+ ARMMMUIdx_E20_2_PAN = ARMMMUIdx_SE20_2_PAN | ARM_MMU_IDX_A_NS,
+ ARMMMUIdx_E2 = ARMMMUIdx_SE2 | ARM_MMU_IDX_A_NS,
/*
* These are not allocated TLBs and are used only for AT system
@@ -3057,6 +3102,9 @@ typedef enum ARMMMUIdx {
ARMMMUIdx_Stage1_E0 = 0 | ARM_MMU_IDX_NOTLB,
ARMMMUIdx_Stage1_E1 = 1 | ARM_MMU_IDX_NOTLB,
ARMMMUIdx_Stage1_E1_PAN = 2 | ARM_MMU_IDX_NOTLB,
+ ARMMMUIdx_Stage1_SE0 = 3 | ARM_MMU_IDX_NOTLB,
+ ARMMMUIdx_Stage1_SE1 = 4 | ARM_MMU_IDX_NOTLB,
+ ARMMMUIdx_Stage1_SE1_PAN = 5 | ARM_MMU_IDX_NOTLB,
/*
* Not allocated a TLB: used only for second stage of an S12 page
* table walk, or for descriptor loads during first stage of an S1
@@ -3064,7 +3112,8 @@ typedef enum ARMMMUIdx {
* then various TLB flush insns which currently are no-ops or flush
* only stage 1 MMU indexes will need to change to flush stage 2.
*/
- ARMMMUIdx_Stage2 = 3 | ARM_MMU_IDX_NOTLB,
+ ARMMMUIdx_Stage2 = 6 | ARM_MMU_IDX_NOTLB,
+ ARMMMUIdx_Stage2_S = 7 | ARM_MMU_IDX_NOTLB,
/*
* M-profile.
@@ -3095,8 +3144,12 @@ typedef enum ARMMMUIdxBit {
TO_CORE_BIT(E20_2),
TO_CORE_BIT(E20_2_PAN),
TO_CORE_BIT(SE10_0),
+ TO_CORE_BIT(SE20_0),
TO_CORE_BIT(SE10_1),
+ TO_CORE_BIT(SE20_2),
TO_CORE_BIT(SE10_1_PAN),
+ TO_CORE_BIT(SE20_2_PAN),
+ TO_CORE_BIT(SE2),
TO_CORE_BIT(SE3),
TO_CORE_BIT(MUser),
@@ -3127,7 +3180,7 @@ static inline int arm_debug_target_el(CPUARMState *env)
bool secure = arm_is_secure(env);
bool route_to_el2 = false;
- if (arm_feature(env, ARM_FEATURE_EL2) && !secure) {
+ if (arm_is_el2_enabled(env)) {
route_to_el2 = env->cp15.hcr_el2 & HCR_TGE ||
env->cp15.mdcr_el2 & MDCR_TDE;
}
@@ -3918,10 +3971,8 @@ static inline bool isar_feature_aa64_fcma(const ARMISARegisters *id)
static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id)
{
/*
- * Note that while QEMU will only implement the architected algorithm
- * QARMA, and thus APA+GPA, the host cpu for kvm may use implementation
- * defined algorithms, and thus API+GPI, and this predicate controls
- * migration of the 128-bit keys.
+ * Return true if any form of pauth is enabled, as this
+ * predicate controls migration of the 128-bit keys.
*/
return (id->id_aa64isar1 &
(FIELD_DP64(0, ID_AA64ISAR1, APA, 0xf) |
@@ -3930,6 +3981,15 @@ static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id)
FIELD_DP64(0, ID_AA64ISAR1, GPI, 0xf))) != 0;
}
+static inline bool isar_feature_aa64_pauth_arch(const ARMISARegisters *id)
+{
+ /*
+ * Return true if pauth is enabled with the architected QARMA algorithm.
+ * QEMU will always set APA+GPA to the same value.
+ */
+ return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, APA) != 0;
+}
+
static inline bool isar_feature_aa64_sb(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SB) != 0;
@@ -3977,6 +4037,11 @@ static inline bool isar_feature_aa64_sve(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SVE) != 0;
}
+static inline bool isar_feature_aa64_sel2(const ARMISARegisters *id)
+{
+ return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, SEL2) != 0;
+}
+
static inline bool isar_feature_aa64_vh(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64mmfr1, ID_AA64MMFR1, VH) != 0;
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index da24f94..5e85102 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -28,6 +28,8 @@
#include "sysemu/kvm.h"
#include "kvm_arm.h"
#include "qapi/visitor.h"
+#include "hw/qdev-properties.h"
+
#ifndef CONFIG_USER_ONLY
static uint64_t a57_a53_l2ctlr_read(CPUARMState *env, const ARMCPRegInfo *ri)
@@ -486,6 +488,12 @@ static void cpu_max_set_sve_max_vq(Object *obj, Visitor *v, const char *name,
cpu->sve_max_vq = max_vq;
}
+/*
+ * Note that cpu_arm_get/set_sve_vq cannot use the simpler
+ * object_property_add_bool interface because they make use
+ * of the contents of "name" to determine which bit on which
+ * to operate.
+ */
static void cpu_arm_get_sve_vq(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -527,26 +535,17 @@ static void cpu_arm_set_sve_vq(Object *obj, Visitor *v, const char *name,
set_bit(vq - 1, cpu->sve_vq_init);
}
-static void cpu_arm_get_sve(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
+static bool cpu_arm_get_sve(Object *obj, Error **errp)
{
ARMCPU *cpu = ARM_CPU(obj);
- bool value = cpu_isar_feature(aa64_sve, cpu);
-
- visit_type_bool(v, name, &value, errp);
+ return cpu_isar_feature(aa64_sve, cpu);
}
-static void cpu_arm_set_sve(Object *obj, Visitor *v, const char *name,
- void *opaque, Error **errp)
+static void cpu_arm_set_sve(Object *obj, bool value, Error **errp)
{
ARMCPU *cpu = ARM_CPU(obj);
- bool value;
uint64_t t;
- if (!visit_type_bool(v, name, &value, errp)) {
- return;
- }
-
if (value && kvm_enabled() && !kvm_arm_sve_supported()) {
error_setg(errp, "'sve' feature not supported by KVM on this host");
return;
@@ -561,8 +560,7 @@ void aarch64_add_sve_properties(Object *obj)
{
uint32_t vq;
- object_property_add(obj, "sve", "bool", cpu_arm_get_sve,
- cpu_arm_set_sve, NULL, NULL);
+ object_property_add_bool(obj, "sve", cpu_arm_get_sve, cpu_arm_set_sve);
for (vq = 1; vq <= ARM_MAX_VQ; ++vq) {
char name[8];
@@ -572,6 +570,36 @@ void aarch64_add_sve_properties(Object *obj)
}
}
+void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
+{
+ int arch_val = 0, impdef_val = 0;
+ uint64_t t;
+
+ /* TODO: Handle HaveEnhancedPAC, HaveEnhancedPAC2, HaveFPAC. */
+ if (cpu->prop_pauth) {
+ if (cpu->prop_pauth_impdef) {
+ impdef_val = 1;
+ } else {
+ arch_val = 1;
+ }
+ } else if (cpu->prop_pauth_impdef) {
+ error_setg(errp, "cannot enable pauth-impdef without pauth");
+ error_append_hint(errp, "Add pauth=on to the CPU property list.\n");
+ }
+
+ t = cpu->isar.id_aa64isar1;
+ t = FIELD_DP64(t, ID_AA64ISAR1, APA, arch_val);
+ t = FIELD_DP64(t, ID_AA64ISAR1, GPA, arch_val);
+ t = FIELD_DP64(t, ID_AA64ISAR1, API, impdef_val);
+ t = FIELD_DP64(t, ID_AA64ISAR1, GPI, impdef_val);
+ cpu->isar.id_aa64isar1 = t;
+}
+
+static Property arm_cpu_pauth_property =
+ DEFINE_PROP_BOOL("pauth", ARMCPU, prop_pauth, true);
+static Property arm_cpu_pauth_impdef_property =
+ DEFINE_PROP_BOOL("pauth-impdef", ARMCPU, prop_pauth_impdef, false);
+
/* -cpu max: if KVM is enabled, like -cpu host (best possible with this host);
* otherwise, a CPU with as many features enabled as our emulation supports.
* The version of '-cpu max' for qemu-system-arm is defined in cpu.c;
@@ -627,10 +655,6 @@ static void aarch64_max_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2);
t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1);
t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1);
- t = FIELD_DP64(t, ID_AA64ISAR1, APA, 1); /* PAuth, architected only */
- t = FIELD_DP64(t, ID_AA64ISAR1, API, 0);
- t = FIELD_DP64(t, ID_AA64ISAR1, GPA, 1);
- t = FIELD_DP64(t, ID_AA64ISAR1, GPI, 0);
t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1);
t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1);
t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1);
@@ -641,6 +665,7 @@ static void aarch64_max_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1);
t = FIELD_DP64(t, ID_AA64PFR0, FP, 1);
t = FIELD_DP64(t, ID_AA64PFR0, ADVSIMD, 1);
+ t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1);
cpu->isar.id_aa64pfr0 = t;
t = cpu->isar.id_aa64pfr1;
@@ -721,6 +746,10 @@ static void aarch64_max_initfn(Object *obj)
cpu->ctr = 0x80038003; /* 32 byte I and D cacheline size, VIPT icache */
cpu->dcz_blocksize = 7; /* 512 bytes */
#endif
+
+ /* Default to PAUTH on, with the architected algorithm. */
+ qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_property);
+ qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_impdef_property);
}
aarch64_add_sve_properties(obj);
diff --git a/target/arm/helper-a64.c b/target/arm/helper-a64.c
index 30b2ad1..c426c23 100644
--- a/target/arm/helper-a64.c
+++ b/target/arm/helper-a64.c
@@ -972,8 +972,7 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc)
if (new_el == -1) {
goto illegal_return;
}
- if (new_el > cur_el
- || (new_el == 2 && !arm_feature(env, ARM_FEATURE_EL2))) {
+ if (new_el > cur_el || (new_el == 2 && !arm_is_el2_enabled(env))) {
/* Disallow return to an EL which is unimplemented or higher
* than the current one.
*/
@@ -985,11 +984,6 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc)
goto illegal_return;
}
- if (new_el == 2 && arm_is_secure_below_el3(env)) {
- /* Return to the non-existent secure-EL2 */
- goto illegal_return;
- }
-
if (new_el == 1 && (arm_hcr_el2_eff(env) & HCR_TGE)) {
goto illegal_return;
}
diff --git a/target/arm/helper.c b/target/arm/helper.c
index c5377e7..d2ead3f 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -533,12 +533,20 @@ static CPAccessResult access_trap_aa32s_el1(CPUARMState *env,
return CP_ACCESS_OK;
}
if (arm_is_secure_below_el3(env)) {
+ if (env->cp15.scr_el3 & SCR_EEL2) {
+ return CP_ACCESS_TRAP_EL2;
+ }
return CP_ACCESS_TRAP_EL3;
}
/* This will be EL1 NS and EL2 NS, which just UNDEF */
return CP_ACCESS_TRAP_UNCATEGORIZED;
}
+static uint64_t arm_mdcr_el2_eff(CPUARMState *env)
+{
+ return arm_is_el2_enabled(env) ? env->cp15.mdcr_el2 : 0;
+}
+
/* Check for traps to "powerdown debug" registers, which are controlled
* by MDCR.TDOSA
*/
@@ -546,11 +554,11 @@ static CPAccessResult access_tdosa(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
int el = arm_current_el(env);
- bool mdcr_el2_tdosa = (env->cp15.mdcr_el2 & MDCR_TDOSA) ||
- (env->cp15.mdcr_el2 & MDCR_TDE) ||
+ uint64_t mdcr_el2 = arm_mdcr_el2_eff(env);
+ bool mdcr_el2_tdosa = (mdcr_el2 & MDCR_TDOSA) || (mdcr_el2 & MDCR_TDE) ||
(arm_hcr_el2_eff(env) & HCR_TGE);
- if (el < 2 && mdcr_el2_tdosa && !arm_is_secure_below_el3(env)) {
+ if (el < 2 && mdcr_el2_tdosa) {
return CP_ACCESS_TRAP_EL2;
}
if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDOSA)) {
@@ -566,11 +574,11 @@ static CPAccessResult access_tdra(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
int el = arm_current_el(env);
- bool mdcr_el2_tdra = (env->cp15.mdcr_el2 & MDCR_TDRA) ||
- (env->cp15.mdcr_el2 & MDCR_TDE) ||
+ uint64_t mdcr_el2 = arm_mdcr_el2_eff(env);
+ bool mdcr_el2_tdra = (mdcr_el2 & MDCR_TDRA) || (mdcr_el2 & MDCR_TDE) ||
(arm_hcr_el2_eff(env) & HCR_TGE);
- if (el < 2 && mdcr_el2_tdra && !arm_is_secure_below_el3(env)) {
+ if (el < 2 && mdcr_el2_tdra) {
return CP_ACCESS_TRAP_EL2;
}
if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDA)) {
@@ -586,11 +594,11 @@ static CPAccessResult access_tda(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
int el = arm_current_el(env);
- bool mdcr_el2_tda = (env->cp15.mdcr_el2 & MDCR_TDA) ||
- (env->cp15.mdcr_el2 & MDCR_TDE) ||
+ uint64_t mdcr_el2 = arm_mdcr_el2_eff(env);
+ bool mdcr_el2_tda = (mdcr_el2 & MDCR_TDA) || (mdcr_el2 & MDCR_TDE) ||
(arm_hcr_el2_eff(env) & HCR_TGE);
- if (el < 2 && mdcr_el2_tda && !arm_is_secure_below_el3(env)) {
+ if (el < 2 && mdcr_el2_tda) {
return CP_ACCESS_TRAP_EL2;
}
if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TDA)) {
@@ -606,9 +614,9 @@ static CPAccessResult access_tpm(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
int el = arm_current_el(env);
+ uint64_t mdcr_el2 = arm_mdcr_el2_eff(env);
- if (el < 2 && (env->cp15.mdcr_el2 & MDCR_TPM)
- && !arm_is_secure_below_el3(env)) {
+ if (el < 2 && (mdcr_el2 & MDCR_TPM)) {
return CP_ACCESS_TRAP_EL2;
}
if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TPM)) {
@@ -1049,8 +1057,8 @@ static CPAccessResult cpacr_access(CPUARMState *env, const ARMCPRegInfo *ri,
{
if (arm_feature(env, ARM_FEATURE_V8)) {
/* Check if CPACR accesses are to be trapped to EL2 */
- if (arm_current_el(env) == 1 &&
- (env->cp15.cptr_el[2] & CPTR_TCPAC) && !arm_is_secure(env)) {
+ if (arm_current_el(env) == 1 && arm_is_el2_enabled(env) &&
+ (env->cp15.cptr_el[2] & CPTR_TCPAC)) {
return CP_ACCESS_TRAP_EL2;
/* Check if CPACR accesses are to be trapped to EL3 */
} else if (arm_current_el(env) < 3 &&
@@ -1348,12 +1356,12 @@ static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri,
* trapping to EL2 or EL3 for other accesses.
*/
int el = arm_current_el(env);
+ uint64_t mdcr_el2 = arm_mdcr_el2_eff(env);
if (el == 0 && !(env->cp15.c9_pmuserenr & 1)) {
return CP_ACCESS_TRAP;
}
- if (el < 2 && (env->cp15.mdcr_el2 & MDCR_TPM)
- && !arm_is_secure_below_el3(env)) {
+ if (el < 2 && (mdcr_el2 & MDCR_TPM)) {
return CP_ACCESS_TRAP_EL2;
}
if (el < 3 && (env->cp15.mdcr_el3 & MDCR_TPM)) {
@@ -1432,7 +1440,8 @@ static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter)
bool enabled, prohibited, filtered;
bool secure = arm_is_secure(env);
int el = arm_current_el(env);
- uint8_t hpmn = env->cp15.mdcr_el2 & MDCR_HPMN;
+ uint64_t mdcr_el2 = arm_mdcr_el2_eff(env);
+ uint8_t hpmn = mdcr_el2 & MDCR_HPMN;
if (!arm_feature(env, ARM_FEATURE_PMU)) {
return false;
@@ -1442,13 +1451,13 @@ static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter)
(counter < hpmn || counter == 31)) {
e = env->cp15.c9_pmcr & PMCRE;
} else {
- e = env->cp15.mdcr_el2 & MDCR_HPME;
+ e = mdcr_el2 & MDCR_HPME;
}
enabled = e && (env->cp15.c9_pmcnten & (1 << counter));
if (!secure) {
if (el == 2 && (counter < hpmn || counter == 31)) {
- prohibited = env->cp15.mdcr_el2 & MDCR_HPMD;
+ prohibited = mdcr_el2 & MDCR_HPMD;
} else {
prohibited = false;
}
@@ -2024,6 +2033,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
if (cpu_isar_feature(aa64_pauth, cpu)) {
valid_mask |= SCR_API | SCR_APK;
}
+ if (cpu_isar_feature(aa64_sel2, cpu)) {
+ valid_mask |= SCR_EEL2;
+ }
if (cpu_isar_feature(aa64_mte, cpu)) {
valid_mask |= SCR_ATA;
}
@@ -2084,13 +2096,11 @@ static void csselr_write(CPUARMState *env, const ARMCPRegInfo *ri,
static uint64_t isr_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
CPUState *cs = env_cpu(env);
- uint64_t hcr_el2 = arm_hcr_el2_eff(env);
+ bool el1 = arm_current_el(env) == 1;
+ uint64_t hcr_el2 = el1 ? arm_hcr_el2_eff(env) : 0;
uint64_t ret = 0;
- bool allow_virt = (arm_current_el(env) == 1 &&
- (!arm_is_secure_below_el3(env) ||
- (env->cp15.scr_el3 & SCR_EEL2)));
- if (allow_virt && (hcr_el2 & HCR_IMO)) {
+ if (hcr_el2 & HCR_IMO) {
if (cs->interrupt_request & CPU_INTERRUPT_VIRQ) {
ret |= CPSR_I;
}
@@ -2100,7 +2110,7 @@ static uint64_t isr_read(CPUARMState *env, const ARMCPRegInfo *ri)
}
}
- if (allow_virt && (hcr_el2 & HCR_FMO)) {
+ if (hcr_el2 & HCR_FMO) {
if (cs->interrupt_request & CPU_INTERRUPT_VFIQ) {
ret |= CPSR_F;
}
@@ -2522,7 +2532,7 @@ static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx,
bool isread)
{
unsigned int cur_el = arm_current_el(env);
- bool secure = arm_is_secure(env);
+ bool has_el2 = arm_is_el2_enabled(env);
uint64_t hcr = arm_hcr_el2_eff(env);
switch (cur_el) {
@@ -2546,8 +2556,7 @@ static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx,
}
} else {
/* If HCR_EL2.<E2H> == 0: check CNTHCTL_EL2.EL1PCEN. */
- if (arm_feature(env, ARM_FEATURE_EL2) &&
- timeridx == GTIMER_PHYS && !secure &&
+ if (has_el2 && timeridx == GTIMER_PHYS &&
!extract32(env->cp15.cnthctl_el2, 1, 1)) {
return CP_ACCESS_TRAP_EL2;
}
@@ -2556,8 +2565,7 @@ static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx,
case 1:
/* Check CNTHCTL_EL2.EL1PCTEN, which changes location based on E2H. */
- if (arm_feature(env, ARM_FEATURE_EL2) &&
- timeridx == GTIMER_PHYS && !secure &&
+ if (has_el2 && timeridx == GTIMER_PHYS &&
(hcr & HCR_E2H
? !extract32(env->cp15.cnthctl_el2, 10, 1)
: !extract32(env->cp15.cnthctl_el2, 0, 1))) {
@@ -2572,7 +2580,7 @@ static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx,
bool isread)
{
unsigned int cur_el = arm_current_el(env);
- bool secure = arm_is_secure(env);
+ bool has_el2 = arm_is_el2_enabled(env);
uint64_t hcr = arm_hcr_el2_eff(env);
switch (cur_el) {
@@ -2593,8 +2601,7 @@ static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx,
/* fall through */
case 1:
- if (arm_feature(env, ARM_FEATURE_EL2) &&
- timeridx == GTIMER_PHYS && !secure) {
+ if (has_el2 && timeridx == GTIMER_PHYS) {
if (hcr & HCR_E2H) {
/* If HCR_EL2.<E2H,TGE> == '10': check CNTHCTL_EL2.EL1PTEN. */
if (!extract32(env->cp15.cnthctl_el2, 11, 1)) {
@@ -2861,6 +2868,9 @@ static int gt_phys_redir_timeridx(CPUARMState *env)
case ARMMMUIdx_E20_0:
case ARMMMUIdx_E20_2:
case ARMMMUIdx_E20_2_PAN:
+ case ARMMMUIdx_SE20_0:
+ case ARMMMUIdx_SE20_2:
+ case ARMMMUIdx_SE20_2_PAN:
return GTIMER_HYP;
default:
return GTIMER_PHYS;
@@ -2873,6 +2883,9 @@ static int gt_virt_redir_timeridx(CPUARMState *env)
case ARMMMUIdx_E20_0:
case ARMMMUIdx_E20_2:
case ARMMMUIdx_E20_2_PAN:
+ case ARMMMUIdx_SE20_0:
+ case ARMMMUIdx_SE20_2:
+ case ARMMMUIdx_SE20_2_PAN:
return GTIMER_HYPVIRT;
default:
return GTIMER_VIRT;
@@ -3381,13 +3394,16 @@ static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
if (ri->opc2 & 4) {
- /* The ATS12NSO* operations must trap to EL3 if executed in
+ /* The ATS12NSO* operations must trap to EL3 or EL2 if executed in
* Secure EL1 (which can only happen if EL3 is AArch64).
* They are simply UNDEF if executed from NS EL1.
* They function normally from EL2 or EL3.
*/
if (arm_current_el(env) == 1) {
if (arm_is_secure_below_el3(env)) {
+ if (env->cp15.scr_el3 & SCR_EEL2) {
+ return CP_ACCESS_TRAP_UNCATEGORIZED_EL2;
+ }
return CP_ACCESS_TRAP_UNCATEGORIZED_EL3;
}
return CP_ACCESS_TRAP_UNCATEGORIZED;
@@ -3423,7 +3439,7 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
uint32_t syn, fsr, fsc;
bool take_exc = false;
- if (fi.s1ptw && current_el == 1 && !arm_is_secure(env)
+ if (fi.s1ptw && current_el == 1
&& arm_mmu_idx_is_stage1_of_2(mmu_idx)) {
/*
* Synchronous stage 2 fault on an access made as part of the
@@ -3438,6 +3454,9 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
target_el = 3;
} else {
env->cp15.hpfar_el2 = extract64(fi.s2addr, 12, 47) << 4;
+ if (arm_is_secure_below_el3(env) && fi.s1ns) {
+ env->cp15.hpfar_el2 |= HPFAR_NS;
+ }
target_el = 2;
}
take_exc = true;
@@ -3576,14 +3595,14 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
mmu_idx = ARMMMUIdx_SE3;
break;
case 2:
- g_assert(!secure); /* TODO: ARMv8.4-SecEL2 */
+ g_assert(!secure); /* ARMv8.4-SecEL2 is 64-bit only */
/* fall through */
case 1:
if (ri->crm == 9 && (env->uncached_cpsr & CPSR_PAN)) {
- mmu_idx = (secure ? ARMMMUIdx_SE10_1_PAN
+ mmu_idx = (secure ? ARMMMUIdx_Stage1_SE1_PAN
: ARMMMUIdx_Stage1_E1_PAN);
} else {
- mmu_idx = secure ? ARMMMUIdx_SE10_1 : ARMMMUIdx_Stage1_E1;
+ mmu_idx = secure ? ARMMMUIdx_Stage1_SE1 : ARMMMUIdx_Stage1_E1;
}
break;
default:
@@ -3597,10 +3616,11 @@ static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
mmu_idx = ARMMMUIdx_SE10_0;
break;
case 2:
+ g_assert(!secure); /* ARMv8.4-SecEL2 is 64-bit only */
mmu_idx = ARMMMUIdx_Stage1_E0;
break;
case 1:
- mmu_idx = secure ? ARMMMUIdx_SE10_0 : ARMMMUIdx_Stage1_E0;
+ mmu_idx = secure ? ARMMMUIdx_Stage1_SE0 : ARMMMUIdx_Stage1_E0;
break;
default:
g_assert_not_reached();
@@ -3646,7 +3666,8 @@ static void ats1h_write(CPUARMState *env, const ARMCPRegInfo *ri,
static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
- if (arm_current_el(env) == 3 && !(env->cp15.scr_el3 & SCR_NS)) {
+ if (arm_current_el(env) == 3 &&
+ !(env->cp15.scr_el3 & (SCR_NS | SCR_EEL2))) {
return CP_ACCESS_TRAP;
}
return CP_ACCESS_OK;
@@ -3665,14 +3686,14 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
switch (ri->opc1) {
case 0: /* AT S1E1R, AT S1E1W, AT S1E1RP, AT S1E1WP */
if (ri->crm == 9 && (env->pstate & PSTATE_PAN)) {
- mmu_idx = (secure ? ARMMMUIdx_SE10_1_PAN
+ mmu_idx = (secure ? ARMMMUIdx_Stage1_SE1_PAN
: ARMMMUIdx_Stage1_E1_PAN);
} else {
- mmu_idx = secure ? ARMMMUIdx_SE10_1 : ARMMMUIdx_Stage1_E1;
+ mmu_idx = secure ? ARMMMUIdx_Stage1_SE1 : ARMMMUIdx_Stage1_E1;
}
break;
case 4: /* AT S1E2R, AT S1E2W */
- mmu_idx = ARMMMUIdx_E2;
+ mmu_idx = secure ? ARMMMUIdx_SE2 : ARMMMUIdx_E2;
break;
case 6: /* AT S1E3R, AT S1E3W */
mmu_idx = ARMMMUIdx_SE3;
@@ -3682,7 +3703,7 @@ static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
}
break;
case 2: /* AT S1E0R, AT S1E0W */
- mmu_idx = secure ? ARMMMUIdx_SE10_0 : ARMMMUIdx_Stage1_E0;
+ mmu_idx = secure ? ARMMMUIdx_Stage1_SE0 : ARMMMUIdx_Stage1_E0;
break;
case 4: /* AT S12E1R, AT S12E1W */
mmu_idx = secure ? ARMMMUIdx_SE10_1 : ARMMMUIdx_E10_1;
@@ -3987,10 +4008,15 @@ static void vmsa_tcr_ttbr_el2_write(CPUARMState *env, const ARMCPRegInfo *ri,
*/
if (extract64(raw_read(env, ri) ^ value, 48, 16) &&
(arm_hcr_el2_eff(env) & HCR_E2H)) {
- tlb_flush_by_mmuidx(env_cpu(env),
- ARMMMUIdxBit_E20_2 |
- ARMMMUIdxBit_E20_2_PAN |
- ARMMMUIdxBit_E20_0);
+ uint16_t mask = ARMMMUIdxBit_E20_2 |
+ ARMMMUIdxBit_E20_2_PAN |
+ ARMMMUIdxBit_E20_0;
+
+ if (arm_is_secure_below_el3(env)) {
+ mask >>= ARM_MMU_IDX_A_NS;
+ }
+
+ tlb_flush_by_mmuidx(env_cpu(env), mask);
}
raw_write(env, ri, value);
}
@@ -4006,10 +4032,15 @@ static void vttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
* the combined stage 1&2 tlbs (EL10_1 and EL10_0).
*/
if (raw_read(env, ri) != value) {
- tlb_flush_by_mmuidx(cs,
- ARMMMUIdxBit_E10_1 |
- ARMMMUIdxBit_E10_1_PAN |
- ARMMMUIdxBit_E10_0);
+ uint16_t mask = ARMMMUIdxBit_E10_1 |
+ ARMMMUIdxBit_E10_1_PAN |
+ ARMMMUIdxBit_E10_0;
+
+ if (arm_is_secure_below_el3(env)) {
+ mask >>= ARM_MMU_IDX_A_NS;
+ }
+
+ tlb_flush_by_mmuidx(cs, mask);
raw_write(env, ri, value);
}
}
@@ -4250,11 +4281,9 @@ static const ARMCPRegInfo strongarm_cp_reginfo[] = {
static uint64_t midr_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
- ARMCPU *cpu = env_archcpu(env);
unsigned int cur_el = arm_current_el(env);
- bool secure = arm_is_secure(env);
- if (arm_feature(&cpu->env, ARM_FEATURE_EL2) && !secure && cur_el == 1) {
+ if (arm_is_el2_enabled(env) && cur_el == 1) {
return env->cp15.vpidr_el2;
}
return raw_read(env, ri);
@@ -4281,9 +4310,8 @@ static uint64_t mpidr_read_val(CPUARMState *env)
static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
unsigned int cur_el = arm_current_el(env);
- bool secure = arm_is_secure(env);
- if (arm_feature(env, ARM_FEATURE_EL2) && !secure && cur_el == 1) {
+ if (arm_is_el2_enabled(env) && cur_el == 1) {
return env->cp15.vmpidr_el2;
}
return mpidr_read_val(env);
@@ -4441,21 +4469,24 @@ static CPAccessResult aa64_cacheop_pou_access(CPUARMState *env,
static int vae1_tlbmask(CPUARMState *env)
{
- /* Since we exclude secure first, we may read HCR_EL2 directly. */
- if (arm_is_secure_below_el3(env)) {
- return ARMMMUIdxBit_SE10_1 |
- ARMMMUIdxBit_SE10_1_PAN |
- ARMMMUIdxBit_SE10_0;
- } else if ((env->cp15.hcr_el2 & (HCR_E2H | HCR_TGE))
- == (HCR_E2H | HCR_TGE)) {
- return ARMMMUIdxBit_E20_2 |
+ uint64_t hcr = arm_hcr_el2_eff(env);
+ uint16_t mask;
+
+ if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
+ mask = ARMMMUIdxBit_E20_2 |
ARMMMUIdxBit_E20_2_PAN |
ARMMMUIdxBit_E20_0;
} else {
- return ARMMMUIdxBit_E10_1 |
+ mask = ARMMMUIdxBit_E10_1 |
ARMMMUIdxBit_E10_1_PAN |
ARMMMUIdxBit_E10_0;
}
+
+ if (arm_is_secure_below_el3(env)) {
+ mask >>= ARM_MMU_IDX_A_NS;
+ }
+
+ return mask;
}
/* Return 56 if TBI is enabled, 64 otherwise. */
@@ -4471,17 +4502,20 @@ static int tlbbits_for_regime(CPUARMState *env, ARMMMUIdx mmu_idx,
static int vae1_tlbbits(CPUARMState *env, uint64_t addr)
{
+ uint64_t hcr = arm_hcr_el2_eff(env);
ARMMMUIdx mmu_idx;
/* Only the regime of the mmu_idx below is significant. */
- if (arm_is_secure_below_el3(env)) {
- mmu_idx = ARMMMUIdx_SE10_0;
- } else if ((env->cp15.hcr_el2 & (HCR_E2H | HCR_TGE))
- == (HCR_E2H | HCR_TGE)) {
+ if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
mmu_idx = ARMMMUIdx_E20_0;
} else {
mmu_idx = ARMMMUIdx_E10_0;
}
+
+ if (arm_is_secure_below_el3(env)) {
+ mmu_idx &= ~ARM_MMU_IDX_A_NS;
+ }
+
return tlbbits_for_regime(env, mmu_idx, addr);
}
@@ -4527,11 +4561,17 @@ static int alle1_tlbmask(CPUARMState *env)
static int e2_tlbmask(CPUARMState *env)
{
- /* TODO: ARMv8.4-SecEL2 */
- return ARMMMUIdxBit_E20_0 |
- ARMMMUIdxBit_E20_2 |
- ARMMMUIdxBit_E20_2_PAN |
- ARMMMUIdxBit_E2;
+ if (arm_is_secure_below_el3(env)) {
+ return ARMMMUIdxBit_SE20_0 |
+ ARMMMUIdxBit_SE20_2 |
+ ARMMMUIdxBit_SE20_2_PAN |
+ ARMMMUIdxBit_SE2;
+ } else {
+ return ARMMMUIdxBit_E20_0 |
+ ARMMMUIdxBit_E20_2 |
+ ARMMMUIdxBit_E20_2_PAN |
+ ARMMMUIdxBit_E2;
+ }
}
static void tlbi_aa64_alle1_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -4651,10 +4691,12 @@ static void tlbi_aa64_vae2is_write(CPUARMState *env, const ARMCPRegInfo *ri,
{
CPUState *cs = env_cpu(env);
uint64_t pageaddr = sextract64(value << 12, 0, 56);
- int bits = tlbbits_for_regime(env, ARMMMUIdx_E2, pageaddr);
+ bool secure = arm_is_secure_below_el3(env);
+ int mask = secure ? ARMMMUIdxBit_SE2 : ARMMMUIdxBit_E2;
+ int bits = tlbbits_for_regime(env, secure ? ARMMMUIdx_E2 : ARMMMUIdx_SE2,
+ pageaddr);
- tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr,
- ARMMMUIdxBit_E2, bits);
+ tlb_flush_page_bits_by_mmuidx_all_cpus_synced(cs, pageaddr, mask, bits);
}
static void tlbi_aa64_vae3is_write(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -5350,7 +5392,7 @@ uint64_t arm_hcr_el2_eff(CPUARMState *env)
{
uint64_t ret = env->cp15.hcr_el2;
- if (arm_is_secure_below_el3(env)) {
+ if (!arm_is_el2_enabled(env)) {
/*
* "This register has no effect if EL2 is not enabled in the
* current Security state". This is ARMv8.4-SecEL2 speak for
@@ -5696,16 +5738,40 @@ static const ARMCPRegInfo el2_v8_cp_reginfo[] = {
REGINFO_SENTINEL
};
+static CPAccessResult sel2_access(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ if (arm_current_el(env) == 3 || arm_is_secure_below_el3(env)) {
+ return CP_ACCESS_OK;
+ }
+ return CP_ACCESS_TRAP_UNCATEGORIZED;
+}
+
+static const ARMCPRegInfo el2_sec_cp_reginfo[] = {
+ { .name = "VSTTBR_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 6, .opc2 = 0,
+ .access = PL2_RW, .accessfn = sel2_access,
+ .fieldoffset = offsetof(CPUARMState, cp15.vsttbr_el2) },
+ { .name = "VSTCR_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .crn = 2, .crm = 6, .opc2 = 2,
+ .access = PL2_RW, .accessfn = sel2_access,
+ .fieldoffset = offsetof(CPUARMState, cp15.vstcr_el2) },
+ REGINFO_SENTINEL
+};
+
static CPAccessResult nsacr_access(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
/* The NSACR is RW at EL3, and RO for NS EL1 and NS EL2.
- * At Secure EL1 it traps to EL3.
+ * At Secure EL1 it traps to EL3 or EL2.
*/
if (arm_current_el(env) == 3) {
return CP_ACCESS_OK;
}
if (arm_is_secure_below_el3(env)) {
+ if (env->cp15.scr_el3 & SCR_EEL2) {
+ return CP_ACCESS_TRAP_EL2;
+ }
return CP_ACCESS_TRAP_EL3;
}
/* Accesses from EL1 NS and EL2 NS are UNDEF for write but allow reads. */
@@ -6147,7 +6213,7 @@ int sve_exception_el(CPUARMState *env, int el)
/* CPTR_EL2. Since TZ and TFP are positive,
* they will be zero when EL2 is not present.
*/
- if (el <= 2 && !arm_is_secure_below_el3(env)) {
+ if (el <= 2 && arm_is_el2_enabled(env)) {
if (env->cp15.cptr_el[2] & CPTR_TZ) {
return 2;
}
@@ -7708,6 +7774,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
if (arm_feature(env, ARM_FEATURE_V8)) {
define_arm_cp_regs(cpu, el2_v8_cp_reginfo);
}
+ if (cpu_isar_feature(aa64_sel2, cpu)) {
+ define_arm_cp_regs(cpu, el2_sec_cp_reginfo);
+ }
/* RVBAR_EL2 is only implemented if EL2 is the highest EL */
if (!arm_feature(env, ARM_FEATURE_EL3)) {
ARMCPRegInfo rvbar = {
@@ -8722,8 +8791,7 @@ static int bad_mode_switch(CPUARMState *env, int mode, CPSRWriteType write_type)
}
return 0;
case ARM_CPU_MODE_HYP:
- return !arm_feature(env, ARM_FEATURE_EL2)
- || arm_current_el(env) < 2 || arm_is_secure_below_el3(env);
+ return !arm_is_el2_enabled(env) || arm_current_el(env) < 2;
case ARM_CPU_MODE_MON:
return arm_current_el(env) < 3;
default:
@@ -9005,13 +9073,13 @@ static const int8_t target_el_table[2][2][2][2][2][4] = {
{{/* 0 1 1 0 */{ 3, 3, 3, -1 },{ 3, -1, -1, 3 },},
{/* 0 1 1 1 */{ 3, 3, 3, -1 },{ 3, -1, -1, 3 },},},},},
{{{{/* 1 0 0 0 */{ 1, 1, 2, -1 },{ 1, 1, -1, 1 },},
- {/* 1 0 0 1 */{ 2, 2, 2, -1 },{ 1, 1, -1, 1 },},},
- {{/* 1 0 1 0 */{ 1, 1, 1, -1 },{ 1, 1, -1, 1 },},
- {/* 1 0 1 1 */{ 2, 2, 2, -1 },{ 1, 1, -1, 1 },},},},
+ {/* 1 0 0 1 */{ 2, 2, 2, -1 },{ 2, 2, -1, 1 },},},
+ {{/* 1 0 1 0 */{ 1, 1, 1, -1 },{ 1, 1, 1, 1 },},
+ {/* 1 0 1 1 */{ 2, 2, 2, -1 },{ 2, 2, 2, 1 },},},},
{{{/* 1 1 0 0 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },},
{/* 1 1 0 1 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },},},
- {{/* 1 1 1 0 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },},
- {/* 1 1 1 1 */{ 3, 3, 3, -1 },{ 3, 3, -1, 3 },},},},},
+ {{/* 1 1 1 0 */{ 3, 3, 3, -1 },{ 3, 3, 3, 3 },},
+ {/* 1 1 1 1 */{ 3, 3, 3, -1 },{ 3, 3, 3, 3 },},},},},
};
/*
@@ -9957,7 +10025,8 @@ uint64_t arm_sctlr(CPUARMState *env, int el)
/* Only EL0 needs to be adjusted for EL1&0 or EL2&0. */
if (el == 0) {
ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, 0);
- el = (mmu_idx == ARMMMUIdx_E20_0 ? 2 : 1);
+ el = (mmu_idx == ARMMMUIdx_E20_0 || mmu_idx == ARMMMUIdx_SE20_0)
+ ? 2 : 1;
}
return env->cp15.sctlr_el[el];
}
@@ -9974,6 +10043,8 @@ static inline uint64_t regime_sctlr(CPUARMState *env, ARMMMUIdx mmu_idx)
static inline bool regime_translation_disabled(CPUARMState *env,
ARMMMUIdx mmu_idx)
{
+ uint64_t hcr_el2;
+
if (arm_feature(env, ARM_FEATURE_M)) {
switch (env->v7m.mpu_ctrl[regime_is_secure(env, mmu_idx)] &
(R_V7M_MPU_CTRL_ENABLE_MASK | R_V7M_MPU_CTRL_HFNMIENA_MASK)) {
@@ -9992,19 +10063,21 @@ static inline bool regime_translation_disabled(CPUARMState *env,
}
}
- if (mmu_idx == ARMMMUIdx_Stage2) {
+ hcr_el2 = arm_hcr_el2_eff(env);
+
+ if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) {
/* HCR.DC means HCR.VM behaves as 1 */
- return (env->cp15.hcr_el2 & (HCR_DC | HCR_VM)) == 0;
+ return (hcr_el2 & (HCR_DC | HCR_VM)) == 0;
}
- if (env->cp15.hcr_el2 & HCR_TGE) {
+ if (hcr_el2 & HCR_TGE) {
/* TGE means that NS EL0/1 act as if SCTLR_EL1.M is zero */
if (!regime_is_secure(env, mmu_idx) && regime_el(env, mmu_idx) == 1) {
return true;
}
}
- if ((env->cp15.hcr_el2 & HCR_DC) && arm_mmu_idx_is_stage1_of_2(mmu_idx)) {
+ if ((hcr_el2 & HCR_DC) && arm_mmu_idx_is_stage1_of_2(mmu_idx)) {
/* HCR.DC means SCTLR_EL1.M behaves as 0 */
return true;
}
@@ -10025,6 +10098,9 @@ static inline uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx,
if (mmu_idx == ARMMMUIdx_Stage2) {
return env->cp15.vttbr_el2;
}
+ if (mmu_idx == ARMMMUIdx_Stage2_S) {
+ return env->cp15.vsttbr_el2;
+ }
if (ttbrn == 0) {
return env->cp15.ttbr0_el[regime_el(env, mmu_idx)];
} else {
@@ -10040,6 +10116,12 @@ static inline uint64_t regime_ttbr(CPUARMState *env, ARMMMUIdx mmu_idx,
static inline ARMMMUIdx stage_1_mmu_idx(ARMMMUIdx mmu_idx)
{
switch (mmu_idx) {
+ case ARMMMUIdx_SE10_0:
+ return ARMMMUIdx_Stage1_SE0;
+ case ARMMMUIdx_SE10_1:
+ return ARMMMUIdx_Stage1_SE1;
+ case ARMMMUIdx_SE10_1_PAN:
+ return ARMMMUIdx_Stage1_SE1_PAN;
case ARMMMUIdx_E10_0:
return ARMMMUIdx_Stage1_E0;
case ARMMMUIdx_E10_1:
@@ -10082,7 +10164,9 @@ static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx)
switch (mmu_idx) {
case ARMMMUIdx_SE10_0:
case ARMMMUIdx_E20_0:
+ case ARMMMUIdx_SE20_0:
case ARMMMUIdx_Stage1_E0:
+ case ARMMMUIdx_Stage1_SE0:
case ARMMMUIdx_MUser:
case ARMMMUIdx_MSUser:
case ARMMMUIdx_MUserNegPri:
@@ -10248,6 +10332,7 @@ static int get_S1prot(CPUARMState *env, ARMMMUIdx mmu_idx, bool is_aa64,
int wxn = 0;
assert(mmu_idx != ARMMMUIdx_Stage2);
+ assert(mmu_idx != ARMMMUIdx_Stage2_S);
user_rw = simple_ap_to_rw_prot_is_user(ap, true);
if (is_user) {
@@ -10333,7 +10418,7 @@ static bool get_level1_table_address(CPUARMState *env, ARMMMUIdx mmu_idx,
/* Translate a S1 pagetable walk through S2 if needed. */
static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx,
- hwaddr addr, MemTxAttrs txattrs,
+ hwaddr addr, bool *is_secure,
ARMMMUFaultInfo *fi)
{
if (arm_mmu_idx_is_stage1_of_2(mmu_idx) &&
@@ -10342,10 +10427,12 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx,
hwaddr s2pa;
int s2prot;
int ret;
+ ARMMMUIdx s2_mmu_idx = *is_secure ? ARMMMUIdx_Stage2_S
+ : ARMMMUIdx_Stage2;
ARMCacheAttrs cacheattrs = {};
+ MemTxAttrs txattrs = {};
- ret = get_phys_addr_lpae(env, addr, MMU_DATA_LOAD, ARMMMUIdx_Stage2,
- false,
+ ret = get_phys_addr_lpae(env, addr, MMU_DATA_LOAD, s2_mmu_idx, false,
&s2pa, &txattrs, &s2prot, &s2size, fi,
&cacheattrs);
if (ret) {
@@ -10353,9 +10440,11 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx,
fi->s2addr = addr;
fi->stage2 = true;
fi->s1ptw = true;
+ fi->s1ns = !*is_secure;
return ~0;
}
- if ((env->cp15.hcr_el2 & HCR_PTW) && (cacheattrs.attrs & 0xf0) == 0) {
+ if ((arm_hcr_el2_eff(env) & HCR_PTW) &&
+ (cacheattrs.attrs & 0xf0) == 0) {
/*
* PTW set and S1 walk touched S2 Device memory:
* generate Permission fault.
@@ -10364,8 +10453,21 @@ static hwaddr S1_ptw_translate(CPUARMState *env, ARMMMUIdx mmu_idx,
fi->s2addr = addr;
fi->stage2 = true;
fi->s1ptw = true;
+ fi->s1ns = !*is_secure;
return ~0;
}
+
+ if (arm_is_secure_below_el3(env)) {
+ /* Check if page table walk is to secure or non-secure PA space. */
+ if (*is_secure) {
+ *is_secure = !(env->cp15.vstcr_el2.raw_tcr & VSTCR_SW);
+ } else {
+ *is_secure = !(env->cp15.vtcr_el2.raw_tcr & VTCR_NSW);
+ }
+ } else {
+ assert(!*is_secure);
+ }
+
addr = s2pa;
}
return addr;
@@ -10382,9 +10484,9 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure,
AddressSpace *as;
uint32_t data;
+ addr = S1_ptw_translate(env, mmu_idx, addr, &is_secure, fi);
attrs.secure = is_secure;
as = arm_addressspace(cs, attrs);
- addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fi);
if (fi->s1ptw) {
return 0;
}
@@ -10411,9 +10513,9 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure,
AddressSpace *as;
uint64_t data;
+ addr = S1_ptw_translate(env, mmu_idx, addr, &is_secure, fi);
attrs.secure = is_secure;
as = arm_addressspace(cs, attrs);
- addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fi);
if (fi->s1ptw) {
return 0;
}
@@ -10788,7 +10890,7 @@ static uint8_t convert_stage2_attrs(CPUARMState *env, uint8_t s2attrs)
uint8_t hihint = 0, lohint = 0;
if (hiattr != 0) { /* normal memory */
- if ((env->cp15.hcr_el2 & HCR_CD) != 0) { /* cache disabled */
+ if (arm_hcr_el2_eff(env) & HCR_CD) { /* cache disabled */
hiattr = loattr = 1; /* non-cacheable */
} else {
if (hiattr != 1) { /* Write-through or write-back */
@@ -10808,7 +10910,7 @@ static int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx)
{
if (regime_has_2_ranges(mmu_idx)) {
return extract64(tcr, 37, 2);
- } else if (mmu_idx == ARMMMUIdx_Stage2) {
+ } else if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) {
return 0; /* VTCR_EL2 */
} else {
/* Replicate the single TBI bit so we always have 2 bits. */
@@ -10820,7 +10922,7 @@ static int aa64_va_parameter_tbid(uint64_t tcr, ARMMMUIdx mmu_idx)
{
if (regime_has_2_ranges(mmu_idx)) {
return extract64(tcr, 51, 2);
- } else if (mmu_idx == ARMMMUIdx_Stage2) {
+ } else if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) {
return 0; /* VTCR_EL2 */
} else {
/* Replicate the single TBID bit so we always have 2 bits. */
@@ -10850,7 +10952,7 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
tsz = extract32(tcr, 0, 6);
using64k = extract32(tcr, 14, 1);
using16k = extract32(tcr, 15, 1);
- if (mmu_idx == ARMMMUIdx_Stage2) {
+ if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) {
/* VTCR_EL2 */
hpd = false;
} else {
@@ -10915,6 +11017,8 @@ static ARMVAParameters aa32_va_parameters(CPUARMState *env, uint32_t va,
int select, tsz;
bool epd, hpd;
+ assert(mmu_idx != ARMMMUIdx_Stage2_S);
+
if (mmu_idx == ARMMMUIdx_Stage2) {
/* VTCR */
bool sext = extract32(tcr, 4, 1);
@@ -11080,7 +11184,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
goto do_fault;
}
- if (mmu_idx != ARMMMUIdx_Stage2) {
+ if (mmu_idx != ARMMMUIdx_Stage2 && mmu_idx != ARMMMUIdx_Stage2_S) {
/* The starting level depends on the virtual address size (which can
* be up to 48 bits) and the translation granule size. It indicates
* the number of strides (stride bits at a time) needed to
@@ -11188,7 +11292,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
attrs = extract64(descriptor, 2, 10)
| (extract64(descriptor, 52, 12) << 10);
- if (mmu_idx == ARMMMUIdx_Stage2) {
+ if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) {
/* Stage 2 table descriptors do not include any attribute fields */
break;
}
@@ -11218,8 +11322,8 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
ap = extract32(attrs, 4, 2);
- if (mmu_idx == ARMMMUIdx_Stage2) {
- ns = true;
+ if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) {
+ ns = mmu_idx == ARMMMUIdx_Stage2;
xn = extract32(attrs, 11, 2);
*prot = get_S2prot(env, ap, xn, s1_is_el0);
} else {
@@ -11246,7 +11350,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, uint64_t address,
arm_tlb_bti_gp(txattrs) = true;
}
- if (mmu_idx == ARMMMUIdx_Stage2) {
+ if (mmu_idx == ARMMMUIdx_Stage2 || mmu_idx == ARMMMUIdx_Stage2_S) {
cacheattrs->attrs = convert_stage2_attrs(env, extract32(attrs, 0, 4));
} else {
/* Index into MAIR registers for cache attributes */
@@ -11265,7 +11369,9 @@ do_fault:
fi->type = fault_type;
fi->level = level;
/* Tag the error as S2 for failed S1 PTW at S2 or ordinary S2. */
- fi->stage2 = fi->s1ptw || (mmu_idx == ARMMMUIdx_Stage2);
+ fi->stage2 = fi->s1ptw || (mmu_idx == ARMMMUIdx_Stage2 ||
+ mmu_idx == ARMMMUIdx_Stage2_S);
+ fi->s1ns = mmu_idx == ARMMMUIdx_Stage2;
return true;
}
@@ -12084,21 +12190,22 @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
target_ulong *page_size,
ARMMMUFaultInfo *fi, ARMCacheAttrs *cacheattrs)
{
- if (mmu_idx == ARMMMUIdx_E10_0 ||
- mmu_idx == ARMMMUIdx_E10_1 ||
- mmu_idx == ARMMMUIdx_E10_1_PAN) {
+ ARMMMUIdx s1_mmu_idx = stage_1_mmu_idx(mmu_idx);
+
+ if (mmu_idx != s1_mmu_idx) {
/* Call ourselves recursively to do the stage 1 and then stage 2
- * translations.
+ * translations if mmu_idx is a two-stage regime.
*/
if (arm_feature(env, ARM_FEATURE_EL2)) {
hwaddr ipa;
int s2_prot;
int ret;
ARMCacheAttrs cacheattrs2 = {};
+ ARMMMUIdx s2_mmu_idx;
+ bool is_el0;
- ret = get_phys_addr(env, address, access_type,
- stage_1_mmu_idx(mmu_idx), &ipa, attrs,
- prot, page_size, fi, cacheattrs);
+ ret = get_phys_addr(env, address, access_type, s1_mmu_idx, &ipa,
+ attrs, prot, page_size, fi, cacheattrs);
/* If S1 fails or S2 is disabled, return early. */
if (ret || regime_translation_disabled(env, ARMMMUIdx_Stage2)) {
@@ -12106,9 +12213,11 @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
return ret;
}
+ s2_mmu_idx = attrs->secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2;
+ is_el0 = mmu_idx == ARMMMUIdx_E10_0 || mmu_idx == ARMMMUIdx_SE10_0;
+
/* S1 is done. Now do S2 translation. */
- ret = get_phys_addr_lpae(env, ipa, access_type, ARMMMUIdx_Stage2,
- mmu_idx == ARMMMUIdx_E10_0,
+ ret = get_phys_addr_lpae(env, ipa, access_type, s2_mmu_idx, is_el0,
phys_ptr, attrs, &s2_prot,
page_size, fi, &cacheattrs2);
fi->s2addr = ipa;
@@ -12121,7 +12230,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
}
/* Combine the S1 and S2 cache attributes. */
- if (env->cp15.hcr_el2 & HCR_DC) {
+ if (arm_hcr_el2_eff(env) & HCR_DC) {
/*
* HCR.DC forces the first stage attributes to
* Normal Non-Shareable,
@@ -12135,6 +12244,18 @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
cacheattrs->shareability = 0;
}
*cacheattrs = combine_cacheattrs(*cacheattrs, cacheattrs2);
+
+ /* Check if IPA translates to secure or non-secure PA space. */
+ if (arm_is_secure_below_el3(env)) {
+ if (attrs->secure) {
+ attrs->secure =
+ !(env->cp15.vstcr_el2.raw_tcr & (VSTCR_SA | VSTCR_SW));
+ } else {
+ attrs->secure =
+ !((env->cp15.vtcr_el2.raw_tcr & (VTCR_NSA | VTCR_NSW))
+ || (env->cp15.vstcr_el2.raw_tcr & VSTCR_SA));
+ }
+ }
return 0;
} else {
/*
@@ -12203,7 +12324,7 @@ bool get_phys_addr(CPUARMState *env, target_ulong address,
* MMU disabled. S1 addresses within aa64 translation regimes are
* still checked for bounds -- see AArch64.TranslateAddressS1Off.
*/
- if (mmu_idx != ARMMMUIdx_Stage2) {
+ if (mmu_idx != ARMMMUIdx_Stage2 && mmu_idx != ARMMMUIdx_Stage2_S) {
int r_el = regime_el(env, mmu_idx);
if (arm_el_is_aa64(env, r_el)) {
int pamax = arm_pamax(env_archcpu(env));
@@ -12649,7 +12770,7 @@ int fp_exception_el(CPUARMState *env, int cur_el)
/* CPTR_EL2 : present in v7VE or v8 */
if (cur_el <= 2 && extract32(env->cp15.cptr_el[2], 10, 1)
- && !arm_is_secure_below_el3(env)) {
+ && arm_is_el2_enabled(env)) {
/* Trap FP ops at EL2, NS-EL1 or NS-EL0 to EL2 */
return 2;
}
@@ -12674,6 +12795,7 @@ int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
case ARMMMUIdx_E10_0:
case ARMMMUIdx_E20_0:
case ARMMMUIdx_SE10_0:
+ case ARMMMUIdx_SE20_0:
return 0;
case ARMMMUIdx_E10_1:
case ARMMMUIdx_E10_1_PAN:
@@ -12683,6 +12805,9 @@ int arm_mmu_idx_to_el(ARMMMUIdx mmu_idx)
case ARMMMUIdx_E2:
case ARMMMUIdx_E20_2:
case ARMMMUIdx_E20_2_PAN:
+ case ARMMMUIdx_SE2:
+ case ARMMMUIdx_SE20_2:
+ case ARMMMUIdx_SE20_2_PAN:
return 2;
case ARMMMUIdx_SE3:
return 3;
@@ -12700,6 +12825,9 @@ ARMMMUIdx arm_v7m_mmu_idx_for_secstate(CPUARMState *env, bool secstate)
ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el)
{
+ ARMMMUIdx idx;
+ uint64_t hcr;
+
if (arm_feature(env, ARM_FEATURE_M)) {
return arm_v7m_mmu_idx_for_secstate(env, env->v7m.secure);
}
@@ -12707,40 +12835,43 @@ ARMMMUIdx arm_mmu_idx_el(CPUARMState *env, int el)
/* See ARM pseudo-function ELIsInHost. */
switch (el) {
case 0:
- if (arm_is_secure_below_el3(env)) {
- return ARMMMUIdx_SE10_0;
- }
- if ((env->cp15.hcr_el2 & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)
- && arm_el_is_aa64(env, 2)) {
- return ARMMMUIdx_E20_0;
+ hcr = arm_hcr_el2_eff(env);
+ if ((hcr & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE)) {
+ idx = ARMMMUIdx_E20_0;
+ } else {
+ idx = ARMMMUIdx_E10_0;
}
- return ARMMMUIdx_E10_0;
+ break;
case 1:
- if (arm_is_secure_below_el3(env)) {
- if (env->pstate & PSTATE_PAN) {
- return ARMMMUIdx_SE10_1_PAN;
- }
- return ARMMMUIdx_SE10_1;
- }
if (env->pstate & PSTATE_PAN) {
- return ARMMMUIdx_E10_1_PAN;
+ idx = ARMMMUIdx_E10_1_PAN;
+ } else {
+ idx = ARMMMUIdx_E10_1;
}
- return ARMMMUIdx_E10_1;
+ break;
case 2:
- /* TODO: ARMv8.4-SecEL2 */
/* Note that TGE does not apply at EL2. */
- if ((env->cp15.hcr_el2 & HCR_E2H) && arm_el_is_aa64(env, 2)) {
+ if (arm_hcr_el2_eff(env) & HCR_E2H) {
if (env->pstate & PSTATE_PAN) {
- return ARMMMUIdx_E20_2_PAN;
+ idx = ARMMMUIdx_E20_2_PAN;
+ } else {
+ idx = ARMMMUIdx_E20_2;
}
- return ARMMMUIdx_E20_2;
+ } else {
+ idx = ARMMMUIdx_E2;
}
- return ARMMMUIdx_E2;
+ break;
case 3:
return ARMMMUIdx_SE3;
default:
g_assert_not_reached();
}
+
+ if (arm_is_secure_below_el3(env)) {
+ idx &= ~ARM_MMU_IDX_A_NS;
+ }
+
+ return idx;
}
ARMMMUIdx arm_mmu_idx(CPUARMState *env)
@@ -12905,7 +13036,8 @@ static uint32_t rebuild_hflags_a64(CPUARMState *env, int el, int fp_el,
break;
case ARMMMUIdx_E20_2:
case ARMMMUIdx_E20_2_PAN:
- /* TODO: ARMv8.4-SecEL2 */
+ case ARMMMUIdx_SE20_2:
+ case ARMMMUIdx_SE20_2_PAN:
/*
* Note that EL20_2 is gated by HCR_EL2.E2H == 1, but EL20_0 is
* gated by HCR_EL2.<E2H,TGE> == '11', and so is LDTR.
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 5460678..853fa88 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -593,6 +593,7 @@ typedef enum ARMFaultType {
* @s2addr: Address that caused a fault at stage 2
* @stage2: True if we faulted at stage 2
* @s1ptw: True if we faulted at stage 2 while doing a stage 1 page-table walk
+ * @s1ns: True if we faulted on a non-secure IPA while in secure state
* @ea: True if we should set the EA (external abort type) bit in syndrome
*/
typedef struct ARMMMUFaultInfo ARMMMUFaultInfo;
@@ -603,6 +604,7 @@ struct ARMMMUFaultInfo {
int domain;
bool stage2;
bool s1ptw;
+ bool s1ns;
bool ea;
};
@@ -851,6 +853,9 @@ static inline bool regime_has_2_ranges(ARMMMUIdx mmu_idx)
case ARMMMUIdx_Stage1_E0:
case ARMMMUIdx_Stage1_E1:
case ARMMMUIdx_Stage1_E1_PAN:
+ case ARMMMUIdx_Stage1_SE0:
+ case ARMMMUIdx_Stage1_SE1:
+ case ARMMMUIdx_Stage1_SE1_PAN:
case ARMMMUIdx_E10_0:
case ARMMMUIdx_E10_1:
case ARMMMUIdx_E10_1_PAN:
@@ -860,6 +865,9 @@ static inline bool regime_has_2_ranges(ARMMMUIdx mmu_idx)
case ARMMMUIdx_SE10_0:
case ARMMMUIdx_SE10_1:
case ARMMMUIdx_SE10_1_PAN:
+ case ARMMMUIdx_SE20_0:
+ case ARMMMUIdx_SE20_2:
+ case ARMMMUIdx_SE20_2_PAN:
return true;
default:
return false;
@@ -890,6 +898,14 @@ static inline bool regime_is_secure(CPUARMState *env, ARMMMUIdx mmu_idx)
case ARMMMUIdx_SE10_0:
case ARMMMUIdx_SE10_1:
case ARMMMUIdx_SE10_1_PAN:
+ case ARMMMUIdx_SE20_0:
+ case ARMMMUIdx_SE20_2:
+ case ARMMMUIdx_SE20_2_PAN:
+ case ARMMMUIdx_Stage1_SE0:
+ case ARMMMUIdx_Stage1_SE1:
+ case ARMMMUIdx_Stage1_SE1_PAN:
+ case ARMMMUIdx_SE2:
+ case ARMMMUIdx_Stage2_S:
case ARMMMUIdx_MSPrivNegPri:
case ARMMMUIdx_MSUserNegPri:
case ARMMMUIdx_MSPriv:
@@ -904,9 +920,11 @@ static inline bool regime_is_pan(CPUARMState *env, ARMMMUIdx mmu_idx)
{
switch (mmu_idx) {
case ARMMMUIdx_Stage1_E1_PAN:
+ case ARMMMUIdx_Stage1_SE1_PAN:
case ARMMMUIdx_E10_1_PAN:
case ARMMMUIdx_E20_2_PAN:
case ARMMMUIdx_SE10_1_PAN:
+ case ARMMMUIdx_SE20_2_PAN:
return true;
default:
return false;
@@ -917,21 +935,29 @@ static inline bool regime_is_pan(CPUARMState *env, ARMMMUIdx mmu_idx)
static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
{
switch (mmu_idx) {
+ case ARMMMUIdx_SE20_0:
+ case ARMMMUIdx_SE20_2:
+ case ARMMMUIdx_SE20_2_PAN:
case ARMMMUIdx_E20_0:
case ARMMMUIdx_E20_2:
case ARMMMUIdx_E20_2_PAN:
case ARMMMUIdx_Stage2:
+ case ARMMMUIdx_Stage2_S:
+ case ARMMMUIdx_SE2:
case ARMMMUIdx_E2:
return 2;
case ARMMMUIdx_SE3:
return 3;
case ARMMMUIdx_SE10_0:
+ case ARMMMUIdx_Stage1_SE0:
return arm_el_is_aa64(env, 3) ? 1 : 3;
case ARMMMUIdx_SE10_1:
case ARMMMUIdx_SE10_1_PAN:
case ARMMMUIdx_Stage1_E0:
case ARMMMUIdx_Stage1_E1:
case ARMMMUIdx_Stage1_E1_PAN:
+ case ARMMMUIdx_Stage1_SE1:
+ case ARMMMUIdx_Stage1_SE1_PAN:
case ARMMMUIdx_E10_0:
case ARMMMUIdx_E10_1:
case ARMMMUIdx_E10_1_PAN:
@@ -955,6 +981,13 @@ static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx)
if (mmu_idx == ARMMMUIdx_Stage2) {
return &env->cp15.vtcr_el2;
}
+ if (mmu_idx == ARMMMUIdx_Stage2_S) {
+ /*
+ * Note: Secure stage 2 nominally shares fields from VTCR_EL2, but
+ * those are not currently used by QEMU, so just return VSTCR_EL2.
+ */
+ return &env->cp15.vstcr_el2;
+ }
return &env->cp15.tcr_el[regime_el(env, mmu_idx)];
}
@@ -1157,6 +1190,9 @@ static inline bool arm_mmu_idx_is_stage1_of_2(ARMMMUIdx mmu_idx)
case ARMMMUIdx_Stage1_E0:
case ARMMMUIdx_Stage1_E1:
case ARMMMUIdx_Stage1_E1_PAN:
+ case ARMMMUIdx_Stage1_SE0:
+ case ARMMMUIdx_Stage1_SE1:
+ case ARMMMUIdx_Stage1_SE1_PAN:
return true;
default:
return false;
@@ -1313,6 +1349,15 @@ void arm_log_exception(int idx);
#define TAG_GRANULE (1 << LOG2_TAG_GRANULE)
/*
+ * SVE predicates are 1/8 the size of SVE vectors, and cannot use
+ * the same simd_desc() encoding due to restrictions on size.
+ * Use these instead.
+ */
+FIELD(PREDDESC, OPRSZ, 0, 6)
+FIELD(PREDDESC, ESZ, 6, 2)
+FIELD(PREDDESC, DATA, 8, 24)
+
+/*
* The SVE simd_data field, for memory ops, contains either
* rd (5 bits) or a shift count (2 bits).
*/
diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c
index 6176003..731c435 100644
--- a/target/arm/m_helper.c
+++ b/target/arm/m_helper.c
@@ -1347,7 +1347,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu)
bool exc_secure = false;
bool return_to_secure;
bool ftype;
- bool restore_s16_s31;
+ bool restore_s16_s31 = false;
/*
* If we're not in Handler mode then jumps to magic exception-exit
diff --git a/target/arm/monitor.c b/target/arm/monitor.c
index 198b14e..80c64fa 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -95,6 +95,7 @@ static const char *cpu_model_advertised_features[] = {
"sve640", "sve768", "sve896", "sve1024", "sve1152", "sve1280",
"sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048",
"kvm-no-adjvtime", "kvm-steal-time",
+ "pauth", "pauth-impdef",
NULL
};
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
index ff91fe6..5e0f123 100644
--- a/target/arm/op_helper.c
+++ b/target/arm/op_helper.c
@@ -652,10 +652,10 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
target_el = exception_target_el(env);
break;
case CP_ACCESS_TRAP_EL2:
- /* Requesting a trap to EL2 when we're in EL3 or S-EL0/1 is
+ /* Requesting a trap to EL2 when we're in EL3 is
* a bug in the access function.
*/
- assert(!arm_is_secure(env) && arm_current_el(env) != 3);
+ assert(arm_current_el(env) != 3);
target_el = 2;
break;
case CP_ACCESS_TRAP_EL3:
diff --git a/target/arm/pauth_helper.c b/target/arm/pauth_helper.c
index 564c48f..cd6df18 100644
--- a/target/arm/pauth_helper.c
+++ b/target/arm/pauth_helper.c
@@ -24,6 +24,7 @@
#include "exec/cpu_ldst.h"
#include "exec/helper-proto.h"
#include "tcg/tcg-gvec-desc.h"
+#include "qemu/xxhash.h"
static uint64_t pac_cell_shuffle(uint64_t i)
@@ -207,8 +208,8 @@ static uint64_t tweak_inv_shuffle(uint64_t i)
return o;
}
-static uint64_t pauth_computepac(uint64_t data, uint64_t modifier,
- ARMPACKey key)
+static uint64_t pauth_computepac_architected(uint64_t data, uint64_t modifier,
+ ARMPACKey key)
{
static const uint64_t RC[5] = {
0x0000000000000000ull,
@@ -272,6 +273,22 @@ static uint64_t pauth_computepac(uint64_t data, uint64_t modifier,
return workingval;
}
+static uint64_t pauth_computepac_impdef(uint64_t data, uint64_t modifier,
+ ARMPACKey key)
+{
+ return qemu_xxhash64_4(data, modifier, key.lo, key.hi);
+}
+
+static uint64_t pauth_computepac(CPUARMState *env, uint64_t data,
+ uint64_t modifier, ARMPACKey key)
+{
+ if (cpu_isar_feature(aa64_pauth_arch, env_archcpu(env))) {
+ return pauth_computepac_architected(data, modifier, key);
+ } else {
+ return pauth_computepac_impdef(data, modifier, key);
+ }
+}
+
static uint64_t pauth_addpac(CPUARMState *env, uint64_t ptr, uint64_t modifier,
ARMPACKey *key, bool data)
{
@@ -292,7 +309,7 @@ static uint64_t pauth_addpac(CPUARMState *env, uint64_t ptr, uint64_t modifier,
bot_bit = 64 - param.tsz;
ext_ptr = deposit64(ptr, bot_bit, top_bit - bot_bit, ext);
- pac = pauth_computepac(ext_ptr, modifier, *key);
+ pac = pauth_computepac(env, ext_ptr, modifier, *key);
/*
* Check if the ptr has good extension bits and corrupt the
@@ -341,7 +358,7 @@ static uint64_t pauth_auth(CPUARMState *env, uint64_t ptr, uint64_t modifier,
uint64_t pac, orig_ptr, test;
orig_ptr = pauth_original_ptr(ptr, param);
- pac = pauth_computepac(orig_ptr, modifier, *key);
+ pac = pauth_computepac(env, orig_ptr, modifier, *key);
bot_bit = 64 - param.tsz;
top_bit = 64 - 8 * param.tbi;
@@ -442,7 +459,7 @@ uint64_t HELPER(pacga)(CPUARMState *env, uint64_t x, uint64_t y)
uint64_t pac;
pauth_check_trap(env, arm_current_el(env), GETPC());
- pac = pauth_computepac(x, y, env->keys.apga);
+ pac = pauth_computepac(env, x, y, env->keys.apga);
return pac & 0xffffffff00000000ull;
}
diff --git a/target/arm/sve_helper.c b/target/arm/sve_helper.c
index 5f037c3..844db08 100644
--- a/target/arm/sve_helper.c
+++ b/target/arm/sve_helper.c
@@ -889,8 +889,9 @@ static intptr_t last_active_element(uint64_t *g, intptr_t words, intptr_t esz)
return (intptr_t)-1 << esz;
}
-uint32_t HELPER(sve_pfirst)(void *vd, void *vg, uint32_t words)
+uint32_t HELPER(sve_pfirst)(void *vd, void *vg, uint32_t pred_desc)
{
+ intptr_t words = DIV_ROUND_UP(FIELD_EX32(pred_desc, PREDDESC, OPRSZ), 8);
uint32_t flags = PREDTEST_INIT;
uint64_t *d = vd, *g = vg;
intptr_t i = 0;
@@ -914,8 +915,8 @@ uint32_t HELPER(sve_pfirst)(void *vd, void *vg, uint32_t words)
uint32_t HELPER(sve_pnext)(void *vd, void *vg, uint32_t pred_desc)
{
- intptr_t words = extract32(pred_desc, 0, SIMD_OPRSZ_BITS);
- intptr_t esz = extract32(pred_desc, SIMD_DATA_SHIFT, 2);
+ intptr_t words = DIV_ROUND_UP(FIELD_EX32(pred_desc, PREDDESC, OPRSZ), 8);
+ intptr_t esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
uint32_t flags = PREDTEST_INIT;
uint64_t *d = vd, *g = vg, esz_mask;
intptr_t i, next;
@@ -1867,9 +1868,9 @@ static uint64_t compress_bits(uint64_t x, int n)
void HELPER(sve_zip_p)(void *vd, void *vn, void *vm, uint32_t pred_desc)
{
- intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
- int esz = extract32(pred_desc, SIMD_DATA_SHIFT, 2);
- intptr_t high = extract32(pred_desc, SIMD_DATA_SHIFT + 2, 1);
+ intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
+ int esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
+ intptr_t high = FIELD_EX32(pred_desc, PREDDESC, DATA);
uint64_t *d = vd;
intptr_t i;
@@ -1928,9 +1929,9 @@ void HELPER(sve_zip_p)(void *vd, void *vn, void *vm, uint32_t pred_desc)
void HELPER(sve_uzp_p)(void *vd, void *vn, void *vm, uint32_t pred_desc)
{
- intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
- int esz = extract32(pred_desc, SIMD_DATA_SHIFT, 2);
- int odd = extract32(pred_desc, SIMD_DATA_SHIFT + 2, 1) << esz;
+ intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
+ int esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
+ int odd = FIELD_EX32(pred_desc, PREDDESC, DATA) << esz;
uint64_t *d = vd, *n = vn, *m = vm;
uint64_t l, h;
intptr_t i;
@@ -1985,9 +1986,9 @@ void HELPER(sve_uzp_p)(void *vd, void *vn, void *vm, uint32_t pred_desc)
void HELPER(sve_trn_p)(void *vd, void *vn, void *vm, uint32_t pred_desc)
{
- intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
- uintptr_t esz = extract32(pred_desc, SIMD_DATA_SHIFT, 2);
- bool odd = extract32(pred_desc, SIMD_DATA_SHIFT + 2, 1);
+ intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
+ int esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
+ int odd = FIELD_EX32(pred_desc, PREDDESC, DATA);
uint64_t *d = vd, *n = vn, *m = vm;
uint64_t mask;
int shr, shl;
@@ -2035,8 +2036,8 @@ static uint8_t reverse_bits_8(uint8_t x, int n)
void HELPER(sve_rev_p)(void *vd, void *vn, uint32_t pred_desc)
{
- intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
- int esz = extract32(pred_desc, SIMD_DATA_SHIFT, 2);
+ intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
+ int esz = FIELD_EX32(pred_desc, PREDDESC, ESZ);
intptr_t i, oprsz_2 = oprsz / 2;
if (oprsz <= 8) {
@@ -2065,8 +2066,8 @@ void HELPER(sve_rev_p)(void *vd, void *vn, uint32_t pred_desc)
void HELPER(sve_punpk_p)(void *vd, void *vn, uint32_t pred_desc)
{
- intptr_t oprsz = extract32(pred_desc, 0, SIMD_OPRSZ_BITS) + 2;
- intptr_t high = extract32(pred_desc, SIMD_DATA_SHIFT + 2, 1);
+ intptr_t oprsz = FIELD_EX32(pred_desc, PREDDESC, OPRSZ);
+ intptr_t high = FIELD_EX32(pred_desc, PREDDESC, DATA);
uint64_t *d = vd;
intptr_t i;
diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c
index b35dc8a..df85079 100644
--- a/target/arm/tlb_helper.c
+++ b/target/arm/tlb_helper.c
@@ -63,6 +63,9 @@ static void QEMU_NORETURN arm_deliver_fault(ARMCPU *cpu, vaddr addr,
if (fi->stage2) {
target_el = 2;
env->cp15.hpfar_el2 = extract64(fi->s2addr, 12, 47) << 4;
+ if (arm_is_secure_below_el3(env) && fi->s1ns) {
+ env->cp15.hpfar_el2 |= HPFAR_NS;
+ }
}
same_el = (arm_current_el(env) == target_el);
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index ef63edf..ffc060e 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -118,6 +118,10 @@ static int get_a64_user_mem_index(DisasContext *s)
case ARMMMUIdx_SE10_1_PAN:
useridx = ARMMMUIdx_SE10_0;
break;
+ case ARMMMUIdx_SE20_2:
+ case ARMMMUIdx_SE20_2_PAN:
+ useridx = ARMMMUIdx_SE20_0;
+ break;
default:
g_assert_not_reached();
}
diff --git a/target/arm/translate-sve.c b/target/arm/translate-sve.c
index 0c3a6d2..27402af 100644
--- a/target/arm/translate-sve.c
+++ b/target/arm/translate-sve.c
@@ -1494,10 +1494,10 @@ static bool do_pfirst_pnext(DisasContext *s, arg_rr_esz *a,
TCGv_ptr t_pd = tcg_temp_new_ptr();
TCGv_ptr t_pg = tcg_temp_new_ptr();
TCGv_i32 t;
- unsigned desc;
+ unsigned desc = 0;
- desc = DIV_ROUND_UP(pred_full_reg_size(s), 8);
- desc = deposit32(desc, SIMD_DATA_SHIFT, 2, a->esz);
+ desc = FIELD_DP32(desc, PREDDESC, OPRSZ, pred_full_reg_size(s));
+ desc = FIELD_DP32(desc, PREDDESC, ESZ, a->esz);
tcg_gen_addi_ptr(t_pd, cpu_env, pred_full_reg_offset(s, a->rd));
tcg_gen_addi_ptr(t_pg, cpu_env, pred_full_reg_offset(s, a->rn));
@@ -2110,19 +2110,15 @@ static bool do_perm_pred3(DisasContext *s, arg_rrr_esz *a, bool high_odd,
unsigned vsz = pred_full_reg_size(s);
- /* Predicate sizes may be smaller and cannot use simd_desc.
- We cannot round up, as we do elsewhere, because we need
- the exact size for ZIP2 and REV. We retain the style for
- the other helpers for consistency. */
TCGv_ptr t_d = tcg_temp_new_ptr();
TCGv_ptr t_n = tcg_temp_new_ptr();
TCGv_ptr t_m = tcg_temp_new_ptr();
TCGv_i32 t_desc;
- int desc;
+ uint32_t desc = 0;
- desc = vsz - 2;
- desc = deposit32(desc, SIMD_DATA_SHIFT, 2, a->esz);
- desc = deposit32(desc, SIMD_DATA_SHIFT + 2, 2, high_odd);
+ desc = FIELD_DP32(desc, PREDDESC, OPRSZ, vsz);
+ desc = FIELD_DP32(desc, PREDDESC, ESZ, a->esz);
+ desc = FIELD_DP32(desc, PREDDESC, DATA, high_odd);
tcg_gen_addi_ptr(t_d, cpu_env, pred_full_reg_offset(s, a->rd));
tcg_gen_addi_ptr(t_n, cpu_env, pred_full_reg_offset(s, a->rn));
@@ -2149,19 +2145,14 @@ static bool do_perm_pred2(DisasContext *s, arg_rr_esz *a, bool high_odd,
TCGv_ptr t_d = tcg_temp_new_ptr();
TCGv_ptr t_n = tcg_temp_new_ptr();
TCGv_i32 t_desc;
- int desc;
+ uint32_t desc = 0;
tcg_gen_addi_ptr(t_d, cpu_env, pred_full_reg_offset(s, a->rd));
tcg_gen_addi_ptr(t_n, cpu_env, pred_full_reg_offset(s, a->rn));
- /* Predicate sizes may be smaller and cannot use simd_desc.
- We cannot round up, as we do elsewhere, because we need
- the exact size for ZIP2 and REV. We retain the style for
- the other helpers for consistency. */
-
- desc = vsz - 2;
- desc = deposit32(desc, SIMD_DATA_SHIFT, 2, a->esz);
- desc = deposit32(desc, SIMD_DATA_SHIFT + 2, 2, high_odd);
+ desc = FIELD_DP32(desc, PREDDESC, OPRSZ, vsz);
+ desc = FIELD_DP32(desc, PREDDESC, ESZ, a->esz);
+ desc = FIELD_DP32(desc, PREDDESC, DATA, high_odd);
t_desc = tcg_const_i32(desc);
fn(t_d, t_n, t_desc);
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 528b93d..1653cca 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -1094,6 +1094,22 @@ static void unallocated_encoding(DisasContext *s)
default_exception_el(s));
}
+static void gen_exception_el(DisasContext *s, int excp, uint32_t syn,
+ TCGv_i32 tcg_el)
+{
+ TCGv_i32 tcg_excp;
+ TCGv_i32 tcg_syn;
+
+ gen_set_condexec(s);
+ gen_set_pc_im(s, s->pc_curr);
+ tcg_excp = tcg_const_i32(excp);
+ tcg_syn = tcg_const_i32(syn);
+ gen_helper_exception_with_syndrome(cpu_env, tcg_excp, tcg_syn, tcg_el);
+ tcg_temp_free_i32(tcg_syn);
+ tcg_temp_free_i32(tcg_excp);
+ s->base.is_jmp = DISAS_NORETURN;
+}
+
/* Force a TB lookup after an instruction that changes the CPU state. */
static inline void gen_lookup_tb(DisasContext *s)
{
@@ -2816,10 +2832,24 @@ static bool msr_banked_access_decode(DisasContext *s, int r, int sysm, int rn,
}
if (s->current_el == 1) {
/* If we're in Secure EL1 (which implies that EL3 is AArch64)
- * then accesses to Mon registers trap to EL3
+ * then accesses to Mon registers trap to Secure EL2, if it exists,
+ * otherwise EL3.
*/
- exc_target = 3;
- goto undef;
+ TCGv_i32 tcg_el;
+
+ if (arm_dc_feature(s, ARM_FEATURE_AARCH64) &&
+ dc_isar_feature(aa64_sel2, s)) {
+ /* Target EL is EL<3 minus SCR_EL3.EEL2> */
+ tcg_el = load_cpu_field(cp15.scr_el3);
+ tcg_gen_sextract_i32(tcg_el, tcg_el, ctz32(SCR_EEL2), 1);
+ tcg_gen_addi_i32(tcg_el, tcg_el, 3);
+ } else {
+ tcg_el = tcg_const_i32(3);
+ }
+
+ gen_exception_el(s, EXCP_UDEF, syn_uncategorized(), tcg_el);
+ tcg_temp_free_i32(tcg_el);
+ return false;
}
break;
case ARM_CPU_MODE_HYP:
diff --git a/tests/qtest/arm-cpu-features.c b/tests/qtest/arm-cpu-features.c
index bc681a9..8252b85 100644
--- a/tests/qtest/arm-cpu-features.c
+++ b/tests/qtest/arm-cpu-features.c
@@ -427,6 +427,18 @@ static void sve_tests_sve_off_kvm(const void *data)
qtest_quit(qts);
}
+static void pauth_tests_default(QTestState *qts, const char *cpu_type)
+{
+ assert_has_feature_enabled(qts, cpu_type, "pauth");
+ assert_has_feature_disabled(qts, cpu_type, "pauth-impdef");
+ assert_set_feature(qts, cpu_type, "pauth", false);
+ assert_set_feature(qts, cpu_type, "pauth", true);
+ assert_set_feature(qts, cpu_type, "pauth-impdef", true);
+ assert_set_feature(qts, cpu_type, "pauth-impdef", false);
+ assert_error(qts, cpu_type, "cannot enable pauth-impdef without pauth",
+ "{ 'pauth': false, 'pauth-impdef': true }");
+}
+
static void test_query_cpu_model_expansion(const void *data)
{
QTestState *qts;
@@ -462,6 +474,7 @@ static void test_query_cpu_model_expansion(const void *data)
assert_has_feature_enabled(qts, "cortex-a57", "aarch64");
sve_tests_default(qts, "max");
+ pauth_tests_default(qts, "max");
/* Test that features that depend on KVM generate errors without. */
assert_error(qts, "max",
diff --git a/tests/qtest/npcm7xx_adc-test.c b/tests/qtest/npcm7xx_adc-test.c
index f029706..5ce8ce1 100644
--- a/tests/qtest/npcm7xx_adc-test.c
+++ b/tests/qtest/npcm7xx_adc-test.c
@@ -129,6 +129,7 @@ static void adc_qom_set(QTestState *qts, const ADC *adc,
path, name, value);
/* The qom set message returns successfully. */
g_assert_true(qdict_haskey(response, "return"));
+ qobject_unref(response);
}
static void adc_write_input(QTestState *qts, const ADC *adc,