aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accel/tcg/translate-all.c1
-rw-r--r--bsd-user/main.c48
-rw-r--r--bsd-user/mmap.c3
-rw-r--r--linux-user/arm/cpu_loop.c9
-rw-r--r--target/ppc/translate.c3
-rw-r--r--target/s390x/tcg/excp_helper.c40
-rw-r--r--util/interval-tree.c79
7 files changed, 132 insertions, 51 deletions
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index a1782db5dd..b2d4e22c17 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -374,6 +374,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
"Restarting code generation for "
"code_gen_buffer overflow\n");
tb_unlock_pages(tb);
+ tcg_ctx->gen_tb = NULL;
goto buffer_overflow;
case -2:
diff --git a/bsd-user/main.c b/bsd-user/main.c
index b597328118..381bb18df8 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -473,10 +473,6 @@ int main(int argc, char **argv)
target_environ = envlist_to_environ(envlist, NULL);
envlist_free(envlist);
- if (reserved_va) {
- mmap_next_start = reserved_va + 1;
- }
-
{
Error *err = NULL;
if (seed_optarg != NULL) {
@@ -494,7 +490,49 @@ int main(int argc, char **argv)
* Now that page sizes are configured we can do
* proper page alignment for guest_base.
*/
- guest_base = HOST_PAGE_ALIGN(guest_base);
+ if (have_guest_base) {
+ if (guest_base & ~qemu_host_page_mask) {
+ error_report("Selected guest base not host page aligned");
+ exit(1);
+ }
+ }
+
+ /*
+ * If reserving host virtual address space, do so now.
+ * Combined with '-B', ensure that the chosen range is free.
+ */
+ if (reserved_va) {
+ void *p;
+
+ if (have_guest_base) {
+ p = mmap((void *)guest_base, reserved_va + 1, PROT_NONE,
+ MAP_ANON | MAP_PRIVATE | MAP_FIXED | MAP_EXCL, -1, 0);
+ } else {
+ p = mmap(NULL, reserved_va + 1, PROT_NONE,
+ MAP_ANON | MAP_PRIVATE, -1, 0);
+ }
+ if (p == MAP_FAILED) {
+ const char *err = strerror(errno);
+ char *sz = size_to_str(reserved_va + 1);
+
+ if (have_guest_base) {
+ error_report("Cannot allocate %s bytes at -B %p for guest "
+ "address space: %s", sz, (void *)guest_base, err);
+ } else {
+ error_report("Cannot allocate %s bytes for guest "
+ "address space: %s", sz, err);
+ }
+ exit(1);
+ }
+ guest_base = (uintptr_t)p;
+ have_guest_base = true;
+
+ /* Ensure that mmap_next_start is within range. */
+ if (reserved_va <= mmap_next_start) {
+ mmap_next_start = (reserved_va / 4 * 3)
+ & TARGET_PAGE_MASK & qemu_host_page_mask;
+ }
+ }
if (loader_exec(filename, argv + optind, target_environ, regs, info,
&bprm) != 0) {
diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c
index 74ed00b9fe..b62a69bd07 100644
--- a/bsd-user/mmap.c
+++ b/bsd-user/mmap.c
@@ -260,7 +260,8 @@ static abi_ulong mmap_find_vma_aligned(abi_ulong start, abi_ulong size,
if (reserved_va) {
return mmap_find_vma_reserved(start, size,
- (alignment != 0 ? 1 << alignment : 0));
+ (alignment != 0 ? 1 << alignment :
+ MAX(qemu_host_page_size, TARGET_PAGE_SIZE)));
}
addr = start;
diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c
index a992423257..b404117ff3 100644
--- a/linux-user/arm/cpu_loop.c
+++ b/linux-user/arm/cpu_loop.c
@@ -117,8 +117,9 @@ static void arm_kernel_cmpxchg32_helper(CPUARMState *env)
{
uint32_t oldval, newval, val, addr, cpsr, *host_addr;
- oldval = env->regs[0];
- newval = env->regs[1];
+ /* Swap if host != guest endianness, for the host cmpxchg below */
+ oldval = tswap32(env->regs[0]);
+ newval = tswap32(env->regs[1]);
addr = env->regs[2];
mmap_lock();
@@ -174,6 +175,10 @@ static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
return;
}
+ /* Swap if host != guest endianness, for the host cmpxchg below */
+ oldval = tswap64(oldval);
+ newval = tswap64(newval);
+
#ifdef CONFIG_ATOMIC64
val = qatomic_cmpxchg__nocheck(host_addr, oldval, newval);
cpsr = (val == oldval) * CPSR_C;
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index e6a0709066..74796ec7ba 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -4175,6 +4175,9 @@ static void pmu_count_insns(DisasContext *ctx)
static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest)
{
+ if (unlikely(ctx->singlestep_enabled)) {
+ return false;
+ }
return translator_use_goto_tb(&ctx->base, dest);
}
diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c
index 3da337f7c7..b7116d0577 100644
--- a/target/s390x/tcg/excp_helper.c
+++ b/target/s390x/tcg/excp_helper.c
@@ -190,11 +190,6 @@ bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
return false;
}
- if (excp != PGM_ADDRESSING) {
- stq_phys(env_cpu(env)->as,
- env->psa + offsetof(LowCore, trans_exc_code), tec);
- }
-
/*
* For data accesses, ILEN will be filled in from the unwind info,
* within cpu_loop_exit_restore. For code accesses, retaddr == 0,
@@ -211,20 +206,33 @@ static void do_program_interrupt(CPUS390XState *env)
uint64_t mask, addr;
LowCore *lowcore;
int ilen = env->int_pgm_ilen;
+ bool set_trans_exc_code = false;
+ bool advance = false;
assert((env->int_pgm_code == PGM_SPECIFICATION && ilen == 0) ||
ilen == 2 || ilen == 4 || ilen == 6);
switch (env->int_pgm_code) {
case PGM_PER:
- if (env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION) {
- break;
- }
- /* FALL THROUGH */
+ advance = !(env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION);
+ break;
+ case PGM_ASCE_TYPE:
+ case PGM_REG_FIRST_TRANS:
+ case PGM_REG_SEC_TRANS:
+ case PGM_REG_THIRD_TRANS:
+ case PGM_SEGMENT_TRANS:
+ case PGM_PAGE_TRANS:
+ assert(env->int_pgm_code == env->tlb_fill_exc);
+ set_trans_exc_code = true;
+ break;
+ case PGM_PROTECTION:
+ assert(env->int_pgm_code == env->tlb_fill_exc);
+ set_trans_exc_code = true;
+ advance = true;
+ break;
case PGM_OPERATION:
case PGM_PRIVILEGED:
case PGM_EXECUTE:
- case PGM_PROTECTION:
case PGM_ADDRESSING:
case PGM_SPECIFICATION:
case PGM_DATA:
@@ -243,11 +251,15 @@ static void do_program_interrupt(CPUS390XState *env)
case PGM_PC_TRANS_SPEC:
case PGM_ALET_SPEC:
case PGM_MONITOR:
- /* advance the PSW if our exception is not nullifying */
- env->psw.addr += ilen;
+ advance = true;
break;
}
+ /* advance the PSW if our exception is not nullifying */
+ if (advance) {
+ env->psw.addr += ilen;
+ }
+
qemu_log_mask(CPU_LOG_INT,
"%s: code=0x%x ilen=%d psw: %" PRIx64 " %" PRIx64 "\n",
__func__, env->int_pgm_code, ilen, env->psw.mask,
@@ -263,6 +275,10 @@ static void do_program_interrupt(CPUS390XState *env)
env->per_perc_atmid = 0;
}
+ if (set_trans_exc_code) {
+ lowcore->trans_exc_code = cpu_to_be64(env->tlb_fill_tec);
+ }
+
lowcore->pgm_ilen = cpu_to_be16(ilen);
lowcore->pgm_code = cpu_to_be16(env->int_pgm_code);
lowcore->program_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));
diff --git a/util/interval-tree.c b/util/interval-tree.c
index 4c0baf108f..f2866aa7d3 100644
--- a/util/interval-tree.c
+++ b/util/interval-tree.c
@@ -48,12 +48,6 @@
*
* It also guarantees that if the lookup returns an element it is the 'correct'
* one. But not returning an element does _NOT_ mean it's not present.
- *
- * NOTE:
- *
- * Stores to __rb_parent_color are not important for simple lookups so those
- * are left undone as of now. Nor did I check for loops involving parent
- * pointers.
*/
typedef enum RBColor
@@ -68,14 +62,29 @@ typedef struct RBAugmentCallbacks {
void (*rotate)(RBNode *old, RBNode *new);
} RBAugmentCallbacks;
+static inline uintptr_t rb_pc(const RBNode *n)
+{
+ return qatomic_read(&n->rb_parent_color);
+}
+
+static inline void rb_set_pc(RBNode *n, uintptr_t pc)
+{
+ qatomic_set(&n->rb_parent_color, pc);
+}
+
+static inline RBNode *pc_parent(uintptr_t pc)
+{
+ return (RBNode *)(pc & ~1);
+}
+
static inline RBNode *rb_parent(const RBNode *n)
{
- return (RBNode *)(n->rb_parent_color & ~1);
+ return pc_parent(rb_pc(n));
}
static inline RBNode *rb_red_parent(const RBNode *n)
{
- return (RBNode *)n->rb_parent_color;
+ return (RBNode *)rb_pc(n);
}
static inline RBColor pc_color(uintptr_t pc)
@@ -95,27 +104,27 @@ static inline bool pc_is_black(uintptr_t pc)
static inline RBColor rb_color(const RBNode *n)
{
- return pc_color(n->rb_parent_color);
+ return pc_color(rb_pc(n));
}
static inline bool rb_is_red(const RBNode *n)
{
- return pc_is_red(n->rb_parent_color);
+ return pc_is_red(rb_pc(n));
}
static inline bool rb_is_black(const RBNode *n)
{
- return pc_is_black(n->rb_parent_color);
+ return pc_is_black(rb_pc(n));
}
static inline void rb_set_black(RBNode *n)
{
- n->rb_parent_color |= RB_BLACK;
+ rb_set_pc(n, rb_pc(n) | RB_BLACK);
}
static inline void rb_set_parent_color(RBNode *n, RBNode *p, RBColor color)
{
- n->rb_parent_color = (uintptr_t)p | color;
+ rb_set_pc(n, (uintptr_t)p | color);
}
static inline void rb_set_parent(RBNode *n, RBNode *p)
@@ -128,7 +137,11 @@ static inline void rb_link_node(RBNode *node, RBNode *parent, RBNode **rb_link)
node->rb_parent_color = (uintptr_t)parent;
node->rb_left = node->rb_right = NULL;
- qatomic_set(rb_link, node);
+ /*
+ * Ensure that node is initialized before insertion,
+ * as viewed by a concurrent search.
+ */
+ qatomic_set_mb(rb_link, node);
}
static RBNode *rb_next(RBNode *node)
@@ -177,9 +190,10 @@ static inline void rb_change_child(RBNode *old, RBNode *new,
static inline void rb_rotate_set_parents(RBNode *old, RBNode *new,
RBRoot *root, RBColor color)
{
- RBNode *parent = rb_parent(old);
+ uintptr_t pc = rb_pc(old);
+ RBNode *parent = pc_parent(pc);
- new->rb_parent_color = old->rb_parent_color;
+ rb_set_pc(new, pc);
rb_set_parent_color(old, new, color);
rb_change_child(old, new, parent, root);
}
@@ -527,11 +541,11 @@ static void rb_erase_augmented(RBNode *node, RBRoot *root,
* and node must be black due to 4). We adjust colors locally
* so as to bypass rb_erase_color() later on.
*/
- pc = node->rb_parent_color;
- parent = rb_parent(node);
+ pc = rb_pc(node);
+ parent = pc_parent(pc);
rb_change_child(node, child, parent, root);
if (child) {
- child->rb_parent_color = pc;
+ rb_set_pc(child, pc);
rebalance = NULL;
} else {
rebalance = pc_is_black(pc) ? parent : NULL;
@@ -539,9 +553,9 @@ static void rb_erase_augmented(RBNode *node, RBRoot *root,
tmp = parent;
} else if (!child) {
/* Still case 1, but this time the child is node->rb_left */
- pc = node->rb_parent_color;
- parent = rb_parent(node);
- tmp->rb_parent_color = pc;
+ pc = rb_pc(node);
+ parent = pc_parent(pc);
+ rb_set_pc(tmp, pc);
rb_change_child(node, tmp, parent, root);
rebalance = NULL;
tmp = parent;
@@ -595,8 +609,8 @@ static void rb_erase_augmented(RBNode *node, RBRoot *root,
qatomic_set(&successor->rb_left, tmp);
rb_set_parent(tmp, successor);
- pc = node->rb_parent_color;
- tmp = rb_parent(node);
+ pc = rb_pc(node);
+ tmp = pc_parent(pc);
rb_change_child(node, successor, tmp, root);
if (child2) {
@@ -605,7 +619,7 @@ static void rb_erase_augmented(RBNode *node, RBRoot *root,
} else {
rebalance = rb_is_black(successor) ? parent : NULL;
}
- successor->rb_parent_color = pc;
+ rb_set_pc(successor, pc);
tmp = successor;
}
@@ -745,8 +759,9 @@ static IntervalTreeNode *interval_tree_subtree_search(IntervalTreeNode *node,
* Loop invariant: start <= node->subtree_last
* (Cond2 is satisfied by one of the subtree nodes)
*/
- if (node->rb.rb_left) {
- IntervalTreeNode *left = rb_to_itree(node->rb.rb_left);
+ RBNode *tmp = qatomic_read(&node->rb.rb_left);
+ if (tmp) {
+ IntervalTreeNode *left = rb_to_itree(tmp);
if (start <= left->subtree_last) {
/*
@@ -765,8 +780,9 @@ static IntervalTreeNode *interval_tree_subtree_search(IntervalTreeNode *node,
if (start <= node->last) { /* Cond2 */
return node; /* node is leftmost match */
}
- if (node->rb.rb_right) {
- node = rb_to_itree(node->rb.rb_right);
+ tmp = qatomic_read(&node->rb.rb_right);
+ if (tmp) {
+ node = rb_to_itree(tmp);
if (start <= node->subtree_last) {
continue;
}
@@ -814,8 +830,9 @@ IntervalTreeNode *interval_tree_iter_first(IntervalTreeRoot *root,
IntervalTreeNode *interval_tree_iter_next(IntervalTreeNode *node,
uint64_t start, uint64_t last)
{
- RBNode *rb = node->rb.rb_right, *prev;
+ RBNode *rb, *prev;
+ rb = qatomic_read(&node->rb.rb_right);
while (true) {
/*
* Loop invariants:
@@ -840,7 +857,7 @@ IntervalTreeNode *interval_tree_iter_next(IntervalTreeNode *node,
}
prev = &node->rb;
node = rb_to_itree(rb);
- rb = node->rb.rb_right;
+ rb = qatomic_read(&node->rb.rb_right);
} while (prev == rb);
/* Check if the node intersects [start;last] */