static target_ulong h_enter(CPUState *env, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { target_ulong flags = args[0]; target_ulong pte_index = args[1]; target_ulong pteh = args[2]; target_ulong ptel = args[3]; target_ulong i; uint8_t *hpte; /* only handle 4k and 16M pages for now */ if (pteh & HPTE_V_LARGE) { #if 0 /* We don't support 64k pages yet */ if ((ptel & 0xf000) == 0x1000) { /* 64k page */ } else #endif if ((ptel & 0xff000) == 0) { /* 16M page */ /* lowest AVA bit must be 0 for 16M pages */ if (pteh & 0x80) { return H_PARAMETER; } } else { return H_PARAMETER; } } /* FIXME: bounds check the pa? */ /* Check WIMG */ if ((ptel & HPTE_R_WIMG) != HPTE_R_M) { return H_PARAMETER; } pteh &= ~0x60ULL; if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) { return H_PARAMETER; } if (likely((flags & H_EXACT) == 0)) { pte_index &= ~7ULL; hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); for (i = 0; ; ++i) { if (i == 8) { return H_PTEG_FULL; } if (((ldq_p(hpte) & HPTE_V_VALID) == 0) && lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) { break; } hpte += HASH_PTE_SIZE_64; } } else { i = 0; hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64); if (!lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) { return H_PTEG_FULL; } } stq_p(hpte + (HASH_PTE_SIZE_64/2), ptel); /* eieio(); FIXME: need some sort of barrier for smp? */ stq_p(hpte, pteh); assert(!(ldq_p(hpte) & HPTE_V_HVLOCK)); args[0] = pte_index + i; return H_SUCCESS; }