utility.cc revision 11150
1/* 2 * Copyright (c) 2007 The Hewlett-Packard Development Company 3 * Copyright (c) 2011 Advanced Micro Devices, Inc. 4 * All rights reserved. 5 * 6 * The license below extends only to copyright in the software and shall 7 * not be construed as granting a license to any other intellectual 8 * property including but not limited to intellectual property relating 9 * to a hardware implementation of the functionality of the software 10 * licensed hereunder. You may use the software subject to the license 11 * terms below provided that you ensure that this notice is replicated 12 * unmodified and in its entirety in all distributions of the software, 13 * modified or unmodified, in source code or in binary form. 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions are 17 * met: redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer; 19 * redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution; 22 * neither the name of the copyright holders nor the names of its 23 * contributors may be used to endorse or promote products derived from 24 * this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 * 38 * Authors: Gabe Black 39 */ 40 41#include "arch/x86/interrupts.hh" 42#include "arch/x86/registers.hh" 43#include "arch/x86/tlb.hh" 44#include "arch/x86/utility.hh" 45#include "arch/x86/x86_traits.hh" 46#include "cpu/base.hh" 47#include "fputils/fp80.h" 48#include "sim/system.hh" 49 50namespace X86ISA { 51 52uint64_t 53getArgument(ThreadContext *tc, int &number, uint16_t size, bool fp) 54{ 55 if (fp) { 56 panic("getArgument(): Floating point arguments not implemented\n"); 57 } else if (size != 8) { 58 panic("getArgument(): Can only handle 64-bit arguments.\n"); 59 } 60 61 // The first 6 integer arguments are passed in registers, the rest 62 // are passed on the stack. 63 const int int_reg_map[] = { 64 INTREG_RDI, INTREG_RSI, INTREG_RDX, 65 INTREG_RCX, INTREG_R8, INTREG_R9 66 }; 67 if (number < sizeof(int_reg_map) / sizeof(*int_reg_map)) { 68 return tc->readIntReg(int_reg_map[number]); 69 } else { 70 panic("getArgument(): Don't know how to handle stack arguments.\n"); 71 } 72} 73 74void initCPU(ThreadContext *tc, int cpuId) 75{ 76 // This function is essentially performing a reset. The actual INIT 77 // interrupt does a subset of this, so we'll piggyback on some of its 78 // functionality. 79 InitInterrupt init(0); 80 init.invoke(tc); 81 82 PCState pc = tc->pcState(); 83 pc.upc(0); 84 pc.nupc(1); 85 tc->pcState(pc); 86 87 // These next two loops zero internal microcode and implicit registers. 88 // They aren't specified by the ISA but are used internally by M5's 89 // implementation. 90 for (int index = 0; index < NumMicroIntRegs; index++) { 91 tc->setIntReg(INTREG_MICRO(index), 0); 92 } 93 94 for (int index = 0; index < NumImplicitIntRegs; index++) { 95 tc->setIntReg(INTREG_IMPLICIT(index), 0); 96 } 97 98 // Set integer register EAX to 0 to indicate that the optional BIST 99 // passed. No BIST actually runs, but software may still check this 100 // register for errors. 101 tc->setIntReg(INTREG_RAX, 0); 102 103 tc->setMiscReg(MISCREG_CR0, 0x0000000060000010ULL); 104 tc->setMiscReg(MISCREG_CR8, 0); 105 106 // TODO initialize x87, 64 bit, and 128 bit media state 107 108 tc->setMiscReg(MISCREG_MTRRCAP, 0x0508); 109 for (int i = 0; i < 8; i++) { 110 tc->setMiscReg(MISCREG_MTRR_PHYS_BASE(i), 0); 111 tc->setMiscReg(MISCREG_MTRR_PHYS_MASK(i), 0); 112 } 113 tc->setMiscReg(MISCREG_MTRR_FIX_64K_00000, 0); 114 tc->setMiscReg(MISCREG_MTRR_FIX_16K_80000, 0); 115 tc->setMiscReg(MISCREG_MTRR_FIX_16K_A0000, 0); 116 tc->setMiscReg(MISCREG_MTRR_FIX_4K_C0000, 0); 117 tc->setMiscReg(MISCREG_MTRR_FIX_4K_C8000, 0); 118 tc->setMiscReg(MISCREG_MTRR_FIX_4K_D0000, 0); 119 tc->setMiscReg(MISCREG_MTRR_FIX_4K_D8000, 0); 120 tc->setMiscReg(MISCREG_MTRR_FIX_4K_E0000, 0); 121 tc->setMiscReg(MISCREG_MTRR_FIX_4K_E8000, 0); 122 tc->setMiscReg(MISCREG_MTRR_FIX_4K_F0000, 0); 123 tc->setMiscReg(MISCREG_MTRR_FIX_4K_F8000, 0); 124 125 tc->setMiscReg(MISCREG_DEF_TYPE, 0); 126 127 tc->setMiscReg(MISCREG_MCG_CAP, 0x104); 128 tc->setMiscReg(MISCREG_MCG_STATUS, 0); 129 tc->setMiscReg(MISCREG_MCG_CTL, 0); 130 131 for (int i = 0; i < 5; i++) { 132 tc->setMiscReg(MISCREG_MC_CTL(i), 0); 133 tc->setMiscReg(MISCREG_MC_STATUS(i), 0); 134 tc->setMiscReg(MISCREG_MC_ADDR(i), 0); 135 tc->setMiscReg(MISCREG_MC_MISC(i), 0); 136 } 137 138 tc->setMiscReg(MISCREG_TSC, 0); 139 tc->setMiscReg(MISCREG_TSC_AUX, 0); 140 141 for (int i = 0; i < 4; i++) { 142 tc->setMiscReg(MISCREG_PERF_EVT_SEL(i), 0); 143 tc->setMiscReg(MISCREG_PERF_EVT_CTR(i), 0); 144 } 145 146 tc->setMiscReg(MISCREG_STAR, 0); 147 tc->setMiscReg(MISCREG_LSTAR, 0); 148 tc->setMiscReg(MISCREG_CSTAR, 0); 149 150 tc->setMiscReg(MISCREG_SF_MASK, 0); 151 152 tc->setMiscReg(MISCREG_KERNEL_GS_BASE, 0); 153 154 tc->setMiscReg(MISCREG_SYSENTER_CS, 0); 155 tc->setMiscReg(MISCREG_SYSENTER_ESP, 0); 156 tc->setMiscReg(MISCREG_SYSENTER_EIP, 0); 157 158 tc->setMiscReg(MISCREG_PAT, 0x0007040600070406ULL); 159 160 tc->setMiscReg(MISCREG_SYSCFG, 0x20601); 161 162 tc->setMiscReg(MISCREG_IORR_BASE0, 0); 163 tc->setMiscReg(MISCREG_IORR_BASE1, 0); 164 165 tc->setMiscReg(MISCREG_IORR_MASK0, 0); 166 tc->setMiscReg(MISCREG_IORR_MASK1, 0); 167 168 tc->setMiscReg(MISCREG_TOP_MEM, 0x4000000); 169 tc->setMiscReg(MISCREG_TOP_MEM2, 0x0); 170 171 tc->setMiscReg(MISCREG_DEBUG_CTL_MSR, 0); 172 tc->setMiscReg(MISCREG_LAST_BRANCH_FROM_IP, 0); 173 tc->setMiscReg(MISCREG_LAST_BRANCH_TO_IP, 0); 174 tc->setMiscReg(MISCREG_LAST_EXCEPTION_FROM_IP, 0); 175 tc->setMiscReg(MISCREG_LAST_EXCEPTION_TO_IP, 0); 176 177 // Invalidate the caches (this should already be done for us) 178 179 LocalApicBase lApicBase = 0; 180 lApicBase.base = 0xFEE00000 >> 12; 181 lApicBase.enable = 1; 182 lApicBase.bsp = (cpuId == 0); 183 tc->setMiscReg(MISCREG_APIC_BASE, lApicBase); 184 185 Interrupts * interrupts = dynamic_cast<Interrupts *>( 186 tc->getCpuPtr()->getInterruptController(0)); 187 assert(interrupts); 188 189 interrupts->setRegNoEffect(APIC_ID, cpuId << 24); 190 191 interrupts->setRegNoEffect(APIC_VERSION, (5 << 16) | 0x14); 192 193 // TODO Set the SMRAM base address (SMBASE) to 0x00030000 194 195 tc->setMiscReg(MISCREG_VM_CR, 0); 196 tc->setMiscReg(MISCREG_IGNNE, 0); 197 tc->setMiscReg(MISCREG_SMM_CTL, 0); 198 tc->setMiscReg(MISCREG_VM_HSAVE_PA, 0); 199} 200 201void startupCPU(ThreadContext *tc, int cpuId) 202{ 203 if (cpuId == 0 || !FullSystem) { 204 tc->activate(); 205 } else { 206 // This is an application processor (AP). It should be initialized to 207 // look like only the BIOS POST has run on it and put then put it into 208 // a halted state. 209 tc->suspend(); 210 } 211} 212 213void 214copyMiscRegs(ThreadContext *src, ThreadContext *dest) 215{ 216 // This function assumes no side effects other than TLB invalidation 217 // need to be considered while copying state. That will likely not be 218 // true in the future. 219 for (int i = 0; i < NUM_MISCREGS; ++i) { 220 if ( ( i != MISCREG_CR1 && 221 !(i > MISCREG_CR4 && i < MISCREG_CR8) && 222 !(i > MISCREG_CR8 && i <= MISCREG_CR15) ) == false) { 223 continue; 224 } 225 dest->setMiscRegNoEffect(i, src->readMiscRegNoEffect(i)); 226 } 227 228 // The TSC has to be updated with side-effects if the CPUs in a 229 // CPU switch have different frequencies. 230 dest->setMiscReg(MISCREG_TSC, src->readMiscReg(MISCREG_TSC)); 231 232 dest->getITBPtr()->flushAll(); 233 dest->getDTBPtr()->flushAll(); 234} 235 236void 237copyRegs(ThreadContext *src, ThreadContext *dest) 238{ 239 //copy int regs 240 for (int i = 0; i < NumIntRegs; ++i) 241 dest->setIntRegFlat(i, src->readIntRegFlat(i)); 242 //copy float regs 243 for (int i = 0; i < NumFloatRegs; ++i) 244 dest->setFloatRegBitsFlat(i, src->readFloatRegBitsFlat(i)); 245 //copy condition-code regs 246 for (int i = 0; i < NumCCRegs; ++i) 247 dest->setCCRegFlat(i, src->readCCRegFlat(i)); 248 copyMiscRegs(src, dest); 249 dest->pcState(src->pcState()); 250} 251 252void 253skipFunction(ThreadContext *tc) 254{ 255 panic("Not implemented for x86\n"); 256} 257 258uint64_t 259getRFlags(ThreadContext *tc) 260{ 261 const uint64_t ncc_flags(tc->readMiscRegNoEffect(MISCREG_RFLAGS)); 262 const uint64_t cc_flags(tc->readCCReg(X86ISA::CCREG_ZAPS)); 263 const uint64_t cfof_bits(tc->readCCReg(X86ISA::CCREG_CFOF)); 264 const uint64_t df_bit(tc->readCCReg(X86ISA::CCREG_DF)); 265 // ecf (PSEUDO(3)) & ezf (PSEUDO(4)) are only visible to 266 // microcode, so we can safely ignore them. 267 268 // Reconstruct the real rflags state, mask out internal flags, and 269 // make sure reserved bits have the expected values. 270 return ((ncc_flags | cc_flags | cfof_bits | df_bit) & 0x3F7FD5) 271 | 0x2; 272} 273 274void 275setRFlags(ThreadContext *tc, uint64_t val) 276{ 277 tc->setCCReg(X86ISA::CCREG_ZAPS, val & ccFlagMask); 278 tc->setCCReg(X86ISA::CCREG_CFOF, val & cfofMask); 279 tc->setCCReg(X86ISA::CCREG_DF, val & DFBit); 280 281 // Internal microcode registers (ECF & EZF) 282 tc->setCCReg(X86ISA::CCREG_ECF, 0); 283 tc->setCCReg(X86ISA::CCREG_EZF, 0); 284 285 // Update the RFLAGS misc reg with whatever didn't go into the 286 // magic registers. 287 tc->setMiscReg(MISCREG_RFLAGS, val & ~(ccFlagMask | cfofMask | DFBit)); 288} 289 290uint8_t 291convX87TagsToXTags(uint16_t ftw) 292{ 293 uint8_t ftwx(0); 294 for (int i = 0; i < 8; ++i) { 295 // Extract the tag for the current element on the FP stack 296 const unsigned tag((ftw >> (2 * i)) & 0x3); 297 298 /* 299 * Check the type of the current FP element. Valid values are: 300 * 0 == Valid 301 * 1 == Zero 302 * 2 == Special (Nan, unsupported, infinity, denormal) 303 * 3 == Empty 304 */ 305 // The xsave version of the tag word only keeps track of 306 // whether the element is empty or not. Set the corresponding 307 // bit in the ftwx if it's not empty, 308 if (tag != 0x3) 309 ftwx |= 1 << i; 310 } 311 312 return ftwx; 313} 314 315uint16_t 316convX87XTagsToTags(uint8_t ftwx) 317{ 318 uint16_t ftw(0); 319 for (int i = 0; i < 8; ++i) { 320 const unsigned xtag(((ftwx >> i) & 0x1)); 321 322 // The xtag for an x87 stack position is 0 for empty stack positions. 323 if (!xtag) { 324 // Set the tag word to 3 (empty) for the current element. 325 ftw |= 0x3 << (2 * i); 326 } else { 327 // TODO: We currently assume that non-empty elements are 328 // valid (0x0), but we should ideally reconstruct the full 329 // state (valid/zero/special). 330 } 331 } 332 333 return ftw; 334} 335 336uint16_t 337genX87Tags(uint16_t ftw, uint8_t top, int8_t spm) 338{ 339 const uint8_t new_top((top + spm + 8) % 8); 340 341 if (spm > 0) { 342 // Removing elements from the stack. Flag the elements as empty. 343 for (int i = top; i != new_top; i = (i + 1 + 8) % 8) 344 ftw |= 0x3 << (2 * i); 345 } else if (spm < 0) { 346 // Adding elements to the stack. Flag the new elements as 347 // valid. We should ideally decode them and "do the right 348 // thing". 349 for (int i = new_top; i != top; i = (i + 1 + 8) % 8) 350 ftw &= ~(0x3 << (2 * i)); 351 } 352 353 return ftw; 354} 355 356double 357loadFloat80(const void *_mem) 358{ 359 const fp80_t *fp80((const fp80_t *)_mem); 360 361 return fp80_cvtd(*fp80); 362} 363 364void 365storeFloat80(void *_mem, double value) 366{ 367 fp80_t *fp80((fp80_t *)_mem); 368 369 *fp80 = fp80_cvfd(value); 370} 371 372} // namespace X86_ISA 373