qemu/target-i386/misc_helper.c
<<
>>
Prefs
   1/*
   2 *  x86 misc helpers
   3 *
   4 *  Copyright (c) 2003 Fabrice Bellard
   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 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 "cpu.h"
  21#include "exec/helper-proto.h"
  22#include "exec/cpu_ldst.h"
  23#include "exec/address-spaces.h"
  24
  25void helper_outb(CPUX86State *env, uint32_t port, uint32_t data)
  26{
  27#ifdef CONFIG_USER_ONLY
  28    fprintf(stderr, "outb: port=0x%04x, data=%02x\n", port, data);
  29#else
  30    address_space_stb(&address_space_io, port, data,
  31                      cpu_get_mem_attrs(env), NULL);
  32#endif
  33}
  34
  35target_ulong helper_inb(CPUX86State *env, uint32_t port)
  36{
  37#ifdef CONFIG_USER_ONLY
  38    fprintf(stderr, "inb: port=0x%04x\n", port);
  39    return 0;
  40#else
  41    return address_space_ldub(&address_space_io, port,
  42                              cpu_get_mem_attrs(env), NULL);
  43#endif
  44}
  45
  46void helper_outw(CPUX86State *env, uint32_t port, uint32_t data)
  47{
  48#ifdef CONFIG_USER_ONLY
  49    fprintf(stderr, "outw: port=0x%04x, data=%04x\n", port, data);
  50#else
  51    address_space_stw(&address_space_io, port, data,
  52                      cpu_get_mem_attrs(env), NULL);
  53#endif
  54}
  55
  56target_ulong helper_inw(CPUX86State *env, uint32_t port)
  57{
  58#ifdef CONFIG_USER_ONLY
  59    fprintf(stderr, "inw: port=0x%04x\n", port);
  60    return 0;
  61#else
  62    return address_space_lduw(&address_space_io, port,
  63                              cpu_get_mem_attrs(env), NULL);
  64#endif
  65}
  66
  67void helper_outl(CPUX86State *env, uint32_t port, uint32_t data)
  68{
  69#ifdef CONFIG_USER_ONLY
  70    fprintf(stderr, "outw: port=0x%04x, data=%08x\n", port, data);
  71#else
  72    address_space_stl(&address_space_io, port, data,
  73                      cpu_get_mem_attrs(env), NULL);
  74#endif
  75}
  76
  77target_ulong helper_inl(CPUX86State *env, uint32_t port)
  78{
  79#ifdef CONFIG_USER_ONLY
  80    fprintf(stderr, "inl: port=0x%04x\n", port);
  81    return 0;
  82#else
  83    return address_space_ldl(&address_space_io, port,
  84                             cpu_get_mem_attrs(env), NULL);
  85#endif
  86}
  87
  88void helper_into(CPUX86State *env, int next_eip_addend)
  89{
  90    int eflags;
  91
  92    eflags = cpu_cc_compute_all(env, CC_OP);
  93    if (eflags & CC_O) {
  94        raise_interrupt(env, EXCP04_INTO, 1, 0, next_eip_addend);
  95    }
  96}
  97
  98void helper_cpuid(CPUX86State *env)
  99{
 100    uint32_t eax, ebx, ecx, edx;
 101
 102    cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0);
 103
 104    cpu_x86_cpuid(env, (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_ECX],
 105                  &eax, &ebx, &ecx, &edx);
 106    env->regs[R_EAX] = eax;
 107    env->regs[R_EBX] = ebx;
 108    env->regs[R_ECX] = ecx;
 109    env->regs[R_EDX] = edx;
 110}
 111
 112#if defined(CONFIG_USER_ONLY)
 113target_ulong helper_read_crN(CPUX86State *env, int reg)
 114{
 115    return 0;
 116}
 117
 118void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
 119{
 120}
 121#else
 122target_ulong helper_read_crN(CPUX86State *env, int reg)
 123{
 124    target_ulong val;
 125
 126    cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0);
 127    switch (reg) {
 128    default:
 129        val = env->cr[reg];
 130        break;
 131    case 8:
 132        if (!(env->hflags2 & HF2_VINTR_MASK)) {
 133            val = cpu_get_apic_tpr(x86_env_get_cpu(env)->apic_state);
 134        } else {
 135            val = env->v_tpr;
 136        }
 137        break;
 138    }
 139    return val;
 140}
 141
 142void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
 143{
 144    cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0);
 145    switch (reg) {
 146    case 0:
 147        cpu_x86_update_cr0(env, t0);
 148        break;
 149    case 3:
 150        cpu_x86_update_cr3(env, t0);
 151        break;
 152    case 4:
 153        cpu_x86_update_cr4(env, t0);
 154        break;
 155    case 8:
 156        if (!(env->hflags2 & HF2_VINTR_MASK)) {
 157            cpu_set_apic_tpr(x86_env_get_cpu(env)->apic_state, t0);
 158        }
 159        env->v_tpr = t0 & 0x0f;
 160        break;
 161    default:
 162        env->cr[reg] = t0;
 163        break;
 164    }
 165}
 166#endif
 167
 168void helper_lmsw(CPUX86State *env, target_ulong t0)
 169{
 170    /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
 171       if already set to one. */
 172    t0 = (env->cr[0] & ~0xe) | (t0 & 0xf);
 173    helper_write_crN(env, 0, t0);
 174}
 175
 176void helper_invlpg(CPUX86State *env, target_ulong addr)
 177{
 178    X86CPU *cpu = x86_env_get_cpu(env);
 179
 180    cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0);
 181    tlb_flush_page(CPU(cpu), addr);
 182}
 183
 184void helper_rdtsc(CPUX86State *env)
 185{
 186    uint64_t val;
 187
 188    if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
 189        raise_exception_ra(env, EXCP0D_GPF, GETPC());
 190    }
 191    cpu_svm_check_intercept_param(env, SVM_EXIT_RDTSC, 0);
 192
 193    val = cpu_get_tsc(env) + env->tsc_offset;
 194    env->regs[R_EAX] = (uint32_t)(val);
 195    env->regs[R_EDX] = (uint32_t)(val >> 32);
 196}
 197
 198void helper_rdtscp(CPUX86State *env)
 199{
 200    helper_rdtsc(env);
 201    env->regs[R_ECX] = (uint32_t)(env->tsc_aux);
 202}
 203
 204void helper_rdpmc(CPUX86State *env)
 205{
 206    if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
 207        raise_exception_ra(env, EXCP0D_GPF, GETPC());
 208    }
 209    cpu_svm_check_intercept_param(env, SVM_EXIT_RDPMC, 0);
 210
 211    /* currently unimplemented */
 212    qemu_log_mask(LOG_UNIMP, "x86: unimplemented rdpmc\n");
 213    raise_exception_err(env, EXCP06_ILLOP, 0);
 214}
 215
 216#if defined(CONFIG_USER_ONLY)
 217void helper_wrmsr(CPUX86State *env)
 218{
 219}
 220
 221void helper_rdmsr(CPUX86State *env)
 222{
 223}
 224#else
 225void helper_wrmsr(CPUX86State *env)
 226{
 227    uint64_t val;
 228
 229    cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1);
 230
 231    val = ((uint32_t)env->regs[R_EAX]) |
 232        ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);
 233
 234    switch ((uint32_t)env->regs[R_ECX]) {
 235    case MSR_IA32_SYSENTER_CS:
 236        env->sysenter_cs = val & 0xffff;
 237        break;
 238    case MSR_IA32_SYSENTER_ESP:
 239        env->sysenter_esp = val;
 240        break;
 241    case MSR_IA32_SYSENTER_EIP:
 242        env->sysenter_eip = val;
 243        break;
 244    case MSR_IA32_APICBASE:
 245        cpu_set_apic_base(x86_env_get_cpu(env)->apic_state, val);
 246        break;
 247    case MSR_EFER:
 248        {
 249            uint64_t update_mask;
 250
 251            update_mask = 0;
 252            if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_SYSCALL) {
 253                update_mask |= MSR_EFER_SCE;
 254            }
 255            if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
 256                update_mask |= MSR_EFER_LME;
 257            }
 258            if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) {
 259                update_mask |= MSR_EFER_FFXSR;
 260            }
 261            if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_NX) {
 262                update_mask |= MSR_EFER_NXE;
 263            }
 264            if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) {
 265                update_mask |= MSR_EFER_SVME;
 266            }
 267            if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) {
 268                update_mask |= MSR_EFER_FFXSR;
 269            }
 270            cpu_load_efer(env, (env->efer & ~update_mask) |
 271                          (val & update_mask));
 272        }
 273        break;
 274    case MSR_STAR:
 275        env->star = val;
 276        break;
 277    case MSR_PAT:
 278        env->pat = val;
 279        break;
 280    case MSR_VM_HSAVE_PA:
 281        env->vm_hsave = val;
 282        break;
 283#ifdef TARGET_X86_64
 284    case MSR_LSTAR:
 285        env->lstar = val;
 286        break;
 287    case MSR_CSTAR:
 288        env->cstar = val;
 289        break;
 290    case MSR_FMASK:
 291        env->fmask = val;
 292        break;
 293    case MSR_FSBASE:
 294        env->segs[R_FS].base = val;
 295        break;
 296    case MSR_GSBASE:
 297        env->segs[R_GS].base = val;
 298        break;
 299    case MSR_KERNELGSBASE:
 300        env->kernelgsbase = val;
 301        break;
 302#endif
 303    case MSR_MTRRphysBase(0):
 304    case MSR_MTRRphysBase(1):
 305    case MSR_MTRRphysBase(2):
 306    case MSR_MTRRphysBase(3):
 307    case MSR_MTRRphysBase(4):
 308    case MSR_MTRRphysBase(5):
 309    case MSR_MTRRphysBase(6):
 310    case MSR_MTRRphysBase(7):
 311        env->mtrr_var[((uint32_t)env->regs[R_ECX] -
 312                       MSR_MTRRphysBase(0)) / 2].base = val;
 313        break;
 314    case MSR_MTRRphysMask(0):
 315    case MSR_MTRRphysMask(1):
 316    case MSR_MTRRphysMask(2):
 317    case MSR_MTRRphysMask(3):
 318    case MSR_MTRRphysMask(4):
 319    case MSR_MTRRphysMask(5):
 320    case MSR_MTRRphysMask(6):
 321    case MSR_MTRRphysMask(7):
 322        env->mtrr_var[((uint32_t)env->regs[R_ECX] -
 323                       MSR_MTRRphysMask(0)) / 2].mask = val;
 324        break;
 325    case MSR_MTRRfix64K_00000:
 326        env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
 327                        MSR_MTRRfix64K_00000] = val;
 328        break;
 329    case MSR_MTRRfix16K_80000:
 330    case MSR_MTRRfix16K_A0000:
 331        env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
 332                        MSR_MTRRfix16K_80000 + 1] = val;
 333        break;
 334    case MSR_MTRRfix4K_C0000:
 335    case MSR_MTRRfix4K_C8000:
 336    case MSR_MTRRfix4K_D0000:
 337    case MSR_MTRRfix4K_D8000:
 338    case MSR_MTRRfix4K_E0000:
 339    case MSR_MTRRfix4K_E8000:
 340    case MSR_MTRRfix4K_F0000:
 341    case MSR_MTRRfix4K_F8000:
 342        env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
 343                        MSR_MTRRfix4K_C0000 + 3] = val;
 344        break;
 345    case MSR_MTRRdefType:
 346        env->mtrr_deftype = val;
 347        break;
 348    case MSR_MCG_STATUS:
 349        env->mcg_status = val;
 350        break;
 351    case MSR_MCG_CTL:
 352        if ((env->mcg_cap & MCG_CTL_P)
 353            && (val == 0 || val == ~(uint64_t)0)) {
 354            env->mcg_ctl = val;
 355        }
 356        break;
 357    case MSR_TSC_AUX:
 358        env->tsc_aux = val;
 359        break;
 360    case MSR_IA32_MISC_ENABLE:
 361        env->msr_ia32_misc_enable = val;
 362        break;
 363    default:
 364        if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
 365            && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
 366            (4 * env->mcg_cap & 0xff)) {
 367            uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL;
 368            if ((offset & 0x3) != 0
 369                || (val == 0 || val == ~(uint64_t)0)) {
 370                env->mce_banks[offset] = val;
 371            }
 372            break;
 373        }
 374        /* XXX: exception? */
 375        break;
 376    }
 377}
 378
 379void helper_rdmsr(CPUX86State *env)
 380{
 381    uint64_t val;
 382
 383    cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0);
 384
 385    switch ((uint32_t)env->regs[R_ECX]) {
 386    case MSR_IA32_SYSENTER_CS:
 387        val = env->sysenter_cs;
 388        break;
 389    case MSR_IA32_SYSENTER_ESP:
 390        val = env->sysenter_esp;
 391        break;
 392    case MSR_IA32_SYSENTER_EIP:
 393        val = env->sysenter_eip;
 394        break;
 395    case MSR_IA32_APICBASE:
 396        val = cpu_get_apic_base(x86_env_get_cpu(env)->apic_state);
 397        break;
 398    case MSR_EFER:
 399        val = env->efer;
 400        break;
 401    case MSR_STAR:
 402        val = env->star;
 403        break;
 404    case MSR_PAT:
 405        val = env->pat;
 406        break;
 407    case MSR_VM_HSAVE_PA:
 408        val = env->vm_hsave;
 409        break;
 410    case MSR_IA32_PERF_STATUS:
 411        /* tsc_increment_by_tick */
 412        val = 1000ULL;
 413        /* CPU multiplier */
 414        val |= (((uint64_t)4ULL) << 40);
 415        break;
 416#ifdef TARGET_X86_64
 417    case MSR_LSTAR:
 418        val = env->lstar;
 419        break;
 420    case MSR_CSTAR:
 421        val = env->cstar;
 422        break;
 423    case MSR_FMASK:
 424        val = env->fmask;
 425        break;
 426    case MSR_FSBASE:
 427        val = env->segs[R_FS].base;
 428        break;
 429    case MSR_GSBASE:
 430        val = env->segs[R_GS].base;
 431        break;
 432    case MSR_KERNELGSBASE:
 433        val = env->kernelgsbase;
 434        break;
 435    case MSR_TSC_AUX:
 436        val = env->tsc_aux;
 437        break;
 438#endif
 439    case MSR_MTRRphysBase(0):
 440    case MSR_MTRRphysBase(1):
 441    case MSR_MTRRphysBase(2):
 442    case MSR_MTRRphysBase(3):
 443    case MSR_MTRRphysBase(4):
 444    case MSR_MTRRphysBase(5):
 445    case MSR_MTRRphysBase(6):
 446    case MSR_MTRRphysBase(7):
 447        val = env->mtrr_var[((uint32_t)env->regs[R_ECX] -
 448                             MSR_MTRRphysBase(0)) / 2].base;
 449        break;
 450    case MSR_MTRRphysMask(0):
 451    case MSR_MTRRphysMask(1):
 452    case MSR_MTRRphysMask(2):
 453    case MSR_MTRRphysMask(3):
 454    case MSR_MTRRphysMask(4):
 455    case MSR_MTRRphysMask(5):
 456    case MSR_MTRRphysMask(6):
 457    case MSR_MTRRphysMask(7):
 458        val = env->mtrr_var[((uint32_t)env->regs[R_ECX] -
 459                             MSR_MTRRphysMask(0)) / 2].mask;
 460        break;
 461    case MSR_MTRRfix64K_00000:
 462        val = env->mtrr_fixed[0];
 463        break;
 464    case MSR_MTRRfix16K_80000:
 465    case MSR_MTRRfix16K_A0000:
 466        val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
 467                              MSR_MTRRfix16K_80000 + 1];
 468        break;
 469    case MSR_MTRRfix4K_C0000:
 470    case MSR_MTRRfix4K_C8000:
 471    case MSR_MTRRfix4K_D0000:
 472    case MSR_MTRRfix4K_D8000:
 473    case MSR_MTRRfix4K_E0000:
 474    case MSR_MTRRfix4K_E8000:
 475    case MSR_MTRRfix4K_F0000:
 476    case MSR_MTRRfix4K_F8000:
 477        val = env->mtrr_fixed[(uint32_t)env->regs[R_ECX] -
 478                              MSR_MTRRfix4K_C0000 + 3];
 479        break;
 480    case MSR_MTRRdefType:
 481        val = env->mtrr_deftype;
 482        break;
 483    case MSR_MTRRcap:
 484        if (env->features[FEAT_1_EDX] & CPUID_MTRR) {
 485            val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT |
 486                MSR_MTRRcap_WC_SUPPORTED;
 487        } else {
 488            /* XXX: exception? */
 489            val = 0;
 490        }
 491        break;
 492    case MSR_MCG_CAP:
 493        val = env->mcg_cap;
 494        break;
 495    case MSR_MCG_CTL:
 496        if (env->mcg_cap & MCG_CTL_P) {
 497            val = env->mcg_ctl;
 498        } else {
 499            val = 0;
 500        }
 501        break;
 502    case MSR_MCG_STATUS:
 503        val = env->mcg_status;
 504        break;
 505    case MSR_IA32_MISC_ENABLE:
 506        val = env->msr_ia32_misc_enable;
 507        break;
 508    default:
 509        if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
 510            && (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +
 511            (4 * env->mcg_cap & 0xff)) {
 512            uint32_t offset = (uint32_t)env->regs[R_ECX] - MSR_MC0_CTL;
 513            val = env->mce_banks[offset];
 514            break;
 515        }
 516        /* XXX: exception? */
 517        val = 0;
 518        break;
 519    }
 520    env->regs[R_EAX] = (uint32_t)(val);
 521    env->regs[R_EDX] = (uint32_t)(val >> 32);
 522}
 523#endif
 524
 525static void do_pause(X86CPU *cpu)
 526{
 527    CPUState *cs = CPU(cpu);
 528
 529    /* Just let another CPU run.  */
 530    cs->exception_index = EXCP_INTERRUPT;
 531    cpu_loop_exit(cs);
 532}
 533
 534static void do_hlt(X86CPU *cpu)
 535{
 536    CPUState *cs = CPU(cpu);
 537    CPUX86State *env = &cpu->env;
 538
 539    env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
 540    cs->halted = 1;
 541    cs->exception_index = EXCP_HLT;
 542    cpu_loop_exit(cs);
 543}
 544
 545void helper_hlt(CPUX86State *env, int next_eip_addend)
 546{
 547    X86CPU *cpu = x86_env_get_cpu(env);
 548
 549    cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0);
 550    env->eip += next_eip_addend;
 551
 552    do_hlt(cpu);
 553}
 554
 555void helper_monitor(CPUX86State *env, target_ulong ptr)
 556{
 557    if ((uint32_t)env->regs[R_ECX] != 0) {
 558        raise_exception_ra(env, EXCP0D_GPF, GETPC());
 559    }
 560    /* XXX: store address? */
 561    cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0);
 562}
 563
 564void helper_mwait(CPUX86State *env, int next_eip_addend)
 565{
 566    CPUState *cs;
 567    X86CPU *cpu;
 568
 569    if ((uint32_t)env->regs[R_ECX] != 0) {
 570        raise_exception_ra(env, EXCP0D_GPF, GETPC());
 571    }
 572    cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0);
 573    env->eip += next_eip_addend;
 574
 575    cpu = x86_env_get_cpu(env);
 576    cs = CPU(cpu);
 577    /* XXX: not complete but not completely erroneous */
 578    if (cs->cpu_index != 0 || CPU_NEXT(cs) != NULL) {
 579        do_pause(cpu);
 580    } else {
 581        do_hlt(cpu);
 582    }
 583}
 584
 585void helper_pause(CPUX86State *env, int next_eip_addend)
 586{
 587    X86CPU *cpu = x86_env_get_cpu(env);
 588
 589    cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0);
 590    env->eip += next_eip_addend;
 591
 592    do_pause(cpu);
 593}
 594
 595void helper_debug(CPUX86State *env)
 596{
 597    CPUState *cs = CPU(x86_env_get_cpu(env));
 598
 599    cs->exception_index = EXCP_DEBUG;
 600    cpu_loop_exit(cs);
 601}
 602