diff --git a/include/uc_priv.h b/include/uc_priv.h index 95652628..25a05c4a 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -184,6 +184,9 @@ struct uc_struct { RAMList ram_list; // Renamed from "alloc_hint" in qemu. unsigned phys_map_node_alloc_hint; + // Used when a target's page bits can vary + int target_page_bits; + bool target_page_bits_decided; // qemu/cpu-exec.c BounceBuffer bounce; diff --git a/qemu/aarch64.h b/qemu/aarch64.h index 51fd70a5..fd494689 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -2585,6 +2585,7 @@ #define set_float_rounding_mode set_float_rounding_mode_aarch64 #define set_flush_inputs_to_zero set_flush_inputs_to_zero_aarch64 #define set_flush_to_zero set_flush_to_zero_aarch64 +#define set_preferred_target_page_bits set_preferred_target_page_bits_aarch64 #define set_swi_errno set_swi_errno_aarch64 #define sextract32 sextract32_aarch64 #define sextract64 sextract64_aarch64 diff --git a/qemu/aarch64eb.h b/qemu/aarch64eb.h index ee71d352..ed84c712 100644 --- a/qemu/aarch64eb.h +++ b/qemu/aarch64eb.h @@ -2585,6 +2585,7 @@ #define set_float_rounding_mode set_float_rounding_mode_aarch64eb #define set_flush_inputs_to_zero set_flush_inputs_to_zero_aarch64eb #define set_flush_to_zero set_flush_to_zero_aarch64eb +#define set_preferred_target_page_bits set_preferred_target_page_bits_aarch64eb #define set_swi_errno set_swi_errno_aarch64eb #define sextract32 sextract32_aarch64eb #define sextract64 sextract64_aarch64eb diff --git a/qemu/arm.h b/qemu/arm.h index afd21237..8e4098c4 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -2585,6 +2585,7 @@ #define set_float_rounding_mode set_float_rounding_mode_arm #define set_flush_inputs_to_zero set_flush_inputs_to_zero_arm #define set_flush_to_zero set_flush_to_zero_arm +#define set_preferred_target_page_bits set_preferred_target_page_bits_arm #define set_swi_errno set_swi_errno_arm #define sextract32 sextract32_arm #define sextract64 sextract64_arm diff --git a/qemu/armeb.h b/qemu/armeb.h index c0d9f1cb..3e17c731 100644 --- a/qemu/armeb.h +++ b/qemu/armeb.h @@ -2585,6 +2585,7 @@ #define set_float_rounding_mode set_float_rounding_mode_armeb #define set_flush_inputs_to_zero set_flush_inputs_to_zero_armeb #define set_flush_to_zero set_flush_to_zero_armeb +#define set_preferred_target_page_bits set_preferred_target_page_bits_armeb #define set_swi_errno set_swi_errno_armeb #define sextract32 sextract32_armeb #define sextract64 sextract64_armeb diff --git a/qemu/exec.c b/qemu/exec.c index 1bbddbb6..7ec7c609 100644 --- a/qemu/exec.c +++ b/qemu/exec.c @@ -68,11 +68,40 @@ #endif +bool set_preferred_target_page_bits(struct uc_struct *uc, 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 (uc->target_page_bits == 0 || uc->target_page_bits > bits) { + if (uc->target_page_bits_decided) { + return false; + } + uc->target_page_bits = bits; + } +#endif + return true; +} + #if !defined(CONFIG_USER_ONLY) /* current CPU in the current thread. It is only valid inside cpu_exec() */ //DEFINE_TLS(CPUState *, current_cpu); +static void finalize_target_page_bits(struct uc_struct *uc) +{ +#ifdef TARGET_PAGE_BITS_VARY + if (uc->target_page_bits == 0) { + uc->target_page_bits = TARGET_PAGE_BITS_MIN; + } + uc->target_page_bits_decided = true; +#endif +} + typedef struct PhysPageEntry PhysPageEntry; struct PhysPageEntry { @@ -1826,6 +1855,14 @@ static void memory_map_init(struct uc_struct *uc) void cpu_exec_init_all(struct uc_struct *uc) { + /* 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(uc); io_mem_init(uc); #if !defined(CONFIG_USER_ONLY) memory_map_init(uc); diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 6a1379f6..29a83e9d 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -2591,6 +2591,7 @@ symbols = ( 'set_float_rounding_mode', 'set_flush_inputs_to_zero', 'set_flush_to_zero', + 'set_preferred_target_page_bits', 'set_swi_errno', 'sextract32', 'sextract64', diff --git a/qemu/include/exec/cpu-all.h b/qemu/include/exec/cpu-all.h index 53ad7cdf..f14b2caa 100644 --- a/qemu/include/exec/cpu-all.h +++ b/qemu/include/exec/cpu-all.h @@ -230,6 +230,13 @@ void address_space_stq(AddressSpace *as, hwaddr addr, uint64_t val, /* page related stuff */ +#ifdef TARGET_PAGE_BITS_VARY +#define TARGET_PAGE_BITS ({ assert(target_page_bits_decided); \ + target_page_bits; }) +#else +#define TARGET_PAGE_BITS_MIN TARGET_PAGE_BITS +#endif + #define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS) #define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1) #define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK) diff --git a/qemu/include/hw/boards.h b/qemu/include/hw/boards.h index 786a4ba2..a9471a25 100644 --- a/qemu/include/hw/boards.h +++ b/qemu/include/hw/boards.h @@ -22,6 +22,7 @@ struct QEMUMachine { int max_cpus; int is_default; int arch; + int minimum_page_bits; }; void memory_region_allocate_system_memory(MemoryRegion *mr, Object *owner, @@ -46,6 +47,12 @@ MachineClass *find_default_machine(struct uc_struct *uc, int arch); /** * MachineClass: * @qemu_machine: #QEMUMachine + * @minimum_page_bits: + * If non-zero, the board promises never to create a CPU with a page size + * smaller than this, so QEMU can use a more efficient larger page + * size than the target architecture's minimum. (Attempting to create + * such a CPU will fail.) Note that changing this is a migration + * compatibility break for the machine. */ struct MachineClass { /*< private >*/ @@ -61,6 +68,7 @@ struct MachineClass { int max_cpus; int is_default; int arch; + int minimum_page_bits; }; /** diff --git a/qemu/include/qemu-common.h b/qemu/include/qemu-common.h index ef9cce3d..3209ea1a 100644 --- a/qemu/include/qemu-common.h +++ b/qemu/include/qemu-common.h @@ -66,6 +66,18 @@ bool tcg_enabled(struct uc_struct *uc); struct uc_struct; void cpu_exec_init_all(struct uc_struct *uc); +/** + * set_preferred_target_page_bits: + * @bits: number of bits needed to represent an address within the page + * + * Set the preferred target page size (the actual target page + * size may be smaller than any given CPU's preference). + * Returns true on success, false on failure (which can only happen + * if this is called after the system has already finalized its + * choice of page size and the requested page size is smaller than that). + */ +bool set_preferred_target_page_bits(struct uc_struct *uc, int bits); + #include "qemu/module.h" // support for calling functions before main code is executed. diff --git a/qemu/m68k.h b/qemu/m68k.h index c1c28369..6cb71dfc 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -2585,6 +2585,7 @@ #define set_float_rounding_mode set_float_rounding_mode_m68k #define set_flush_inputs_to_zero set_flush_inputs_to_zero_m68k #define set_flush_to_zero set_flush_to_zero_m68k +#define set_preferred_target_page_bits set_preferred_target_page_bits_m68k #define set_swi_errno set_swi_errno_m68k #define sextract32 sextract32_m68k #define sextract64 sextract64_m68k diff --git a/qemu/mips.h b/qemu/mips.h index d2cebfb5..4c02f55b 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -2585,6 +2585,7 @@ #define set_float_rounding_mode set_float_rounding_mode_mips #define set_flush_inputs_to_zero set_flush_inputs_to_zero_mips #define set_flush_to_zero set_flush_to_zero_mips +#define set_preferred_target_page_bits set_preferred_target_page_bits_mips #define set_swi_errno set_swi_errno_mips #define sextract32 sextract32_mips #define sextract64 sextract64_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index 5996afde..e324b58b 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -2585,6 +2585,7 @@ #define set_float_rounding_mode set_float_rounding_mode_mips64 #define set_flush_inputs_to_zero set_flush_inputs_to_zero_mips64 #define set_flush_to_zero set_flush_to_zero_mips64 +#define set_preferred_target_page_bits set_preferred_target_page_bits_mips64 #define set_swi_errno set_swi_errno_mips64 #define sextract32 sextract32_mips64 #define sextract64 sextract64_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index b5785f5f..5083b087 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -2585,6 +2585,7 @@ #define set_float_rounding_mode set_float_rounding_mode_mips64el #define set_flush_inputs_to_zero set_flush_inputs_to_zero_mips64el #define set_flush_to_zero set_flush_to_zero_mips64el +#define set_preferred_target_page_bits set_preferred_target_page_bits_mips64el #define set_swi_errno set_swi_errno_mips64el #define sextract32 sextract32_mips64el #define sextract64 sextract64_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index f3f7dbd6..e4757b0c 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -2585,6 +2585,7 @@ #define set_float_rounding_mode set_float_rounding_mode_mipsel #define set_flush_inputs_to_zero set_flush_inputs_to_zero_mipsel #define set_flush_to_zero set_flush_to_zero_mipsel +#define set_preferred_target_page_bits set_preferred_target_page_bits_mipsel #define set_swi_errno set_swi_errno_mipsel #define sextract32 sextract32_mipsel #define sextract64 sextract64_mipsel diff --git a/qemu/powerpc.h b/qemu/powerpc.h index 10f51a14..68359243 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -2585,6 +2585,7 @@ #define set_float_rounding_mode set_float_rounding_mode_powerpc #define set_flush_inputs_to_zero set_flush_inputs_to_zero_powerpc #define set_flush_to_zero set_flush_to_zero_powerpc +#define set_preferred_target_page_bits set_preferred_target_page_bits_powerpc #define set_swi_errno set_swi_errno_powerpc #define sextract32 sextract32_powerpc #define sextract64 sextract64_powerpc diff --git a/qemu/sparc.h b/qemu/sparc.h index 41758a6c..ec4b83ec 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -2585,6 +2585,7 @@ #define set_float_rounding_mode set_float_rounding_mode_sparc #define set_flush_inputs_to_zero set_flush_inputs_to_zero_sparc #define set_flush_to_zero set_flush_to_zero_sparc +#define set_preferred_target_page_bits set_preferred_target_page_bits_sparc #define set_swi_errno set_swi_errno_sparc #define sextract32 sextract32_sparc #define sextract64 sextract64_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index fdcee3f3..82ad790c 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -2585,6 +2585,7 @@ #define set_float_rounding_mode set_float_rounding_mode_sparc64 #define set_flush_inputs_to_zero set_flush_inputs_to_zero_sparc64 #define set_flush_to_zero set_flush_to_zero_sparc64 +#define set_preferred_target_page_bits set_preferred_target_page_bits_sparc64 #define set_swi_errno set_swi_errno_sparc64 #define sextract32 sextract32_sparc64 #define sextract64 sextract64_sparc64 diff --git a/qemu/vl.c b/qemu/vl.c index d1187d40..fec0308b 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -136,6 +136,20 @@ int machine_initialize(struct uc_struct *uc) OBJECT_CLASS(machine_class)))); uc->machine_state = current_machine; current_machine->uc = uc; + + // Unicorn: FIXME: this should be uncommented + // However due to the "stellar" way unicorn + // handles multiple targets (e.g. the YOLO + // Python script named header_gen.py), this + // results in a compilation error. + //if (machine_class->minimum_page_bits) { + // if (!set_preferred_target_page_bits(uc, machine_class->minimum_page_bits)) { + // /* This would be a board error: specifying a minimum smaller than + // * a target's compile-time fixed setting. + // */ + // g_assert_not_reached(); + // } + //} uc->cpu_exec_init_all(uc); machine_class->max_cpus = 1; @@ -168,6 +182,7 @@ static void machine_class_init(struct uc_struct *uc, ObjectClass *oc, void *data mc->max_cpus = qm->max_cpus; mc->is_default = qm->is_default; mc->arch = qm->arch; + mc->minimum_page_bits = qm->minimum_page_bits; } void qemu_register_machine(struct uc_struct *uc, QEMUMachine *m, const char *type_machine, diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 1d27d4eb..bbeb1f2b 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -2585,6 +2585,7 @@ #define set_float_rounding_mode set_float_rounding_mode_x86_64 #define set_flush_inputs_to_zero set_flush_inputs_to_zero_x86_64 #define set_flush_to_zero set_flush_to_zero_x86_64 +#define set_preferred_target_page_bits set_preferred_target_page_bits_x86_64 #define set_swi_errno set_swi_errno_x86_64 #define sextract32 sextract32_x86_64 #define sextract64 sextract64_x86_64