qemu/target/ppc/misc_helper.c
<<
>>
Prefs
   1/*
   2 * Miscellaneous PowerPC emulation helpers for QEMU.
   3 *
   4 *  Copyright (c) 2003-2007 Jocelyn Mayer
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2.1 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "cpu.h"
  22#include "exec/exec-all.h"
  23#include "exec/helper-proto.h"
  24#include "qemu/error-report.h"
  25#include "qemu/main-loop.h"
  26
  27#include "helper_regs.h"
  28
  29/*****************************************************************************/
  30/* SPR accesses */
  31void helper_load_dump_spr(CPUPPCState *env, uint32_t sprn)
  32{
  33    qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn,
  34             env->spr[sprn]);
  35}
  36
  37void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
  38{
  39    qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
  40             env->spr[sprn]);
  41}
  42
  43#ifdef TARGET_PPC64
  44static void raise_hv_fu_exception(CPUPPCState *env, uint32_t bit,
  45                                  const char *caller, uint32_t cause,
  46                                  uintptr_t raddr)
  47{
  48    qemu_log_mask(CPU_LOG_INT, "HV Facility %d is unavailable (%s)\n",
  49                  bit, caller);
  50
  51    env->spr[SPR_HFSCR] &= ~((target_ulong)FSCR_IC_MASK << FSCR_IC_POS);
  52
  53    raise_exception_err_ra(env, POWERPC_EXCP_HV_FU, cause, raddr);
  54}
  55
  56static void raise_fu_exception(CPUPPCState *env, uint32_t bit,
  57                               uint32_t sprn, uint32_t cause,
  58                               uintptr_t raddr)
  59{
  60    qemu_log("Facility SPR %d is unavailable (SPR FSCR:%d)\n", sprn, bit);
  61
  62    env->spr[SPR_FSCR] &= ~((target_ulong)FSCR_IC_MASK << FSCR_IC_POS);
  63    cause &= FSCR_IC_MASK;
  64    env->spr[SPR_FSCR] |= (target_ulong)cause << FSCR_IC_POS;
  65
  66    raise_exception_err_ra(env, POWERPC_EXCP_FU, 0, raddr);
  67}
  68#endif
  69
  70void helper_hfscr_facility_check(CPUPPCState *env, uint32_t bit,
  71                                 const char *caller, uint32_t cause)
  72{
  73#ifdef TARGET_PPC64
  74    if ((env->msr_mask & MSR_HVB) && !msr_hv &&
  75                                     !(env->spr[SPR_HFSCR] & (1UL << bit))) {
  76        raise_hv_fu_exception(env, bit, caller, cause, GETPC());
  77    }
  78#endif
  79}
  80
  81void helper_fscr_facility_check(CPUPPCState *env, uint32_t bit,
  82                                uint32_t sprn, uint32_t cause)
  83{
  84#ifdef TARGET_PPC64
  85    if (env->spr[SPR_FSCR] & (1ULL << bit)) {
  86        /* Facility is enabled, continue */
  87        return;
  88    }
  89    raise_fu_exception(env, bit, sprn, cause, GETPC());
  90#endif
  91}
  92
  93void helper_msr_facility_check(CPUPPCState *env, uint32_t bit,
  94                               uint32_t sprn, uint32_t cause)
  95{
  96#ifdef TARGET_PPC64
  97    if (env->msr & (1ULL << bit)) {
  98        /* Facility is enabled, continue */
  99        return;
 100    }
 101    raise_fu_exception(env, bit, sprn, cause, GETPC());
 102#endif
 103}
 104
 105#if !defined(CONFIG_USER_ONLY)
 106
 107void helper_store_sdr1(CPUPPCState *env, target_ulong val)
 108{
 109    if (env->spr[SPR_SDR1] != val) {
 110        ppc_store_sdr1(env, val);
 111        tlb_flush(env_cpu(env));
 112    }
 113}
 114
 115#if defined(TARGET_PPC64)
 116void helper_store_ptcr(CPUPPCState *env, target_ulong val)
 117{
 118    if (env->spr[SPR_PTCR] != val) {
 119        ppc_store_ptcr(env, val);
 120        tlb_flush(env_cpu(env));
 121    }
 122}
 123
 124void helper_store_pcr(CPUPPCState *env, target_ulong value)
 125{
 126    PowerPCCPU *cpu = env_archcpu(env);
 127    PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
 128
 129    env->spr[SPR_PCR] = value & pcc->pcr_mask;
 130}
 131
 132/*
 133 * DPDES register is shared. Each bit reflects the state of the
 134 * doorbell interrupt of a thread of the same core.
 135 */
 136target_ulong helper_load_dpdes(CPUPPCState *env)
 137{
 138    target_ulong dpdes = 0;
 139
 140    helper_hfscr_facility_check(env, HFSCR_MSGP, "load DPDES", HFSCR_IC_MSGP);
 141
 142    /* TODO: TCG supports only one thread */
 143    if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
 144        dpdes = 1;
 145    }
 146
 147    return dpdes;
 148}
 149
 150void helper_store_dpdes(CPUPPCState *env, target_ulong val)
 151{
 152    PowerPCCPU *cpu = env_archcpu(env);
 153    CPUState *cs = CPU(cpu);
 154
 155    helper_hfscr_facility_check(env, HFSCR_MSGP, "store DPDES", HFSCR_IC_MSGP);
 156
 157    /* TODO: TCG supports only one thread */
 158    if (val & ~0x1) {
 159        qemu_log_mask(LOG_GUEST_ERROR, "Invalid DPDES register value "
 160                      TARGET_FMT_lx"\n", val);
 161        return;
 162    }
 163
 164    if (val & 0x1) {
 165        env->pending_interrupts |= 1 << PPC_INTERRUPT_DOORBELL;
 166        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
 167    } else {
 168        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
 169    }
 170}
 171#endif /* defined(TARGET_PPC64) */
 172
 173void helper_store_pidr(CPUPPCState *env, target_ulong val)
 174{
 175    env->spr[SPR_BOOKS_PID] = val;
 176    tlb_flush(env_cpu(env));
 177}
 178
 179void helper_store_lpidr(CPUPPCState *env, target_ulong val)
 180{
 181    env->spr[SPR_LPIDR] = val;
 182
 183    /*
 184     * We need to flush the TLB on LPID changes as we only tag HV vs
 185     * guest in TCG TLB. Also the quadrants means the HV will
 186     * potentially access and cache entries for the current LPID as
 187     * well.
 188     */
 189    tlb_flush(env_cpu(env));
 190}
 191
 192void helper_store_hid0_601(CPUPPCState *env, target_ulong val)
 193{
 194    target_ulong hid0;
 195
 196    hid0 = env->spr[SPR_HID0];
 197    if ((val ^ hid0) & 0x00000008) {
 198        /* Change current endianness */
 199        env->hflags &= ~(1 << MSR_LE);
 200        env->hflags_nmsr &= ~(1 << MSR_LE);
 201        env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
 202        env->hflags |= env->hflags_nmsr;
 203        qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__,
 204                 val & 0x8 ? 'l' : 'b', env->hflags);
 205    }
 206    env->spr[SPR_HID0] = (uint32_t)val;
 207}
 208
 209void helper_store_403_pbr(CPUPPCState *env, uint32_t num, target_ulong value)
 210{
 211    if (likely(env->pb[num] != value)) {
 212        env->pb[num] = value;
 213        /* Should be optimized */
 214        tlb_flush(env_cpu(env));
 215    }
 216}
 217
 218void helper_store_40x_dbcr0(CPUPPCState *env, target_ulong val)
 219{
 220    store_40x_dbcr0(env, val);
 221}
 222
 223void helper_store_40x_sler(CPUPPCState *env, target_ulong val)
 224{
 225    store_40x_sler(env, val);
 226}
 227#endif
 228/*****************************************************************************/
 229/* PowerPC 601 specific instructions (POWER bridge) */
 230
 231target_ulong helper_clcs(CPUPPCState *env, uint32_t arg)
 232{
 233    switch (arg) {
 234    case 0x0CUL:
 235        /* Instruction cache line size */
 236        return env->icache_line_size;
 237    case 0x0DUL:
 238        /* Data cache line size */
 239        return env->dcache_line_size;
 240    case 0x0EUL:
 241        /* Minimum cache line size */
 242        return (env->icache_line_size < env->dcache_line_size) ?
 243            env->icache_line_size : env->dcache_line_size;
 244    case 0x0FUL:
 245        /* Maximum cache line size */
 246        return (env->icache_line_size > env->dcache_line_size) ?
 247            env->icache_line_size : env->dcache_line_size;
 248    default:
 249        /* Undefined */
 250        return 0;
 251    }
 252}
 253
 254/*****************************************************************************/
 255/* Special registers manipulation */
 256
 257/* GDBstub can read and write MSR... */
 258void ppc_store_msr(CPUPPCState *env, target_ulong value)
 259{
 260    hreg_store_msr(env, value, 0);
 261}
 262
 263/*
 264 * This code is lifted from MacOnLinux. It is called whenever THRM1,2
 265 * or 3 is read an fixes up the values in such a way that will make
 266 * MacOS not hang. These registers exist on some 75x and 74xx
 267 * processors.
 268 */
 269void helper_fixup_thrm(CPUPPCState *env)
 270{
 271    target_ulong v, t;
 272    int i;
 273
 274#define THRM1_TIN       (1 << 31)
 275#define THRM1_TIV       (1 << 30)
 276#define THRM1_THRES(x)  (((x) & 0x7f) << 23)
 277#define THRM1_TID       (1 << 2)
 278#define THRM1_TIE       (1 << 1)
 279#define THRM1_V         (1 << 0)
 280#define THRM3_E         (1 << 0)
 281
 282    if (!(env->spr[SPR_THRM3] & THRM3_E)) {
 283        return;
 284    }
 285
 286    /* Note: Thermal interrupts are unimplemented */
 287    for (i = SPR_THRM1; i <= SPR_THRM2; i++) {
 288        v = env->spr[i];
 289        if (!(v & THRM1_V)) {
 290            continue;
 291        }
 292        v |= THRM1_TIV;
 293        v &= ~THRM1_TIN;
 294        t = v & THRM1_THRES(127);
 295        if ((v & THRM1_TID) && t < THRM1_THRES(24)) {
 296            v |= THRM1_TIN;
 297        }
 298        if (!(v & THRM1_TID) && t > THRM1_THRES(24)) {
 299            v |= THRM1_TIN;
 300        }
 301        env->spr[i] = v;
 302    }
 303}
 304