X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Farch%2Fx86%2Futility.cc;h=cf30723487bb03eefb3b49f047e405b02b054ae2;hb=68127ca3da543db0c2f3d131d2b3f3525a35ec50;hp=0eee0c93e2251a2ca9b45544f688b44bc6a6404c;hpb=b0e3aab5df9328ddfd13e396456cebdcaf0c8912;p=gem5.git diff --git a/src/arch/x86/utility.cc b/src/arch/x86/utility.cc index 0eee0c93e..cf3072348 100644 --- a/src/arch/x86/utility.cc +++ b/src/arch/x86/utility.cc @@ -1,44 +1,27 @@ /* * Copyright (c) 2007 The Hewlett-Packard Development Company + * Copyright (c) 2011 Advanced Micro Devices, Inc. * All rights reserved. * - * Redistribution and use of this software in source and binary forms, - * with or without modification, are permitted provided that the - * following conditions are met: + * 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. * - * The software must be used only for Non-Commercial Use which means any - * use which is NOT directed to receiving any direct monetary - * compensation for, or commercial advantage from such use. Illustrative - * examples of non-commercial use are academic research, personal study, - * teaching, education and corporate research & development. - * Illustrative examples of commercial use are distributing products for - * commercial advantage and providing services using the software for - * commercial advantage. - * - * If you wish to use this software or functionality therein that may be - * covered by patents for commercial use, please contact: - * Director of Intellectual Property Licensing - * Office of Strategy and Technology - * Hewlett-Packard Company - * 1501 Page Mill Road - * Palo Alto, California 94304 - * - * 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 HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its + * 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. No right of - * sublicense is granted herewith. Derivatives of the software and - * output created using the software may be prepared, but only for - * Non-Commercial Uses. Derivatives of the software may be shared with - * others provided: (i) the others agree to abide by the list of - * conditions herein which includes the Non-Commercial Use restrictions; - * and (ii) such Derivatives of the software include the above copyright - * notice to acknowledge the contribution from this software where - * applicable, this list of conditions and the disclaimer below. + * 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 @@ -55,30 +38,51 @@ * Authors: Gabe Black */ -#include "arch/x86/intregs.hh" -#include "arch/x86/miscregs.hh" -#include "arch/x86/segmentregs.hh" +#include "arch/x86/interrupts.hh" +#include "arch/x86/registers.hh" +#include "arch/x86/tlb.hh" #include "arch/x86/utility.hh" #include "arch/x86/x86_traits.hh" +#include "cpu/base.hh" +#include "fputils/fp80.h" +#include "sim/system.hh" namespace X86ISA { -uint64_t getArgument(ThreadContext *tc, int number, bool fp) { -#if FULL_SYSTEM - panic("getArgument() not implemented for x86!\n"); -#else - panic("getArgument() only implemented for FULL_SYSTEM\n"); - M5_DUMMY_RETURN -#endif +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"); + } } -# if FULL_SYSTEM void initCPU(ThreadContext *tc, int cpuId) { - // The otherwise unmodified integer registers should be set to 0. - for (int index = 0; index < NUM_INTREGS; index++) { - tc->setIntReg(index, 0); - } + // 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 @@ -96,69 +100,9 @@ void initCPU(ThreadContext *tc, int cpuId) // register for errors. tc->setIntReg(INTREG_RAX, 0); - //The following values are dictated by the architecture for after a RESET# - tc->setMiscReg(MISCREG_CR0, 0x0000000060000010); - tc->setMiscReg(MISCREG_CR2, 0); - tc->setMiscReg(MISCREG_CR3, 0); - tc->setMiscReg(MISCREG_CR4, 0); + tc->setMiscReg(MISCREG_CR0, 0x0000000060000010ULL); tc->setMiscReg(MISCREG_CR8, 0); - tc->setMiscReg(MISCREG_RFLAGS, 0x0000000000000002); - - tc->setMiscReg(MISCREG_EFER, 0); - - SegAttr dataAttr = 0; - dataAttr.writable = 1; - dataAttr.readable = 1; - dataAttr.expandDown = 0; - dataAttr.dpl = 0; - dataAttr.defaultSize = 0; - - for (int seg = 0; seg != NUM_SEGMENTREGS; seg++) { - tc->setMiscReg(MISCREG_SEG_SEL(seg), 0); - tc->setMiscReg(MISCREG_SEG_BASE(seg), 0); - tc->setMiscReg(MISCREG_SEG_LIMIT(seg), 0xffff); - tc->setMiscReg(MISCREG_SEG_ATTR(seg), dataAttr); - } - - SegAttr codeAttr = 0; - codeAttr.writable = 0; - codeAttr.readable = 1; - codeAttr.expandDown = 0; - codeAttr.dpl = 0; - codeAttr.defaultSize = 0; - - tc->setMiscReg(MISCREG_CS, 0xf000); - tc->setMiscReg(MISCREG_CS_BASE, 0x00000000ffff0000); - // This has the base value pre-added. - tc->setMiscReg(MISCREG_CS_LIMIT, 0xffffffff); - tc->setMiscReg(MISCREG_CS_ATTR, codeAttr); - - tc->setPC(0x000000000000fff0 + - tc->readMiscReg(MISCREG_CS_BASE)); - tc->setNextPC(tc->readPC() + sizeof(MachInst)); - - tc->setMiscReg(MISCREG_GDTR_BASE, 0); - tc->setMiscReg(MISCREG_GDTR_LIMIT, 0xffff); - - tc->setMiscReg(MISCREG_IDTR_BASE, 0); - tc->setMiscReg(MISCREG_IDTR_LIMIT, 0xffff); - - tc->setMiscReg(MISCREG_LDTR, 0); - tc->setMiscReg(MISCREG_LDTR_BASE, 0); - tc->setMiscReg(MISCREG_LDTR_LIMIT, 0xffff); - tc->setMiscReg(MISCREG_LDTR_ATTR, 0); - - tc->setMiscReg(MISCREG_TR, 0); - tc->setMiscReg(MISCREG_TR_BASE, 0); - tc->setMiscReg(MISCREG_TR_LIMIT, 0xffff); - tc->setMiscReg(MISCREG_TR_ATTR, 0); - - // This value should be the family/model/stepping of the processor. - // (page 418). It should be consistent with the value from CPUID, but the - // actual value probably doesn't matter much. - tc->setIntReg(INTREG_RDX, 0); - // TODO initialize x87, 64 bit, and 128 bit media state tc->setMiscReg(MISCREG_MTRRCAP, 0x0508); @@ -191,14 +135,6 @@ void initCPU(ThreadContext *tc, int cpuId) tc->setMiscReg(MISCREG_MC_MISC(i), 0); } - tc->setMiscReg(MISCREG_DR0, 0); - tc->setMiscReg(MISCREG_DR1, 0); - tc->setMiscReg(MISCREG_DR2, 0); - tc->setMiscReg(MISCREG_DR3, 0); - - tc->setMiscReg(MISCREG_DR6, 0x00000000ffff0ff0); - tc->setMiscReg(MISCREG_DR7, 0x0000000000000400); - tc->setMiscReg(MISCREG_TSC, 0); tc->setMiscReg(MISCREG_TSC_AUX, 0); @@ -219,7 +155,7 @@ void initCPU(ThreadContext *tc, int cpuId) tc->setMiscReg(MISCREG_SYSENTER_ESP, 0); tc->setMiscReg(MISCREG_SYSENTER_EIP, 0); - tc->setMiscReg(MISCREG_PAT, 0x0007040600070406); + tc->setMiscReg(MISCREG_PAT, 0x0007040600070406ULL); tc->setMiscReg(MISCREG_SYSCFG, 0x20601); @@ -240,8 +176,19 @@ void initCPU(ThreadContext *tc, int cpuId) // Invalidate the caches (this should already be done for us) - // TODO Turn on the APIC. This should be handled elsewhere but it isn't - // currently being handled at all. + 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 @@ -251,22 +198,173 @@ void initCPU(ThreadContext *tc, int cpuId) tc->setMiscReg(MISCREG_VM_HSAVE_PA, 0); } -#endif - void startupCPU(ThreadContext *tc, int cpuId) { - if (cpuId == 0) { - // This is the boot strap processor (BSP). Initialize it to look like - // the boot loader has just turned control over to the 64 bit OS. - - // Enable paging, turn on long mode, etc. - - tc->activate(0); + 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(); } } -} //namespace X86_ISA +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) +{ + const fp80_t *fp80((const fp80_t *)_mem); + + return fp80_cvtd(*fp80); +} + +void +storeFloat80(void *_mem, double value) +{ + fp80_t *fp80((fp80_t *)_mem); + + *fp80 = fp80_cvfd(value); +} + +} // namespace X86_ISA