diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2016-10-24 16:26:49 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2016-10-24 16:26:49 +0100 |
commit | 20bccb82ff3ea09bcb7c4ee226d3160cab15f7da (patch) | |
tree | beb472fa034fe9e742c571f678982235695f29eb /exec.c | |
parent | 66ec9f49399f0a9fa13ee77c472caba0de2773fc (diff) |
cpu: Support a target CPU having a variable page size
Support target CPUs having a page size which isn't knownn
at compile time. To use this, the CPU implementation should:
* define TARGET_PAGE_BITS_VARY
* not define TARGET_PAGE_BITS
* define TARGET_PAGE_BITS_MIN to the smallest value it
might possibly want for TARGET_PAGE_BITS
* call set_preferred_target_page_bits() in its realize
function to indicate the actual preferred target page
size for the CPU (and report any error from it)
In CONFIG_USER_ONLY, the CPU implementation should continue
to define TARGET_PAGE_BITS appropriately for the guest
OS page size.
Machines which want to take advantage of having the page
size something larger than TARGET_PAGE_BITS_MIN must
set the MachineClass minimum_page_bits field to a value
which they guarantee will be no greater than the preferred
page size for any CPU they create.
Note that changing the target page size by setting
minimum_page_bits is a migration compatibility break
for that machine.
For debugging purposes, attempts to use TARGET_PAGE_SIZE
before it has been finally confirmed will assert.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
Diffstat (limited to 'exec.c')
-rw-r--r-- | exec.c | 42 |
1 files changed, 42 insertions, 0 deletions
@@ -93,6 +93,11 @@ static MemoryRegion io_mem_unassigned; #endif +#ifdef TARGET_PAGE_BITS_VARY +int target_page_bits; +bool target_page_bits_decided; +#endif + struct CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus); /* current CPU in the current thread. It is only valid inside cpu_exec() */ @@ -102,8 +107,37 @@ __thread CPUState *current_cpu; 2 = Adaptive rate instruction counting. */ int use_icount; +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 (target_page_bits == 0 || target_page_bits > bits) { + if (target_page_bits_decided) { + return false; + } + target_page_bits = bits; + } +#endif + return true; +} + #if !defined(CONFIG_USER_ONLY) +static void finalize_target_page_bits(void) +{ +#ifdef TARGET_PAGE_BITS_VARY + if (target_page_bits == 0) { + target_page_bits = TARGET_PAGE_BITS_MIN; + } + target_page_bits_decided = true; +#endif +} + typedef struct PhysPageEntry PhysPageEntry; struct PhysPageEntry { @@ -2807,6 +2841,14 @@ void cpu_register_map_client(QEMUBH *bh) void cpu_exec_init_all(void) { qemu_mutex_init(&ram_list.mutex); + /* The data structures we set up here depend on knowing the page size, + * so no more changes can be made after this point. + * In an ideal world, nothing we did before we had finished the + * machine setup would care about the target page size, and we could + * do this much later, rather than requiring board models to state + * up front what their requirements are. + */ + finalize_target_page_bits(); io_mem_init(); memory_map_init(); qemu_mutex_init(&map_client_list_lock); |