utility.cc revision 10058:32784c63de81
111420Sdavid.guillen@arm.com/* 211420Sdavid.guillen@arm.com * Copyright (c) 2007 The Hewlett-Packard Development Company 311420Sdavid.guillen@arm.com * Copyright (c) 2011 Advanced Micro Devices, Inc. 411420Sdavid.guillen@arm.com * All rights reserved. 511420Sdavid.guillen@arm.com * 611420Sdavid.guillen@arm.com * The license below extends only to copyright in the software and shall 711420Sdavid.guillen@arm.com * not be construed as granting a license to any other intellectual 811420Sdavid.guillen@arm.com * property including but not limited to intellectual property relating 911420Sdavid.guillen@arm.com * to a hardware implementation of the functionality of the software 1011420Sdavid.guillen@arm.com * licensed hereunder. You may use the software subject to the license 1111420Sdavid.guillen@arm.com * terms below provided that you ensure that this notice is replicated 1211420Sdavid.guillen@arm.com * unmodified and in its entirety in all distributions of the software, 1311420Sdavid.guillen@arm.com * modified or unmodified, in source code or in binary form. 1411420Sdavid.guillen@arm.com * 1511420Sdavid.guillen@arm.com * Redistribution and use in source and binary forms, with or without 1611420Sdavid.guillen@arm.com * modification, are permitted provided that the following conditions are 1711420Sdavid.guillen@arm.com * met: redistributions of source code must retain the above copyright 1811420Sdavid.guillen@arm.com * notice, this list of conditions and the following disclaimer; 1911420Sdavid.guillen@arm.com * redistributions in binary form must reproduce the above copyright 2011420Sdavid.guillen@arm.com * notice, this list of conditions and the following disclaimer in the 2111420Sdavid.guillen@arm.com * documentation and/or other materials provided with the distribution; 2211420Sdavid.guillen@arm.com * neither the name of the copyright holders nor the names of its 2311420Sdavid.guillen@arm.com * contributors may be used to endorse or promote products derived from 2411420Sdavid.guillen@arm.com * this software without specific prior written permission. 2511420Sdavid.guillen@arm.com * 2611420Sdavid.guillen@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2711420Sdavid.guillen@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2811420Sdavid.guillen@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2911420Sdavid.guillen@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3011420Sdavid.guillen@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3111420Sdavid.guillen@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3211420Sdavid.guillen@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3311420Sdavid.guillen@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3411420Sdavid.guillen@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3511420Sdavid.guillen@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3611420Sdavid.guillen@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3711420Sdavid.guillen@arm.com * 3811420Sdavid.guillen@arm.com * Authors: Gabe Black 3911420Sdavid.guillen@arm.com */ 4011420Sdavid.guillen@arm.com 4111420Sdavid.guillen@arm.com#include "arch/x86/interrupts.hh" 4211420Sdavid.guillen@arm.com#include "arch/x86/registers.hh" 4311420Sdavid.guillen@arm.com#include "arch/x86/tlb.hh" 4411420Sdavid.guillen@arm.com#include "arch/x86/utility.hh" 4511420Sdavid.guillen@arm.com#include "arch/x86/x86_traits.hh" 4611420Sdavid.guillen@arm.com#include "cpu/base.hh" 4711420Sdavid.guillen@arm.com#include "fputils/fp80.h" 4811420Sdavid.guillen@arm.com#include "sim/system.hh" 4911420Sdavid.guillen@arm.com 5011899Sandreas.sandberg@arm.comnamespace X86ISA { 5111420Sdavid.guillen@arm.com 5211899Sandreas.sandberg@arm.comuint64_t 5311420Sdavid.guillen@arm.comgetArgument(ThreadContext *tc, int &number, uint16_t size, bool fp) 5411420Sdavid.guillen@arm.com{ 5511420Sdavid.guillen@arm.com if (!FullSystem) { 5611420Sdavid.guillen@arm.com panic("getArgument() only implemented for full system mode.\n"); 5711420Sdavid.guillen@arm.com } else if (fp) { 5811420Sdavid.guillen@arm.com panic("getArgument(): Floating point arguments not implemented\n"); 5911420Sdavid.guillen@arm.com } else if (size != 8) { 6011420Sdavid.guillen@arm.com panic("getArgument(): Can only handle 64-bit arguments.\n"); 6111420Sdavid.guillen@arm.com } 6211420Sdavid.guillen@arm.com 6311420Sdavid.guillen@arm.com // The first 6 integer arguments are passed in registers, the rest 6411420Sdavid.guillen@arm.com // are passed on the stack. 6511420Sdavid.guillen@arm.com const int int_reg_map[] = { 6611420Sdavid.guillen@arm.com INTREG_RDI, INTREG_RSI, INTREG_RDX, 6711420Sdavid.guillen@arm.com INTREG_RCX, INTREG_R8, INTREG_R9 6811420Sdavid.guillen@arm.com }; 6911420Sdavid.guillen@arm.com if (number < sizeof(int_reg_map) / sizeof(*int_reg_map)) { 7011420Sdavid.guillen@arm.com return tc->readIntReg(int_reg_map[number]); 7111420Sdavid.guillen@arm.com } else { 7211420Sdavid.guillen@arm.com panic("getArgument(): Don't know how to handle stack arguments.\n"); 7311420Sdavid.guillen@arm.com } 7411420Sdavid.guillen@arm.com} 7511420Sdavid.guillen@arm.com 7611442Sandreas.hansson@arm.comvoid initCPU(ThreadContext *tc, int cpuId) 7711420Sdavid.guillen@arm.com{ 7811420Sdavid.guillen@arm.com // This function is essentially performing a reset. The actual INIT 7911420Sdavid.guillen@arm.com // interrupt does a subset of this, so we'll piggyback on some of its 8011420Sdavid.guillen@arm.com // functionality. 8111420Sdavid.guillen@arm.com InitInterrupt init(0); 8211420Sdavid.guillen@arm.com init.invoke(tc); 8311420Sdavid.guillen@arm.com 8411420Sdavid.guillen@arm.com PCState pc = tc->pcState(); 8511420Sdavid.guillen@arm.com pc.upc(0); 8611420Sdavid.guillen@arm.com pc.nupc(1); 8711420Sdavid.guillen@arm.com tc->pcState(pc); 8811420Sdavid.guillen@arm.com 8911420Sdavid.guillen@arm.com // These next two loops zero internal microcode and implicit registers. 9011420Sdavid.guillen@arm.com // They aren't specified by the ISA but are used internally by M5's 9111420Sdavid.guillen@arm.com // implementation. 9211420Sdavid.guillen@arm.com for (int index = 0; index < NumMicroIntRegs; index++) { 9311420Sdavid.guillen@arm.com tc->setIntReg(INTREG_MICRO(index), 0); 9411420Sdavid.guillen@arm.com } 9511420Sdavid.guillen@arm.com 9611420Sdavid.guillen@arm.com for (int index = 0; index < NumImplicitIntRegs; index++) { 9711420Sdavid.guillen@arm.com tc->setIntReg(INTREG_IMPLICIT(index), 0); 9811420Sdavid.guillen@arm.com } 9911420Sdavid.guillen@arm.com 10011442Sandreas.hansson@arm.com // Set integer register EAX to 0 to indicate that the optional BIST 10111420Sdavid.guillen@arm.com // passed. No BIST actually runs, but software may still check this 10211420Sdavid.guillen@arm.com // register for errors. 10311420Sdavid.guillen@arm.com tc->setIntReg(INTREG_RAX, 0); 10411420Sdavid.guillen@arm.com 10511420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_CR0, 0x0000000060000010ULL); 10611420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_CR8, 0); 10711420Sdavid.guillen@arm.com 10811420Sdavid.guillen@arm.com // TODO initialize x87, 64 bit, and 128 bit media state 10911420Sdavid.guillen@arm.com 11011420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MTRRCAP, 0x0508); 11111420Sdavid.guillen@arm.com for (int i = 0; i < 8; i++) { 11211420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MTRR_PHYS_BASE(i), 0); 11311420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MTRR_PHYS_MASK(i), 0); 11411420Sdavid.guillen@arm.com } 11511420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MTRR_FIX_64K_00000, 0); 11611420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MTRR_FIX_16K_80000, 0); 11711420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MTRR_FIX_16K_A0000, 0); 11811420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MTRR_FIX_4K_C0000, 0); 11911420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MTRR_FIX_4K_C8000, 0); 12011420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MTRR_FIX_4K_D0000, 0); 12111420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MTRR_FIX_4K_D8000, 0); 12211420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MTRR_FIX_4K_E0000, 0); 12311420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MTRR_FIX_4K_E8000, 0); 12411420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MTRR_FIX_4K_F0000, 0); 12511420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MTRR_FIX_4K_F8000, 0); 12611420Sdavid.guillen@arm.com 12711420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_DEF_TYPE, 0); 12811420Sdavid.guillen@arm.com 12911442Sandreas.hansson@arm.com tc->setMiscReg(MISCREG_MCG_CAP, 0x104); 13011420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MCG_STATUS, 0); 13111420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MCG_CTL, 0); 13211420Sdavid.guillen@arm.com 13311420Sdavid.guillen@arm.com for (int i = 0; i < 5; i++) { 13411420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MC_CTL(i), 0); 13511420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MC_STATUS(i), 0); 13611420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MC_ADDR(i), 0); 13711420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_MC_MISC(i), 0); 13811420Sdavid.guillen@arm.com } 13911420Sdavid.guillen@arm.com 14011420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_TSC, 0); 14111420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_TSC_AUX, 0); 14211420Sdavid.guillen@arm.com 14311420Sdavid.guillen@arm.com for (int i = 0; i < 4; i++) { 14411420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_PERF_EVT_SEL(i), 0); 14511420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_PERF_EVT_CTR(i), 0); 14611420Sdavid.guillen@arm.com } 14711420Sdavid.guillen@arm.com 14811420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_STAR, 0); 14911420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_LSTAR, 0); 15011420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_CSTAR, 0); 15111420Sdavid.guillen@arm.com 15211420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_SF_MASK, 0); 15311420Sdavid.guillen@arm.com 15411420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_KERNEL_GS_BASE, 0); 15511420Sdavid.guillen@arm.com 15611420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_SYSENTER_CS, 0); 15711420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_SYSENTER_ESP, 0); 15811420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_SYSENTER_EIP, 0); 15911420Sdavid.guillen@arm.com 16011420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_PAT, 0x0007040600070406ULL); 16111420Sdavid.guillen@arm.com 16211442Sandreas.hansson@arm.com tc->setMiscReg(MISCREG_SYSCFG, 0x20601); 16311420Sdavid.guillen@arm.com 16411420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_IORR_BASE0, 0); 16511420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_IORR_BASE1, 0); 16611420Sdavid.guillen@arm.com 16711420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_IORR_MASK0, 0); 16811420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_IORR_MASK1, 0); 16911420Sdavid.guillen@arm.com 17011420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_TOP_MEM, 0x4000000); 17111420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_TOP_MEM2, 0x0); 17211420Sdavid.guillen@arm.com 17311420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_DEBUG_CTL_MSR, 0); 17411420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_LAST_BRANCH_FROM_IP, 0); 17511420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_LAST_BRANCH_TO_IP, 0); 17611420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_LAST_EXCEPTION_FROM_IP, 0); 17711420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_LAST_EXCEPTION_TO_IP, 0); 17811420Sdavid.guillen@arm.com 17911420Sdavid.guillen@arm.com // Invalidate the caches (this should already be done for us) 18011420Sdavid.guillen@arm.com 18111420Sdavid.guillen@arm.com LocalApicBase lApicBase = 0; 18212088Sspwilson2@wisc.edu lApicBase.base = 0xFEE00000 >> 12; 18311420Sdavid.guillen@arm.com lApicBase.enable = 1; 18411420Sdavid.guillen@arm.com lApicBase.bsp = (cpuId == 0); 18511420Sdavid.guillen@arm.com tc->setMiscReg(MISCREG_APIC_BASE, lApicBase); 18611420Sdavid.guillen@arm.com 18711420Sdavid.guillen@arm.com Interrupts * interrupts = dynamic_cast<Interrupts *>( 18811420Sdavid.guillen@arm.com tc->getCpuPtr()->getInterruptController()); 18911420Sdavid.guillen@arm.com assert(interrupts); 190 191 interrupts->setRegNoEffect(APIC_ID, cpuId << 24); 192 193 interrupts->setRegNoEffect(APIC_VERSION, (5 << 16) | 0x14); 194 195 // TODO Set the SMRAM base address (SMBASE) to 0x00030000 196 197 tc->setMiscReg(MISCREG_VM_CR, 0); 198 tc->setMiscReg(MISCREG_IGNNE, 0); 199 tc->setMiscReg(MISCREG_SMM_CTL, 0); 200 tc->setMiscReg(MISCREG_VM_HSAVE_PA, 0); 201} 202 203void startupCPU(ThreadContext *tc, int cpuId) 204{ 205 if (cpuId == 0 || !FullSystem) { 206 tc->activate(Cycles(0)); 207 } else { 208 // This is an application processor (AP). It should be initialized to 209 // look like only the BIOS POST has run on it and put then put it into 210 // a halted state. 211 tc->suspend(Cycles(0)); 212 } 213} 214 215void 216copyMiscRegs(ThreadContext *src, ThreadContext *dest) 217{ 218 // This function assumes no side effects other than TLB invalidation 219 // need to be considered while copying state. That will likely not be 220 // true in the future. 221 for (int i = 0; i < NUM_MISCREGS; ++i) { 222 if ( ( i != MISCREG_CR1 && 223 !(i > MISCREG_CR4 && i < MISCREG_CR8) && 224 !(i > MISCREG_CR8 && i <= MISCREG_CR15) ) == false) { 225 continue; 226 } 227 dest->setMiscRegNoEffect(i, src->readMiscRegNoEffect(i)); 228 } 229 230 // The TSC has to be updated with side-effects if the CPUs in a 231 // CPU switch have different frequencies. 232 dest->setMiscReg(MISCREG_TSC, src->readMiscReg(MISCREG_TSC)); 233 234 dest->getITBPtr()->flushAll(); 235 dest->getDTBPtr()->flushAll(); 236} 237 238void 239copyRegs(ThreadContext *src, ThreadContext *dest) 240{ 241 //copy int regs 242 for (int i = 0; i < NumIntRegs; ++i) 243 dest->setIntRegFlat(i, src->readIntRegFlat(i)); 244 //copy float regs 245 for (int i = 0; i < NumFloatRegs; ++i) 246 dest->setFloatRegBitsFlat(i, src->readFloatRegBitsFlat(i)); 247 //copy condition-code regs 248 for (int i = 0; i < NumCCRegs; ++i) 249 dest->setCCRegFlat(i, src->readCCRegFlat(i)); 250 copyMiscRegs(src, dest); 251 dest->pcState(src->pcState()); 252} 253 254void 255skipFunction(ThreadContext *tc) 256{ 257 panic("Not implemented for x86\n"); 258} 259 260uint64_t 261getRFlags(ThreadContext *tc) 262{ 263 const uint64_t ncc_flags(tc->readMiscRegNoEffect(MISCREG_RFLAGS)); 264 const uint64_t cc_flags(tc->readCCReg(X86ISA::CCREG_ZAPS)); 265 const uint64_t cfof_bits(tc->readCCReg(X86ISA::CCREG_CFOF)); 266 const uint64_t df_bit(tc->readCCReg(X86ISA::CCREG_DF)); 267 // ecf (PSEUDO(3)) & ezf (PSEUDO(4)) are only visible to 268 // microcode, so we can safely ignore them. 269 270 // Reconstruct the real rflags state, mask out internal flags, and 271 // make sure reserved bits have the expected values. 272 return ((ncc_flags | cc_flags | cfof_bits | df_bit) & 0x3F7FD5) 273 | 0x2; 274} 275 276void 277setRFlags(ThreadContext *tc, uint64_t val) 278{ 279 tc->setCCReg(X86ISA::CCREG_ZAPS, val & ccFlagMask); 280 tc->setCCReg(X86ISA::CCREG_CFOF, val & cfofMask); 281 tc->setCCReg(X86ISA::CCREG_DF, val & DFBit); 282 283 // Internal microcode registers (ECF & EZF) 284 tc->setCCReg(X86ISA::CCREG_ECF, 0); 285 tc->setCCReg(X86ISA::CCREG_EZF, 0); 286 287 // Update the RFLAGS misc reg with whatever didn't go into the 288 // magic registers. 289 tc->setMiscReg(MISCREG_RFLAGS, val & ~(ccFlagMask | cfofMask | DFBit)); 290} 291 292uint8_t 293convX87TagsToXTags(uint16_t ftw) 294{ 295 uint8_t ftwx(0); 296 for (int i = 0; i < 8; ++i) { 297 // Extract the tag for the current element on the FP stack 298 const unsigned tag((ftw >> (2 * i)) & 0x3); 299 300 /* 301 * Check the type of the current FP element. Valid values are: 302 * 0 == Valid 303 * 1 == Zero 304 * 2 == Special (Nan, unsupported, infinity, denormal) 305 * 3 == Empty 306 */ 307 // The xsave version of the tag word only keeps track of 308 // whether the element is empty or not. Set the corresponding 309 // bit in the ftwx if it's not empty, 310 if (tag != 0x3) 311 ftwx |= 1 << i; 312 } 313 314 return ftwx; 315} 316 317uint16_t 318convX87XTagsToTags(uint8_t ftwx) 319{ 320 uint16_t ftw(0); 321 for (int i = 0; i < 8; ++i) { 322 const unsigned xtag(((ftwx >> i) & 0x1)); 323 324 // The xtag for an x87 stack position is 0 for empty stack positions. 325 if (!xtag) { 326 // Set the tag word to 3 (empty) for the current element. 327 ftw |= 0x3 << (2 * i); 328 } else { 329 // TODO: We currently assume that non-empty elements are 330 // valid (0x0), but we should ideally reconstruct the full 331 // state (valid/zero/special). 332 } 333 } 334 335 return ftw; 336} 337 338uint16_t 339genX87Tags(uint16_t ftw, uint8_t top, int8_t spm) 340{ 341 const uint8_t new_top((top + spm + 8) % 8); 342 343 if (spm > 0) { 344 // Removing elements from the stack. Flag the elements as empty. 345 for (int i = top; i != new_top; i = (i + 1 + 8) % 8) 346 ftw |= 0x3 << (2 * i); 347 } else if (spm < 0) { 348 // Adding elements to the stack. Flag the new elements as 349 // valid. We should ideally decode them and "do the right 350 // thing". 351 for (int i = new_top; i != top; i = (i + 1 + 8) % 8) 352 ftw &= ~(0x3 << (2 * i)); 353 } 354 355 return ftw; 356} 357 358double 359loadFloat80(const void *_mem) 360{ 361 const fp80_t *fp80((const fp80_t *)_mem); 362 363 return fp80_cvtd(*fp80); 364} 365 366void 367storeFloat80(void *_mem, double value) 368{ 369 fp80_t *fp80((fp80_t *)_mem); 370 371 *fp80 = fp80_cvfd(value); 372} 373 374} // namespace X86_ISA 375