Richard Henderson | 7886cef | 2019-09-19 13:30:29 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Variable page size handling |
| 3 | * |
| 4 | * Copyright (c) 2003 Fabrice Bellard |
| 5 | * |
| 6 | * This library is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU Lesser General Public |
| 8 | * License as published by the Free Software Foundation; either |
Chetan Pant | 61f3c91 | 2020-10-23 12:44:24 +0000 | [diff] [blame] | 9 | * version 2.1 of the License, or (at your option) any later version. |
Richard Henderson | 7886cef | 2019-09-19 13:30:29 -0700 | [diff] [blame] | 10 | * |
| 11 | * This library is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | * Lesser General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU Lesser General Public |
| 17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
| 18 | */ |
| 19 | |
| 20 | #include "qemu/osdep.h" |
| 21 | #include "qemu-common.h" |
Richard Henderson | bbc17ca | 2019-09-13 11:21:53 -0400 | [diff] [blame] | 22 | |
| 23 | #define IN_EXEC_VARY 1 |
| 24 | |
Richard Henderson | 7886cef | 2019-09-19 13:30:29 -0700 | [diff] [blame] | 25 | #include "exec/exec-all.h" |
| 26 | |
| 27 | #ifdef TARGET_PAGE_BITS_VARY |
Richard Henderson | bbc17ca | 2019-09-13 11:21:53 -0400 | [diff] [blame] | 28 | # ifdef CONFIG_ATTRIBUTE_ALIAS |
| 29 | /* |
| 30 | * We want to declare the "target_page" variable as const, which tells |
| 31 | * the compiler that it can cache any value that it reads across calls. |
| 32 | * This avoids multiple assertions and multiple reads within any one user. |
| 33 | * |
| 34 | * This works because we finish initializing the data before we ever read |
| 35 | * from the "target_page" symbol. |
| 36 | * |
| 37 | * This also requires that we have a non-constant symbol by which we can |
| 38 | * perform the actual initialization, and which forces the data to be |
| 39 | * allocated within writable memory. Thus "init_target_page", and we use |
| 40 | * that symbol exclusively in the two functions that initialize this value. |
| 41 | * |
| 42 | * The "target_page" symbol is created as an alias of "init_target_page". |
| 43 | */ |
| 44 | static TargetPageBits init_target_page; |
| 45 | |
| 46 | /* |
| 47 | * Note that this is *not* a redundant decl, this is the definition of |
| 48 | * the "target_page" symbol. The syntax for this definition requires |
| 49 | * the use of the extern keyword. This seems to be a GCC bug in |
| 50 | * either the syntax for the alias attribute or in -Wredundant-decls. |
| 51 | * |
| 52 | * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91765 |
| 53 | */ |
| 54 | # pragma GCC diagnostic push |
| 55 | # pragma GCC diagnostic ignored "-Wredundant-decls" |
| 56 | |
| 57 | extern const TargetPageBits target_page |
| 58 | __attribute__((alias("init_target_page"))); |
| 59 | |
| 60 | # pragma GCC diagnostic pop |
| 61 | # else |
| 62 | /* |
| 63 | * When aliases are not supported then we force two different declarations, |
| 64 | * by way of suppressing the header declaration with IN_EXEC_VARY. |
| 65 | * We assume that on such an old compiler, LTO cannot be used, and so the |
| 66 | * compiler cannot not detect the mismatched declarations, and all is well. |
| 67 | */ |
| 68 | TargetPageBits target_page; |
| 69 | # define init_target_page target_page |
| 70 | # endif |
Richard Henderson | 7886cef | 2019-09-19 13:30:29 -0700 | [diff] [blame] | 71 | #endif |
| 72 | |
| 73 | bool set_preferred_target_page_bits(int bits) |
| 74 | { |
| 75 | /* |
| 76 | * The target page size is the lowest common denominator for all |
| 77 | * the CPUs in the system, so we can only make it smaller, never |
| 78 | * larger. And we can't make it smaller once we've committed to |
| 79 | * a particular size. |
| 80 | */ |
| 81 | #ifdef TARGET_PAGE_BITS_VARY |
| 82 | assert(bits >= TARGET_PAGE_BITS_MIN); |
Richard Henderson | bbc17ca | 2019-09-13 11:21:53 -0400 | [diff] [blame] | 83 | if (init_target_page.bits == 0 || init_target_page.bits > bits) { |
| 84 | if (init_target_page.decided) { |
Richard Henderson | 7886cef | 2019-09-19 13:30:29 -0700 | [diff] [blame] | 85 | return false; |
| 86 | } |
Richard Henderson | bbc17ca | 2019-09-13 11:21:53 -0400 | [diff] [blame] | 87 | init_target_page.bits = bits; |
Richard Henderson | 7886cef | 2019-09-19 13:30:29 -0700 | [diff] [blame] | 88 | } |
| 89 | #endif |
| 90 | return true; |
| 91 | } |
| 92 | |
| 93 | void finalize_target_page_bits(void) |
| 94 | { |
| 95 | #ifdef TARGET_PAGE_BITS_VARY |
Richard Henderson | bbc17ca | 2019-09-13 11:21:53 -0400 | [diff] [blame] | 96 | if (init_target_page.bits == 0) { |
| 97 | init_target_page.bits = TARGET_PAGE_BITS_MIN; |
Richard Henderson | 7886cef | 2019-09-19 13:30:29 -0700 | [diff] [blame] | 98 | } |
Richard Henderson | bb8e3ea | 2019-09-13 12:07:40 -0400 | [diff] [blame] | 99 | init_target_page.mask = (target_long)-1 << init_target_page.bits; |
Richard Henderson | bbc17ca | 2019-09-13 11:21:53 -0400 | [diff] [blame] | 100 | init_target_page.decided = true; |
| 101 | |
| 102 | /* |
| 103 | * For the benefit of an -flto build, prevent the compiler from |
| 104 | * hoisting a read from target_page before we finish initializing. |
| 105 | */ |
| 106 | barrier(); |
Richard Henderson | 7886cef | 2019-09-19 13:30:29 -0700 | [diff] [blame] | 107 | #endif |
| 108 | } |