@ -19,11 +19,55 @@
# include "qemu/osdep.h"
# include "qemu-common.h"
# define IN_EXEC_VARY 1
# include "exec/exec-all.h"
# ifdef TARGET_PAGE_BITS_VARY
int target_page_bits ;
bool target_page_bits_decided ;
# 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 )
@ -36,11 +80,11 @@ bool set_preferred_target_page_bits(int bits)
*/
# ifdef TARGET_PAGE_BITS_VARY
assert ( bits > = TARGET_PAGE_BITS_MIN ) ;
if ( target_page_ bits = = 0 | | target_page_ bits > bits ) {
if ( target_page_bits_ decided) {
if ( init_target_page . bits = = 0 | | init_target_page . bits > bits ) {
if ( init_target_page . decided ) {
return false ;
}
target_page_ bits = bits ;
init_target_page . bits = bits ;
}
# endif
return true ;
@ -49,9 +93,15 @@ bool set_preferred_target_page_bits(int bits)
void finalize_target_page_bits ( void )
{
# ifdef TARGET_PAGE_BITS_VARY
if ( target_page_ bits = = 0 ) {
target_page_ bits = TARGET_PAGE_BITS_MIN ;
if ( init_target_page . bits = = 0 ) {
init_target_page . bits = TARGET_PAGE_BITS_MIN ;
}
target_page_bits_decided = true ;
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
}