diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2021-03-24 11:22:08 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2021-03-24 11:22:08 +0000 |
commit | 01874b15d36e3f9a3506c47941a92ccf8d8bed98 (patch) | |
tree | 7f80e037c438ebe084e7e7c06b9f44faffc0a161 | |
parent | 67c1115edd98f388ca89dd38322ea3fadf034523 (diff) | |
parent | 44b99a6d5f24afcd8476d0d2701e1ca4ab9b35c1 (diff) |
Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20210323' into staging
Workaround for macos mprotect
Workaround for target_page vs -flto
# gpg: Signature made Wed 24 Mar 2021 01:40:12 GMT
# gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F
# gpg: issuer "richard.henderson@linaro.org"
# gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full]
# Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F
* remotes/rth/tags/pull-tcg-20210323:
exec: Build page-vary-common.c with -fno-lto
exec: Extract 'page-vary.h' header
exec: Rename exec-vary.c as page-vary.c
tcg: Workaround macOS 11.2 mprotect bug
tcg: Do not set guard pages on the rx portion of code_gen_buffer
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | MAINTAINERS | 2 | ||||
-rwxr-xr-x | configure | 19 | ||||
-rw-r--r-- | exec-vary.c | 108 | ||||
-rw-r--r-- | include/exec/cpu-all.h | 15 | ||||
-rw-r--r-- | include/exec/page-vary.h | 34 | ||||
-rw-r--r-- | meson.build | 21 | ||||
-rw-r--r-- | page-vary-common.c | 54 | ||||
-rw-r--r-- | page-vary.c | 41 | ||||
-rw-r--r-- | tcg/tcg.c | 22 |
9 files changed, 167 insertions, 149 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 9147e9a429..10ed6d7624 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -117,6 +117,8 @@ R: Paolo Bonzini <pbonzini@redhat.com> S: Maintained F: softmmu/cpus.c F: cpus-common.c +F: page-vary.c +F: page-vary-common.c F: accel/tcg/ F: accel/stubs/tcg-stub.c F: util/cacheinfo.c @@ -4890,21 +4890,6 @@ if test "$plugins" = "yes" && fi ######################################## -# See if __attribute__((alias)) is supported. -# This false for Xcode 9, but has been remedied for Xcode 10. -# Unfortunately, travis uses Xcode 9 by default. - -attralias=no -cat > $TMPC << EOF -int x = 1; -extern const int y __attribute__((alias("x"))); -int main(void) { return 0; } -EOF -if compile_prog "" "" ; then - attralias=yes -fi - -######################################## # check if getauxval is available. getauxval=no @@ -5935,10 +5920,6 @@ if test "$atomic64" = "yes" ; then echo "CONFIG_ATOMIC64=y" >> $config_host_mak fi -if test "$attralias" = "yes" ; then - echo "CONFIG_ATTRIBUTE_ALIAS=y" >> $config_host_mak -fi - if test "$getauxval" = "yes" ; then echo "CONFIG_GETAUXVAL=y" >> $config_host_mak fi diff --git a/exec-vary.c b/exec-vary.c deleted file mode 100644 index a603b1b433..0000000000 --- a/exec-vary.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Variable page size handling - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" - -#define IN_EXEC_VARY 1 - -#include "exec/exec-all.h" - -#ifdef TARGET_PAGE_BITS_VARY -# ifdef CONFIG_ATTRIBUTE_ALIAS -/* - * We want to declare the "target_page" variable as const, which tells - * the compiler that it can cache any value that it reads across calls. - * This avoids multiple assertions and multiple reads within any one user. - * - * This works because we finish initializing the data before we ever read - * from the "target_page" symbol. - * - * This also requires that we have a non-constant symbol by which we can - * perform the actual initialization, and which forces the data to be - * allocated within writable memory. Thus "init_target_page", and we use - * that symbol exclusively in the two functions that initialize this value. - * - * The "target_page" symbol is created as an alias of "init_target_page". - */ -static TargetPageBits init_target_page; - -/* - * Note that this is *not* a redundant decl, this is the definition of - * the "target_page" symbol. The syntax for this definition requires - * the use of the extern keyword. This seems to be a GCC bug in - * either the syntax for the alias attribute or in -Wredundant-decls. - * - * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91765 - */ -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wredundant-decls" - -extern const TargetPageBits target_page - __attribute__((alias("init_target_page"))); - -# pragma GCC diagnostic pop -# else -/* - * When aliases are not supported then we force two different declarations, - * by way of suppressing the header declaration with IN_EXEC_VARY. - * We assume that on such an old compiler, LTO cannot be used, and so the - * compiler cannot not detect the mismatched declarations, and all is well. - */ -TargetPageBits target_page; -# define init_target_page target_page -# endif -#endif - -bool set_preferred_target_page_bits(int bits) -{ - /* - * The target page size is the lowest common denominator for all - * the CPUs in the system, so we can only make it smaller, never - * larger. And we can't make it smaller once we've committed to - * a particular size. - */ -#ifdef TARGET_PAGE_BITS_VARY - assert(bits >= TARGET_PAGE_BITS_MIN); - if (init_target_page.bits == 0 || init_target_page.bits > bits) { - if (init_target_page.decided) { - return false; - } - init_target_page.bits = bits; - } -#endif - return true; -} - -void finalize_target_page_bits(void) -{ -#ifdef TARGET_PAGE_BITS_VARY - if (init_target_page.bits == 0) { - init_target_page.bits = TARGET_PAGE_BITS_MIN; - } - init_target_page.mask = (target_long)-1 << init_target_page.bits; - init_target_page.decided = true; - - /* - * For the benefit of an -flto build, prevent the compiler from - * hoisting a read from target_page before we finish initializing. - */ - barrier(); -#endif -} diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 76443eb11d..d76b0b9e02 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -215,22 +215,15 @@ static inline void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val /* page related stuff */ #ifdef TARGET_PAGE_BITS_VARY -typedef struct { - bool decided; - int bits; - target_long mask; -} TargetPageBits; -#if defined(CONFIG_ATTRIBUTE_ALIAS) || !defined(IN_EXEC_VARY) +# include "exec/page-vary.h" extern const TargetPageBits target_page; -#else -extern TargetPageBits target_page; -#endif #ifdef CONFIG_DEBUG_TCG #define TARGET_PAGE_BITS ({ assert(target_page.decided); target_page.bits; }) -#define TARGET_PAGE_MASK ({ assert(target_page.decided); target_page.mask; }) +#define TARGET_PAGE_MASK ({ assert(target_page.decided); \ + (target_long)target_page.mask; }) #else #define TARGET_PAGE_BITS target_page.bits -#define TARGET_PAGE_MASK target_page.mask +#define TARGET_PAGE_MASK ((target_long)target_page.mask) #endif #define TARGET_PAGE_SIZE (-(int)TARGET_PAGE_MASK) #else diff --git a/include/exec/page-vary.h b/include/exec/page-vary.h new file mode 100644 index 0000000000..c22a7a742e --- /dev/null +++ b/include/exec/page-vary.h @@ -0,0 +1,34 @@ +/* + * Definitions for cpus with variable page sizes. + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef EXEC_PAGE_VARY_H +#define EXEC_PAGE_VARY_H + +typedef struct { + bool decided; + int bits; + uint64_t mask; +} TargetPageBits; + +#ifdef IN_PAGE_VARY +extern bool set_preferred_target_page_bits_common(int bits); +extern void finalize_target_page_bits_common(int min); +#endif + +#endif /* EXEC_PAGE_VARY_H */ diff --git a/meson.build b/meson.build index 5c85a15364..c6f4b0cf5e 100644 --- a/meson.build +++ b/meson.build @@ -1933,7 +1933,6 @@ subdir('softmmu') common_ss.add(capstone) specific_ss.add(files('cpu.c', 'disas.c', 'gdbstub.c'), capstone) -specific_ss.add(files('exec-vary.c')) specific_ss.add(when: 'CONFIG_TCG', if_true: files( 'fpu/softfloat.c', 'tcg/optimize.c', @@ -1945,6 +1944,26 @@ specific_ss.add(when: 'CONFIG_TCG', if_true: files( )) specific_ss.add(when: 'CONFIG_TCG_INTERPRETER', if_true: files('tcg/tci.c')) +# Work around a gcc bug/misfeature wherein constant propagation looks +# through an alias: +# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99696 +# to guess that a const variable is always zero. Without lto, this is +# impossible, as the alias is restricted to page-vary-common.c. Indeed, +# without lto, not even the alias is required -- we simply use different +# declarations in different compilation units. +pagevary = files('page-vary-common.c') +if get_option('b_lto') + pagevary_flags = ['-fno-lto'] + if get_option('cfi') + pagevary_flags += '-fno-sanitize=cfi-icall' + endif + pagevary = static_library('page-vary-common', sources: pagevary, + c_args: pagevary_flags) + pagevary = declare_dependency(link_with: pagevary) +endif +common_ss.add(pagevary) +specific_ss.add(files('page-vary.c')) + subdir('backends') subdir('disas') subdir('migration') diff --git a/page-vary-common.c b/page-vary-common.c new file mode 100644 index 0000000000..9175556498 --- /dev/null +++ b/page-vary-common.c @@ -0,0 +1,54 @@ +/* + * Variable page size handling -- target independent part. + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#define IN_PAGE_VARY 1 + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "exec/page-vary.h" + +/* WARNING: This file must *not* be complied with -flto. */ + +TargetPageBits target_page; + +bool set_preferred_target_page_bits_common(int bits) +{ + /* + * The target page size is the lowest common denominator for all + * the CPUs in the system, so we can only make it smaller, never + * larger. And we can't make it smaller once we've committed to + * a particular size. + */ + if (target_page.bits == 0 || target_page.bits > bits) { + if (target_page.decided) { + return false; + } + target_page.bits = bits; + } + return true; +} + +void finalize_target_page_bits_common(int min) +{ + if (target_page.bits == 0) { + target_page.bits = min; + } + target_page.mask = -1ull << target_page.bits; + target_page.decided = true; +} diff --git a/page-vary.c b/page-vary.c new file mode 100644 index 0000000000..057c7f1815 --- /dev/null +++ b/page-vary.c @@ -0,0 +1,41 @@ +/* + * Variable page size handling -- target specific part. + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#define IN_PAGE_VARY 1 + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "exec/exec-all.h" + +bool set_preferred_target_page_bits(int bits) +{ +#ifdef TARGET_PAGE_BITS_VARY + assert(bits >= TARGET_PAGE_BITS_MIN); + return set_preferred_target_page_bits_common(bits); +#else + return true; +#endif +} + +void finalize_target_page_bits(void) +{ +#ifdef TARGET_PAGE_BITS_VARY + finalize_target_page_bits_common(TARGET_PAGE_BITS_MIN); +#endif +} @@ -828,7 +828,6 @@ void tcg_region_init(void) size_t region_size; size_t n_regions; size_t i; - uintptr_t splitwx_diff; n_regions = tcg_n_regions(); @@ -858,19 +857,22 @@ void tcg_region_init(void) /* account for that last guard page */ region.end -= page_size; - /* set guard pages */ - splitwx_diff = tcg_splitwx_diff; + /* + * Set guard pages in the rw buffer, as that's the one into which + * buffer overruns could occur. Do not set guard pages in the rx + * buffer -- let that one use hugepages throughout. + */ for (i = 0; i < region.n; i++) { void *start, *end; - int rc; tcg_region_bounds(i, &start, &end); - rc = qemu_mprotect_none(end, page_size); - g_assert(!rc); - if (splitwx_diff) { - rc = qemu_mprotect_none(end + splitwx_diff, page_size); - g_assert(!rc); - } + + /* + * macOS 11.2 has a bug (Apple Feedback FB8994773) in which mprotect + * rejects a permission change from RWX -> NONE. Guard pages are + * nice for bug detection but are not essential; ignore any failure. + */ + (void)qemu_mprotect_none(end, page_size); } tcg_region_trees_init(); |