spapr_hcall: Fix little-endian resource handling in H_SET_MODE
This changes resource code definitions to ones used in the host kernel. This fixes H_SET_MODE_RESOURCE_LE (switch between big endian and little endian) to sync registers from KVM before changing LPCR value. This adds a set_spr() helper to update an SPR in a CPU's context to avoid possible races and makes use of it to change LPCR. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Reviewed-by: Greg Kurz <gkurz@linux.vnet.ibm.com> Signed-off-by: Andreas Färber <afaerber@suse.de>
This commit is contained in:
		
							parent
							
								
									df99d30d4e
								
							
						
					
					
						commit
						a46622fd07
					
				| 
						 | 
				
			
			@ -4,6 +4,36 @@
 | 
			
		|||
#include "hw/ppc/spapr.h"
 | 
			
		||||
#include "mmu-hash64.h"
 | 
			
		||||
 | 
			
		||||
struct SPRSyncState {
 | 
			
		||||
    CPUState *cs;
 | 
			
		||||
    int spr;
 | 
			
		||||
    target_ulong value;
 | 
			
		||||
    target_ulong mask;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void do_spr_sync(void *arg)
 | 
			
		||||
{
 | 
			
		||||
    struct SPRSyncState *s = arg;
 | 
			
		||||
    PowerPCCPU *cpu = POWERPC_CPU(s->cs);
 | 
			
		||||
    CPUPPCState *env = &cpu->env;
 | 
			
		||||
 | 
			
		||||
    cpu_synchronize_state(s->cs);
 | 
			
		||||
    env->spr[s->spr] &= ~s->mask;
 | 
			
		||||
    env->spr[s->spr] |= s->value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_spr(CPUState *cs, int spr, target_ulong value,
 | 
			
		||||
                    target_ulong mask)
 | 
			
		||||
{
 | 
			
		||||
    struct SPRSyncState s = {
 | 
			
		||||
        .cs = cs,
 | 
			
		||||
        .spr = spr,
 | 
			
		||||
        .value = value,
 | 
			
		||||
        .mask = mask
 | 
			
		||||
    };
 | 
			
		||||
    run_on_cpu(cs, do_spr_sync, &s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
 | 
			
		||||
                                     target_ulong pte_index)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -689,7 +719,7 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPREnvironment *spapr,
 | 
			
		|||
    target_ulong value2 = args[3];
 | 
			
		||||
    target_ulong ret = H_P2;
 | 
			
		||||
 | 
			
		||||
    if (resource == H_SET_MODE_ENDIAN) {
 | 
			
		||||
    if (resource == H_SET_MODE_RESOURCE_LE) {
 | 
			
		||||
        if (value1) {
 | 
			
		||||
            ret = H_P3;
 | 
			
		||||
            goto out;
 | 
			
		||||
| 
						 | 
				
			
			@ -698,22 +728,17 @@ static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPREnvironment *spapr,
 | 
			
		|||
            ret = H_P4;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch (mflags) {
 | 
			
		||||
        case H_SET_MODE_ENDIAN_BIG:
 | 
			
		||||
            CPU_FOREACH(cs) {
 | 
			
		||||
                PowerPCCPU *cp = POWERPC_CPU(cs);
 | 
			
		||||
                CPUPPCState *env = &cp->env;
 | 
			
		||||
                env->spr[SPR_LPCR] &= ~LPCR_ILE;
 | 
			
		||||
                set_spr(cs, SPR_LPCR, 0, LPCR_ILE);
 | 
			
		||||
            }
 | 
			
		||||
            ret = H_SUCCESS;
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case H_SET_MODE_ENDIAN_LITTLE:
 | 
			
		||||
            CPU_FOREACH(cs) {
 | 
			
		||||
                PowerPCCPU *cp = POWERPC_CPU(cs);
 | 
			
		||||
                CPUPPCState *env = &cp->env;
 | 
			
		||||
                env->spr[SPR_LPCR] |= LPCR_ILE;
 | 
			
		||||
                set_spr(cs, SPR_LPCR, LPCR_ILE, LPCR_ILE);
 | 
			
		||||
            }
 | 
			
		||||
            ret = H_SUCCESS;
 | 
			
		||||
            break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -153,8 +153,13 @@ typedef struct sPAPREnvironment {
 | 
			
		|||
#define H_PP1             (1ULL<<(63-62))
 | 
			
		||||
#define H_PP2             (1ULL<<(63-63))
 | 
			
		||||
 | 
			
		||||
/* H_SET_MODE flags */
 | 
			
		||||
#define H_SET_MODE_ENDIAN        4
 | 
			
		||||
/* Values for 2nd argument to H_SET_MODE */
 | 
			
		||||
#define H_SET_MODE_RESOURCE_SET_CIABR           1
 | 
			
		||||
#define H_SET_MODE_RESOURCE_SET_DAWR            2
 | 
			
		||||
#define H_SET_MODE_RESOURCE_ADDR_TRANS_MODE     3
 | 
			
		||||
#define H_SET_MODE_RESOURCE_LE                  4
 | 
			
		||||
 | 
			
		||||
/* Flags for H_SET_MODE_RESOURCE_LE */
 | 
			
		||||
#define H_SET_MODE_ENDIAN_BIG    0
 | 
			
		||||
#define H_SET_MODE_ENDIAN_LITTLE 1
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue