X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Farch%2Fx86%2Futility.cc;h=cf30723487bb03eefb3b49f047e405b02b054ae2;hb=68127ca3da543db0c2f3d131d2b3f3525a35ec50;hp=0153f10e0b9061011bc63ea2a61cd6e99f272c3a;hpb=7ffd88a54b606929de3f7d401b22ad9f1bd1c81b;p=gem5.git diff --git a/src/arch/x86/utility.cc b/src/arch/x86/utility.cc index 0153f10e0..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,31 +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 @@ -97,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, 0x0000000060000010ULL); - tc->setMiscReg(MISCREG_CR2, 0); - tc->setMiscReg(MISCREG_CR3, 0); - tc->setMiscReg(MISCREG_CR4, 0); tc->setMiscReg(MISCREG_CR8, 0); - tc->setMiscReg(MISCREG_RFLAGS, 0x0000000000000002ULL); - - 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, 0x00000000ffff0000ULL); - // This has the base value pre-added. - tc->setMiscReg(MISCREG_CS_LIMIT, 0xffffffff); - tc->setMiscReg(MISCREG_CS_ATTR, codeAttr); - - tc->setPC(0x000000000000fff0ULL + - 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); @@ -192,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, 0x00000000ffff0ff0ULL); - tc->setMiscReg(MISCREG_DR7, 0x0000000000000400ULL); - tc->setMiscReg(MISCREG_TSC, 0); tc->setMiscReg(MISCREG_TSC_AUX, 0); @@ -241,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 @@ -252,179 +198,173 @@ void initCPU(ThreadContext *tc, int cpuId) tc->setMiscReg(MISCREG_VM_HSAVE_PA, 0); } -#endif - -#if FULL_SYSTEM 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. We - // won't actually set up real mode or legacy protected mode descriptor - // tables because we aren't executing any code that would require - // them. We do, however toggle the control bits in the correct order - // while allowing consistency checks and the underlying mechansims - // just to be safe. - - const int NumPDTs = 4; - - const Addr PageMapLevel4 = 0x70000; - const Addr PageDirPtrTable = 0x71000; - const Addr PageDirTable[NumPDTs] = - {0x72000, 0x73000, 0x74000, 0x75000}; - const Addr GDTBase = 0x76000; - - const int PML4Bits = 9; - const int PDPTBits = 9; - const int PDTBits = 9; - - // Get a port to write the page tables and descriptor tables. - FunctionalPort * physPort = tc->getPhysPort(); + 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(); + } +} - /* - * Set up the gdt. - */ - // Place holder at selector 0 - uint64_t nullDescriptor = 0; - physPort->writeBlob(GDTBase, (uint8_t *)(&nullDescriptor), 8); - - //64 bit code segment - SegDescriptor csDesc = 0; - csDesc.type.c = 0; // Not conforming - csDesc.dpl = 0; // Privelege level 0 - csDesc.p = 1; // Present - csDesc.l = 1; // 64 bit - csDesc.d = 0; // default operand size - //Because we're dealing with a pointer and I don't think it's - //guaranteed that there isn't anything in a nonvirtual class between - //it's beginning in memory and it's actual data, we'll use an - //intermediary. - uint64_t csDescVal = csDesc; - physPort->writeBlob(GDTBase, (uint8_t *)(&csDescVal), 8); - - tc->setMiscReg(MISCREG_GDTR_BASE, GDTBase); - tc->setMiscReg(MISCREG_GDTR_LIMIT, 0xF); +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)); + } - /* - * Identity map the first 4GB of memory. In order to map this region - * of memory in long mode, there needs to be one actual page map level - * 4 entry which points to one page directory pointer table which - * points to 4 different page directory tables which are full of two - * megabyte pages. All of the other entries in valid tables are set - * to indicate that they don't pertain to anything valid and will - * cause a fault if used. - */ + // 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)); - // Put valid values in all of the various table entries which indicate - // that those entries don't point to further tables or pages. Then - // set the values of those entries which are needed. + dest->getITBPtr()->flushAll(); + dest->getDTBPtr()->flushAll(); +} - // Page Map Level 4 +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()); +} - // read/write, user, not present - uint64_t pml4e = X86ISA::htog(0x6); - for (int offset = 0; offset < (1 << PML4Bits) * 8; offset += 8) { - physPort->writeBlob(PageMapLevel4 + offset, (uint8_t *)(&pml4e), 8); - } - // Point to the only PDPT - pml4e = X86ISA::htog(0x7 | PageDirPtrTable); - physPort->writeBlob(PageMapLevel4, (uint8_t *)(&pml4e), 8); +void +skipFunction(ThreadContext *tc) +{ + panic("Not implemented for x86\n"); +} - // Page Directory Pointer Table +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; +} - // read/write, user, not present - uint64_t pdpe = X86ISA::htog(0x6); - for (int offset = 0; offset < (1 << PDPTBits) * 8; offset += 8) { - physPort->writeBlob(PageDirPtrTable + offset, - (uint8_t *)(&pdpe), 8); - } - // Point to the PDTs - for (int table = 0; table < NumPDTs; table++) { - pdpe = X86ISA::htog(0x7 | PageDirTable[table]); - physPort->writeBlob(PageDirPtrTable + table * 8, - (uint8_t *)(&pdpe), 8); - } +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); - // Page Directory Tables - - Addr base = 0; - const Addr pageSize = 2 << 20; - for (int table = 0; table < NumPDTs; table++) { - for (int offset = 0; offset < (1 << PDTBits) * 8; offset += 8) { - // read/write, user, present, 4MB - uint64_t pdte = X86ISA::htog(0x87 | base); - physPort->writeBlob(PageDirTable[table] + offset, - (uint8_t *)(&pdte), 8); - base += pageSize; - } - } + // Internal microcode registers (ECF & EZF) + tc->setCCReg(X86ISA::CCREG_ECF, 0); + tc->setCCReg(X86ISA::CCREG_EZF, 0); - /* - * Transition from real mode all the way up to Long mode - */ - CR0 cr0 = tc->readMiscRegNoEffect(MISCREG_CR0); - //Turn off paging. - cr0.pg = 0; - tc->setMiscReg(MISCREG_CR0, cr0); - //Turn on protected mode. - cr0.pe = 1; - tc->setMiscReg(MISCREG_CR0, cr0); - - CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4); - //Turn on pae. - cr4.pae = 1; - tc->setMiscReg(MISCREG_CR4, cr4); - - //Point to the page tables. - tc->setMiscReg(MISCREG_CR3, PageMapLevel4); - - Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER); - //Enable long mode. - efer.lme = 1; - tc->setMiscReg(MISCREG_EFER, efer); - - //Activate long mode. - cr0.pg = 1; - tc->setMiscReg(MISCREG_CR0, cr0); + // 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); /* - * Far jump into 64 bit mode. + * Check the type of the current FP element. Valid values are: + * 0 == Valid + * 1 == Zero + * 2 == Special (Nan, unsupported, infinity, denormal) + * 3 == Empty */ - // Set the selector - tc->setMiscReg(MISCREG_CS, 1); - // Manually set up the segment attributes. In the future when there's - // other existing functionality to do this, that could be used - // instead. - SegAttr csAttr = 0; - csAttr.writable = 0; - csAttr.readable = 1; - csAttr.expandDown = 0; - csAttr.dpl = 0; - csAttr.defaultSize = 0; - csAttr.longMode = 1; - tc->setMiscReg(MISCREG_CS_ATTR, csAttr); - - tc->setPC(tc->getSystemPtr()->kernelEntry); - tc->setNextPC(tc->readPC()); - - // We should now be in long mode. Yay! - - tc->activate(0); - } 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(); + // 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; } -#else +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; +} -void startupCPU(ThreadContext *tc, int cpuId) +uint16_t +genX87Tags(uint16_t ftw, uint8_t top, int8_t spm) { - tc->activate(0); + 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; } -#endif +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 +} // namespace X86_ISA