/* * Copyright (c) 2007 The Hewlett-Packard Development Company * Copyright (c) 2011 Advanced Micro Devices, Inc. * All rights reserved. * * The license below extends only to copyright in the software and shall * not be construed as granting a license to any other intellectual * property including but not limited to intellectual property relating * to a hardware implementation of the functionality of the software * licensed hereunder. You may use the software subject to the license * terms below provided that you ensure that this notice is replicated * unmodified and in its entirety in all distributions of the software, * modified or unmodified, in source code or in binary form. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Gabe Black */ #include "arch/x86/utility.hh" #include "arch/x86/interrupts.hh" #include "arch/x86/registers.hh" #include "arch/x86/x86_traits.hh" #include "cpu/base.hh" #include "fputils/fp80.h" #include "sim/full_system.hh" namespace X86ISA { uint64_t getArgument(ThreadContext *tc, int &number, uint16_t size, bool fp) { if (fp) { panic("getArgument(): Floating point arguments not implemented\n"); } else if (size != 8) { panic("getArgument(): Can only handle 64-bit arguments.\n"); } // The first 6 integer arguments are passed in registers, the rest // are passed on the stack. const int int_reg_map[] = { INTREG_RDI, INTREG_RSI, INTREG_RDX, INTREG_RCX, INTREG_R8, INTREG_R9 }; if (number < sizeof(int_reg_map) / sizeof(*int_reg_map)) { return tc->readIntReg(int_reg_map[number]); } else { panic("getArgument(): Don't know how to handle stack arguments.\n"); } } void initCPU(ThreadContext *tc, int cpuId) { // This function is essentially performing a reset. The actual INIT // interrupt does a subset of this, so we'll piggyback on some of its // functionality. InitInterrupt init(0); init.invoke(tc); PCState pc = tc->pcState(); pc.upc(0); pc.nupc(1); tc->pcState(pc); // These next two loops zero internal microcode and implicit registers. // They aren't specified by the ISA but are used internally by M5's // implementation. for (int index = 0; index < NumMicroIntRegs; index++) { tc->setIntReg(INTREG_MICRO(index), 0); } for (int index = 0; index < NumImplicitIntRegs; index++) { tc->setIntReg(INTREG_IMPLICIT(index), 0); } // Set integer register EAX to 0 to indicate that the optional BIST // passed. No BIST actually runs, but software may still check this // register for errors. tc->setIntReg(INTREG_RAX, 0); tc->setMiscReg(MISCREG_CR0, 0x0000000060000010ULL); tc->setMiscReg(MISCREG_CR8, 0); // TODO initialize x87, 64 bit, and 128 bit media state tc->setMiscReg(MISCREG_MTRRCAP, 0x0508); for (int i = 0; i < 8; i++) { tc->setMiscReg(MISCREG_MTRR_PHYS_BASE(i), 0); tc->setMiscReg(MISCREG_MTRR_PHYS_MASK(i), 0); } tc->setMiscReg(MISCREG_MTRR_FIX_64K_00000, 0); tc->setMiscReg(MISCREG_MTRR_FIX_16K_80000, 0); tc->setMiscReg(MISCREG_MTRR_FIX_16K_A0000, 0); tc->setMiscReg(MISCREG_MTRR_FIX_4K_C0000, 0); tc->setMiscReg(MISCREG_MTRR_FIX_4K_C8000, 0); tc->setMiscReg(MISCREG_MTRR_FIX_4K_D0000, 0); tc->setMiscReg(MISCREG_MTRR_FIX_4K_D8000, 0); tc->setMiscReg(MISCREG_MTRR_FIX_4K_E0000, 0); tc->setMiscReg(MISCREG_MTRR_FIX_4K_E8000, 0); tc->setMiscReg(MISCREG_MTRR_FIX_4K_F0000, 0); tc->setMiscReg(MISCREG_MTRR_FIX_4K_F8000, 0); tc->setMiscReg(MISCREG_DEF_TYPE, 0); tc->setMiscReg(MISCREG_MCG_CAP, 0x104); tc->setMiscReg(MISCREG_MCG_STATUS, 0); tc->setMiscReg(MISCREG_MCG_CTL, 0); for (int i = 0; i < 5; i++) { tc->setMiscReg(MISCREG_MC_CTL(i), 0); tc->setMiscReg(MISCREG_MC_STATUS(i), 0); tc->setMiscReg(MISCREG_MC_ADDR(i), 0); tc->setMiscReg(MISCREG_MC_MISC(i), 0); } tc->setMiscReg(MISCREG_TSC, 0); tc->setMiscReg(MISCREG_TSC_AUX, 0); for (int i = 0; i < 4; i++) { tc->setMiscReg(MISCREG_PERF_EVT_SEL(i), 0); tc->setMiscReg(MISCREG_PERF_EVT_CTR(i), 0); } tc->setMiscReg(MISCREG_STAR, 0); tc->setMiscReg(MISCREG_LSTAR, 0); tc->setMiscReg(MISCREG_CSTAR, 0); tc->setMiscReg(MISCREG_SF_MASK, 0); tc->setMiscReg(MISCREG_KERNEL_GS_BASE, 0); tc->setMiscReg(MISCREG_SYSENTER_CS, 0); tc->setMiscReg(MISCREG_SYSENTER_ESP, 0); tc->setMiscReg(MISCREG_SYSENTER_EIP, 0); tc->setMiscReg(MISCREG_PAT, 0x0007040600070406ULL); tc->setMiscReg(MISCREG_SYSCFG, 0x20601); tc->setMiscReg(MISCREG_IORR_BASE0, 0); tc->setMiscReg(MISCREG_IORR_BASE1, 0); tc->setMiscReg(MISCREG_IORR_MASK0, 0); tc->setMiscReg(MISCREG_IORR_MASK1, 0); tc->setMiscReg(MISCREG_TOP_MEM, 0x4000000); tc->setMiscReg(MISCREG_TOP_MEM2, 0x0); tc->setMiscReg(MISCREG_DEBUG_CTL_MSR, 0); tc->setMiscReg(MISCREG_LAST_BRANCH_FROM_IP, 0); tc->setMiscReg(MISCREG_LAST_BRANCH_TO_IP, 0); tc->setMiscReg(MISCREG_LAST_EXCEPTION_FROM_IP, 0); tc->setMiscReg(MISCREG_LAST_EXCEPTION_TO_IP, 0); // Invalidate the caches (this should already be done for us) LocalApicBase lApicBase = 0; lApicBase.base = 0xFEE00000 >> 12; lApicBase.enable = 1; lApicBase.bsp = (cpuId == 0); tc->setMiscReg(MISCREG_APIC_BASE, lApicBase); Interrupts * interrupts = dynamic_cast( tc->getCpuPtr()->getInterruptController(0)); assert(interrupts); interrupts->setRegNoEffect(APIC_ID, cpuId << 24); interrupts->setRegNoEffect(APIC_VERSION, (5 << 16) | 0x14); // TODO Set the SMRAM base address (SMBASE) to 0x00030000 tc->setMiscReg(MISCREG_VM_CR, 0); tc->setMiscReg(MISCREG_IGNNE, 0); tc->setMiscReg(MISCREG_SMM_CTL, 0); tc->setMiscReg(MISCREG_VM_HSAVE_PA, 0); } void startupCPU(ThreadContext *tc, int cpuId) { if (cpuId == 0 || !FullSystem) { tc->activate(); } else { // This is an application processor (AP). It should be initialized to // look like only the BIOS POST has run on it and put then put it into // a halted state. tc->suspend(); } } void copyMiscRegs(ThreadContext *src, ThreadContext *dest) { // This function assumes no side effects other than TLB invalidation // need to be considered while copying state. That will likely not be // true in the future. for (int i = 0; i < NUM_MISCREGS; ++i) { if (!isValidMiscReg(i)) continue; dest->setMiscRegNoEffect(i, src->readMiscRegNoEffect(i)); } // The TSC has to be updated with side-effects if the CPUs in a // CPU switch have different frequencies. dest->setMiscReg(MISCREG_TSC, src->readMiscReg(MISCREG_TSC)); dest->getITBPtr()->flushAll(); dest->getDTBPtr()->flushAll(); } void copyRegs(ThreadContext *src, ThreadContext *dest) { //copy int regs for (int i = 0; i < NumIntRegs; ++i) dest->setIntRegFlat(i, src->readIntRegFlat(i)); //copy float regs for (int i = 0; i < NumFloatRegs; ++i) dest->setFloatRegBitsFlat(i, src->readFloatRegBitsFlat(i)); //copy condition-code regs for (int i = 0; i < NumCCRegs; ++i) dest->setCCRegFlat(i, src->readCCRegFlat(i)); copyMiscRegs(src, dest); dest->pcState(src->pcState()); } void skipFunction(ThreadContext *tc) { panic("Not implemented for x86\n"); } uint64_t getRFlags(ThreadContext *tc) { const uint64_t ncc_flags(tc->readMiscRegNoEffect(MISCREG_RFLAGS)); const uint64_t cc_flags(tc->readCCReg(X86ISA::CCREG_ZAPS)); const uint64_t cfof_bits(tc->readCCReg(X86ISA::CCREG_CFOF)); const uint64_t df_bit(tc->readCCReg(X86ISA::CCREG_DF)); // ecf (PSEUDO(3)) & ezf (PSEUDO(4)) are only visible to // microcode, so we can safely ignore them. // Reconstruct the real rflags state, mask out internal flags, and // make sure reserved bits have the expected values. return ((ncc_flags | cc_flags | cfof_bits | df_bit) & 0x3F7FD5) | 0x2; } void setRFlags(ThreadContext *tc, uint64_t val) { tc->setCCReg(X86ISA::CCREG_ZAPS, val & ccFlagMask); tc->setCCReg(X86ISA::CCREG_CFOF, val & cfofMask); tc->setCCReg(X86ISA::CCREG_DF, val & DFBit); // Internal microcode registers (ECF & EZF) tc->setCCReg(X86ISA::CCREG_ECF, 0); tc->setCCReg(X86ISA::CCREG_EZF, 0); // Update the RFLAGS misc reg with whatever didn't go into the // magic registers. tc->setMiscReg(MISCREG_RFLAGS, val & ~(ccFlagMask | cfofMask | DFBit)); } uint8_t convX87TagsToXTags(uint16_t ftw) { uint8_t ftwx(0); for (int i = 0; i < 8; ++i) { // Extract the tag for the current element on the FP stack const unsigned tag((ftw >> (2 * i)) & 0x3); /* * Check the type of the current FP element. Valid values are: * 0 == Valid * 1 == Zero * 2 == Special (Nan, unsupported, infinity, denormal) * 3 == Empty */ // The xsave version of the tag word only keeps track of // whether the element is empty or not. Set the corresponding // bit in the ftwx if it's not empty, if (tag != 0x3) ftwx |= 1 << i; } return ftwx; } uint16_t convX87XTagsToTags(uint8_t ftwx) { uint16_t ftw(0); for (int i = 0; i < 8; ++i) { const unsigned xtag(((ftwx >> i) & 0x1)); // The xtag for an x87 stack position is 0 for empty stack positions. if (!xtag) { // Set the tag word to 3 (empty) for the current element. ftw |= 0x3 << (2 * i); } else { // TODO: We currently assume that non-empty elements are // valid (0x0), but we should ideally reconstruct the full // state (valid/zero/special). } } return ftw; } uint16_t genX87Tags(uint16_t ftw, uint8_t top, int8_t spm) { const uint8_t new_top((top + spm + 8) % 8); if (spm > 0) { // Removing elements from the stack. Flag the elements as empty. for (int i = top; i != new_top; i = (i + 1 + 8) % 8) ftw |= 0x3 << (2 * i); } else if (spm < 0) { // Adding elements to the stack. Flag the new elements as // valid. We should ideally decode them and "do the right // thing". for (int i = new_top; i != top; i = (i + 1 + 8) % 8) ftw &= ~(0x3 << (2 * i)); } return ftw; } double loadFloat80(const void *_mem) { fp80_t fp80; memcpy(fp80.bits, _mem, 10); return fp80_cvtd(fp80); } void storeFloat80(void *_mem, double value) { fp80_t fp80 = fp80_cvfd(value); memcpy(_mem, fp80.bits, 10); } } // namespace X86_ISA