Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8b6db3bc authored by Alexander Graf's avatar Alexander Graf Committed by Avi Kivity
Browse files

KVM: PPC: Implement correct SID mapping on Book3s_32



Up until now we were doing segment mappings wrong on Book3s_32. For Book3s_64
we were using a trick where we know that a single mmu_context gives us 16 bits
of context ids.

The mm system on Book3s_32 instead uses a clever algorithm to distribute VSIDs
across the available range, so a context id really only gives us 16 available
VSIDs.

To keep at least a few guest processes in the SID shadow, let's map a number of
contexts that we can use as VSID pool. This makes the code be actually correct
and shouldn't hurt performance too much.

Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
parent ad087376
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -60,6 +60,13 @@ struct kvmppc_sid_map {
#define SID_MAP_NUM     (1 << SID_MAP_BITS)
#define SID_MAP_MASK    (SID_MAP_NUM - 1)

#ifdef CONFIG_PPC_BOOK3S_64
#define SID_CONTEXTS	1
#else
#define SID_CONTEXTS	128
#define VSID_POOL_SIZE	(SID_CONTEXTS * 16)
#endif

struct kvmppc_vcpu_book3s {
	struct kvm_vcpu vcpu;
	struct kvmppc_book3s_shadow_vcpu *shadow_vcpu;
@@ -78,10 +85,14 @@ struct kvmppc_vcpu_book3s {
	u64 sdr1;
	u64 hior;
	u64 msr_mask;
	u64 vsid_first;
	u64 vsid_next;
#ifdef CONFIG_PPC_BOOK3S_32
	u32 vsid_pool[VSID_POOL_SIZE];
#else
	u64 vsid_first;
	u64 vsid_max;
	int context_id;
#endif
	int context_id[SID_CONTEXTS];
	ulong prog_flags; /* flags to inject when giving a 700 trap */
};

+31 −26
Original line number Diff line number Diff line
@@ -275,18 +275,15 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
	backwards_map = !backwards_map;

	/* Uh-oh ... out of mappings. Let's flush! */
	if (vcpu_book3s->vsid_next >= vcpu_book3s->vsid_max) {
		vcpu_book3s->vsid_next = vcpu_book3s->vsid_first;
	if (vcpu_book3s->vsid_next >= VSID_POOL_SIZE) {
		vcpu_book3s->vsid_next = 0;
		memset(vcpu_book3s->sid_map, 0,
		       sizeof(struct kvmppc_sid_map) * SID_MAP_NUM);
		kvmppc_mmu_pte_flush(vcpu, 0, 0);
		kvmppc_mmu_flush_segments(vcpu);
	}
	map->host_vsid = vcpu_book3s->vsid_next;

	/* Would have to be 111 to be completely aligned with the rest of
	   Linux, but that is just way too little space! */
	vcpu_book3s->vsid_next+=1;
	map->host_vsid = vcpu_book3s->vsid_pool[vcpu_book3s->vsid_next];
	vcpu_book3s->vsid_next++;

	map->guest_vsid = gvsid;
	map->valid = true;
@@ -333,40 +330,38 @@ void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)

void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
{
	int i;

	kvmppc_mmu_hpte_destroy(vcpu);
	preempt_disable();
	__destroy_context(to_book3s(vcpu)->context_id);
	for (i = 0; i < SID_CONTEXTS; i++)
		__destroy_context(to_book3s(vcpu)->context_id[i]);
	preempt_enable();
}

/* From mm/mmu_context_hash32.c */
#define CTX_TO_VSID(ctx) (((ctx) * (897 * 16)) & 0xffffff)
#define CTX_TO_VSID(c, id)	((((c) * (897 * 16)) + (id * 0x111)) & 0xffffff)

int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
{
	struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
	int err;
	ulong sdr1;
	int i;
	int j;

	for (i = 0; i < SID_CONTEXTS; i++) {
		err = __init_new_context();
		if (err < 0)
		return -1;
	vcpu3s->context_id = err;

	vcpu3s->vsid_max = CTX_TO_VSID(vcpu3s->context_id + 1) - 1;
	vcpu3s->vsid_first = CTX_TO_VSID(vcpu3s->context_id);

#if 0 /* XXX still doesn't guarantee uniqueness */
	/* We could collide with the Linux vsid space because the vsid
	 * wraps around at 24 bits. We're safe if we do our own space
	 * though, so let's always set the highest bit. */
			goto init_fail;
		vcpu3s->context_id[i] = err;

	vcpu3s->vsid_max |= 0x00800000;
	vcpu3s->vsid_first |= 0x00800000;
#endif
	BUG_ON(vcpu3s->vsid_max < vcpu3s->vsid_first);
		/* Remember context id for this combination */
		for (j = 0; j < 16; j++)
			vcpu3s->vsid_pool[(i * 16) + j] = CTX_TO_VSID(err, j);
	}

	vcpu3s->vsid_next = vcpu3s->vsid_first;
	vcpu3s->vsid_next = 0;

	/* Remember where the HTAB is */
	asm ( "mfsdr1 %0" : "=r"(sdr1) );
@@ -376,4 +371,14 @@ int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
	kvmppc_mmu_hpte_init(vcpu);

	return 0;

init_fail:
	for (j = 0; j < i; j++) {
		if (!vcpu3s->context_id[j])
			continue;

		__destroy_context(to_book3s(vcpu)->context_id[j]);
	}

	return -1;
}
+4 −4
Original line number Diff line number Diff line
@@ -286,7 +286,7 @@ void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
{
	kvmppc_mmu_hpte_destroy(vcpu);
	__destroy_context(to_book3s(vcpu)->context_id);
	__destroy_context(to_book3s(vcpu)->context_id[0]);
}

int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
@@ -297,10 +297,10 @@ int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
	err = __init_new_context();
	if (err < 0)
		return -1;
	vcpu3s->context_id = err;
	vcpu3s->context_id[0] = err;

	vcpu3s->vsid_max = ((vcpu3s->context_id + 1) << USER_ESID_BITS) - 1;
	vcpu3s->vsid_first = vcpu3s->context_id << USER_ESID_BITS;
	vcpu3s->vsid_max = ((vcpu3s->context_id[0] + 1) << USER_ESID_BITS) - 1;
	vcpu3s->vsid_first = vcpu3s->context_id[0] << USER_ESID_BITS;
	vcpu3s->vsid_next = vcpu3s->vsid_first;

	kvmppc_mmu_hpte_init(vcpu);