branch merge
--HG-- extra : convert_revision : 1c56f3c6f2c50d642d2de5ddde83a55234455cec
This commit is contained in:
20
SConstruct
20
SConstruct
@@ -65,7 +65,6 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from os.path import isdir, join as joinpath
|
||||
|
||||
@@ -77,6 +76,10 @@ from os.path import isdir, join as joinpath
|
||||
# scons script, e.g., "/usr/local/bin/python2.4 `which scons` [args]".
|
||||
EnsurePythonVersion(2,4)
|
||||
|
||||
# Import subprocess after we check the version since it doesn't exist in
|
||||
# Python < 2.4.
|
||||
import subprocess
|
||||
|
||||
# Ironically, SCons 0.96 dies if you give EnsureSconsVersion a
|
||||
# 3-element version number.
|
||||
min_scons_version = (0,96,91)
|
||||
@@ -329,6 +332,21 @@ conf = Configure(env,
|
||||
conf_dir = joinpath(build_root, '.scons_config'),
|
||||
log_file = joinpath(build_root, 'scons_config.log'))
|
||||
|
||||
# Check if we should compile a 64 bit binary on Mac OS X/Darwin
|
||||
try:
|
||||
import platform
|
||||
uname = platform.uname()
|
||||
if uname[0] == 'Darwin' and compare_versions(uname[2], '9.0.0') >= 0:
|
||||
if int(subprocess.Popen('sysctl -n hw.cpu64bit_capable', shell=True,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
close_fds=True).communicate()[0][0]):
|
||||
env.Append(CCFLAGS='-arch x86_64')
|
||||
env.Append(CFLAGS='-arch x86_64')
|
||||
env.Append(LINKFLAGS='-arch x86_64')
|
||||
env.Append(ASFLAGS='-arch x86_64')
|
||||
except:
|
||||
pass
|
||||
|
||||
# Recent versions of scons substitute a "Null" object for Configure()
|
||||
# when configuration isn't necessary, e.g., if the "--help" option is
|
||||
# present. Unfortuantely this Null object always returns false,
|
||||
|
||||
@@ -97,7 +97,7 @@ execfile(cpu_models_file.srcnode().abspath)
|
||||
|
||||
# Several files are generated from the ISA description.
|
||||
# We always get the basic decoder and header file.
|
||||
isa_desc_gen_files = [ 'decoder.cc', 'decoder.hh' ]
|
||||
isa_desc_gen_files = [ 'decoder.cc', 'decoder.hh', 'max_inst_regs.hh' ]
|
||||
# We also get an execute file for each selected CPU model.
|
||||
isa_desc_gen_files += [CpuModel.dict[cpu].filename
|
||||
for cpu in env['CPU_MODELS']]
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
namespace LittleEndianGuest {}
|
||||
|
||||
#include "arch/alpha/ipr.hh"
|
||||
#include "arch/alpha/max_inst_regs.hh"
|
||||
#include "arch/alpha/types.hh"
|
||||
#include "config/full_system.hh"
|
||||
#include "sim/host.hh"
|
||||
@@ -44,6 +45,8 @@ class StaticInstPtr;
|
||||
namespace AlphaISA
|
||||
{
|
||||
using namespace LittleEndianGuest;
|
||||
using AlphaISAInst::MaxInstSrcRegs;
|
||||
using AlphaISAInst::MaxInstDestRegs;
|
||||
|
||||
// These enumerate all the registers for dependence tracking.
|
||||
enum DependenceTags {
|
||||
@@ -144,10 +147,6 @@ namespace AlphaISA
|
||||
|
||||
const int TotalDataRegs = NumIntRegs + NumFloatRegs;
|
||||
|
||||
// Static instruction parameters
|
||||
const int MaxInstSrcRegs = 3;
|
||||
const int MaxInstDestRegs = 2;
|
||||
|
||||
// semantically meaningful register indices
|
||||
const int ZeroReg = 31; // architecturally meaningful
|
||||
// the rest of these depend on the ABI
|
||||
|
||||
@@ -74,8 +74,7 @@ namespace AlphaISA
|
||||
{
|
||||
ext_inst = inst;
|
||||
#if FULL_SYSTEM
|
||||
if (pc && 0x1)
|
||||
ext_inst|=(static_cast<ExtMachInst>(pc & 0x1) << 32);
|
||||
ext_inst|=(static_cast<ExtMachInst>(pc & 0x1) << 32);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#define __ARCH_SPARC_ISA_TRAITS_HH__
|
||||
|
||||
#include "arch/sparc/types.hh"
|
||||
#include "arch/sparc/max_inst_regs.hh"
|
||||
#include "arch/sparc/sparc_traits.hh"
|
||||
#include "config/full_system.hh"
|
||||
#include "sim/host.hh"
|
||||
@@ -49,6 +50,8 @@ namespace SparcISA
|
||||
|
||||
//This makes sure the big endian versions of certain functions are used.
|
||||
using namespace BigEndianGuest;
|
||||
using SparcISAInst::MaxInstSrcRegs;
|
||||
using SparcISAInst::MaxInstDestRegs;
|
||||
|
||||
// SPARC has a delay slot
|
||||
#define ISA_HAS_DELAY_SLOT 1
|
||||
@@ -76,10 +79,6 @@ namespace SparcISA
|
||||
// Some OS syscall use a second register (o1) to return a second value
|
||||
const int SyscallPseudoReturnReg = ArgumentReg[1];
|
||||
|
||||
//XXX These numbers are bogus
|
||||
const int MaxInstSrcRegs = 8;
|
||||
const int MaxInstDestRegs = 9;
|
||||
|
||||
//8K. This value is implmentation specific; and should probably
|
||||
//be somewhere else.
|
||||
const int LogVMPageSize = 13;
|
||||
|
||||
@@ -429,6 +429,10 @@ Sparc64LiveProcess::argsInit(int intSize, int pageSize)
|
||||
threadContexts[0]->setIntReg(ArgumentReg[1], argv_array_base);
|
||||
threadContexts[0]->setIntReg(StackPointerReg, stack_min - StackBias);
|
||||
|
||||
// %g1 is a pointer to a function that should be run at exit. Since we
|
||||
// don't have anything like that, it should be set to 0.
|
||||
threadContexts[0]->setIntReg(1, 0);
|
||||
|
||||
Addr prog_entry = objFile->entryPoint();
|
||||
threadContexts[0]->setPC(prog_entry);
|
||||
threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
|
||||
@@ -658,6 +662,10 @@ Sparc32LiveProcess::argsInit(int intSize, int pageSize)
|
||||
//threadContexts[0]->setIntReg(ArgumentReg[1], argv_array_base);
|
||||
threadContexts[0]->setIntReg(StackPointerReg, stack_min);
|
||||
|
||||
// %g1 is a pointer to a function that should be run at exit. Since we
|
||||
// don't have anything like that, it should be set to 0.
|
||||
threadContexts[0]->setIntReg(1, 0);
|
||||
|
||||
uint32_t prog_entry = objFile->entryPoint();
|
||||
threadContexts[0]->setPC(prog_entry);
|
||||
threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
|
||||
|
||||
@@ -112,6 +112,7 @@ if env['TARGET_ISA'] == 'x86':
|
||||
SimObject('X86System.py')
|
||||
|
||||
# Full-system sources
|
||||
Source('pagetable_walker.cc')
|
||||
Source('system.cc')
|
||||
Source('stacktrace.cc')
|
||||
Source('vtophys.cc')
|
||||
|
||||
@@ -53,12 +53,29 @@
|
||||
#
|
||||
# Authors: Gabe Black
|
||||
|
||||
from MemObject import MemObject
|
||||
from m5.SimObject import SimObject
|
||||
from m5.params import *
|
||||
from m5.proxy import *
|
||||
from m5 import build_env
|
||||
|
||||
if build_env['FULL_SYSTEM']:
|
||||
class X86PagetableWalker(MemObject):
|
||||
type = 'X86PagetableWalker'
|
||||
cxx_namespace = 'X86ISA'
|
||||
cxx_class = 'Walker'
|
||||
port = Port("Port for the hardware table walker")
|
||||
system = Param.System(Parent.any, "system object")
|
||||
|
||||
class X86TLB(SimObject):
|
||||
type = 'X86TLB'
|
||||
cxx_namespace = 'X86ISA'
|
||||
cxx_class = 'TLB'
|
||||
abstract = True
|
||||
size = Param.Int("TLB size")
|
||||
if build_env['FULL_SYSTEM']:
|
||||
walker = Param.X86PagetableWalker(\
|
||||
X86PagetableWalker(), "page table walker")
|
||||
|
||||
class X86DTB(X86TLB):
|
||||
type = 'X86DTB'
|
||||
|
||||
@@ -93,6 +93,8 @@
|
||||
#include "arch/x86/isa_traits.hh"
|
||||
#include "mem/page_table.hh"
|
||||
#include "sim/process.hh"
|
||||
#else
|
||||
#include "arch/x86/tlb.hh"
|
||||
#endif
|
||||
|
||||
namespace X86ISA
|
||||
@@ -112,6 +114,19 @@ namespace X86ISA
|
||||
{
|
||||
panic("X86 faults are not implemented!");
|
||||
}
|
||||
|
||||
void FakeITLBFault::invoke(ThreadContext * tc)
|
||||
{
|
||||
// Start the page table walker.
|
||||
tc->getITBPtr()->walk(tc, vaddr);
|
||||
}
|
||||
|
||||
void FakeDTLBFault::invoke(ThreadContext * tc)
|
||||
{
|
||||
// Start the page table walker.
|
||||
tc->getDTBPtr()->walk(tc, vaddr);
|
||||
}
|
||||
|
||||
#else // !FULL_SYSTEM
|
||||
void FakeITLBFault::invoke(ThreadContext * tc)
|
||||
{
|
||||
|
||||
@@ -369,44 +369,28 @@ namespace X86ISA
|
||||
// the tlb on a miss and are to take the place of a hardware table walker.
|
||||
class FakeITLBFault : public X86Fault
|
||||
{
|
||||
#if !FULL_SYSTEM
|
||||
protected:
|
||||
Addr vaddr;
|
||||
public:
|
||||
FakeITLBFault(Addr _vaddr) :
|
||||
X86Fault("fake instruction tlb fault", "itlb"),
|
||||
vaddr(_vaddr)
|
||||
#else
|
||||
public:
|
||||
FakeITLBFault() :
|
||||
X86Fault("fake instruction tlb fault", "itlb")
|
||||
#endif
|
||||
{}
|
||||
|
||||
#if !FULL_SYSTEM
|
||||
void invoke(ThreadContext * tc);
|
||||
#endif
|
||||
};
|
||||
|
||||
class FakeDTLBFault : public X86Fault
|
||||
{
|
||||
#if !FULL_SYSTEM
|
||||
protected:
|
||||
Addr vaddr;
|
||||
public:
|
||||
FakeDTLBFault(Addr _vaddr) :
|
||||
X86Fault("fake data tlb fault", "dtlb"),
|
||||
vaddr(_vaddr)
|
||||
#else
|
||||
public:
|
||||
FakeDTLBFault() :
|
||||
X86Fault("fake data tlb fault", "dtlb")
|
||||
#endif
|
||||
{}
|
||||
|
||||
#if !FULL_SYSTEM
|
||||
void invoke(ThreadContext * tc);
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
*/
|
||||
|
||||
#include "arch/x86/insts/static_inst.hh"
|
||||
#include "arch/x86/segmentregs.hh"
|
||||
|
||||
namespace X86ISA
|
||||
{
|
||||
@@ -75,24 +76,27 @@ namespace X86ISA
|
||||
{
|
||||
switch (segment)
|
||||
{
|
||||
case 0:
|
||||
case SEGMENT_REG_ES:
|
||||
ccprintf(os, "ES");
|
||||
break;
|
||||
case 1:
|
||||
case SEGMENT_REG_CS:
|
||||
ccprintf(os, "CS");
|
||||
break;
|
||||
case 2:
|
||||
case SEGMENT_REG_SS:
|
||||
ccprintf(os, "SS");
|
||||
break;
|
||||
case 3:
|
||||
case SEGMENT_REG_DS:
|
||||
ccprintf(os, "DS");
|
||||
break;
|
||||
case 4:
|
||||
case SEGMENT_REG_FS:
|
||||
ccprintf(os, "FS");
|
||||
break;
|
||||
case 5:
|
||||
case SEGMENT_REG_GS:
|
||||
ccprintf(os, "GS");
|
||||
break;
|
||||
case SEGMENT_REG_INT:
|
||||
ccprintf(os, "INT");
|
||||
break;
|
||||
default:
|
||||
panic("Unrecognized segment %d\n", segment);
|
||||
}
|
||||
|
||||
@@ -61,8 +61,62 @@
|
||||
0x0F: decode OPCODE_OP_TOP5 {
|
||||
format WarnUnimpl {
|
||||
0x00: decode OPCODE_OP_BOTTOM3 {
|
||||
0x00: group6();
|
||||
0x01: group7();
|
||||
//0x00: group6();
|
||||
0x00: decode MODRM_REG {
|
||||
0x0: sldt_Mw_or_Rv();
|
||||
0x1: str_Mw_or_Rv();
|
||||
0x2: lldt_Mw_or_Rv();
|
||||
0x3: ltr_Mw_or_Rv();
|
||||
0x4: verr_Mw_or_Rv();
|
||||
0x5: verw_Mw_or_Rv();
|
||||
//0x6: jmpe_Ev(); // IA-64
|
||||
default: Inst::UD2();
|
||||
}
|
||||
//0x01: group7(); // Ugly, ugly, ugly...
|
||||
0x01: decode MODRM_MOD {
|
||||
0x3: decode MODRM_REG {
|
||||
0x0: decode MODRM_RM {
|
||||
0x1: vmcall();
|
||||
0x2: vmlaunch();
|
||||
0x3: vmresume();
|
||||
0x4: vmxoff();
|
||||
default: Inst::UD2();
|
||||
}
|
||||
0x1: decode MODRM_RM {
|
||||
0x0: monitor();
|
||||
0x1: mwait();
|
||||
default: Inst::UD2();
|
||||
}
|
||||
0x3: decode MODRM_RM {
|
||||
0x0: vmrun();
|
||||
0x1: vmmcall();
|
||||
0x2: vmload();
|
||||
0x3: vmsave();
|
||||
0x4: stgi();
|
||||
0x5: clgi();
|
||||
0x6: skinit();
|
||||
0x7: invlpga();
|
||||
}
|
||||
0x4: smsw_Rv();
|
||||
0x6: lmsw_Rv();
|
||||
0x7: decode MODRM_RM {
|
||||
0x0: swapgs();
|
||||
0x1: rdtscp();
|
||||
default: Inst::UD2();
|
||||
}
|
||||
default: Inst::UD2();
|
||||
}
|
||||
default: decode MODRM_REG {
|
||||
0x0: sgdt_Ms();
|
||||
0x1: sidt_Ms();
|
||||
0x2: lgdt_Ms();
|
||||
0x3: lidt_Ms();
|
||||
0x4: smsw_Mw();
|
||||
0x6: lmsw_Mw();
|
||||
0x7: invlpg_M();
|
||||
default: Inst::UD2();
|
||||
}
|
||||
}
|
||||
0x02: lar_Gv_Ew();
|
||||
0x03: lsl_Gv_Ew();
|
||||
//sandpile.org doesn't seem to know what this is... ?
|
||||
@@ -148,7 +202,7 @@
|
||||
0x0: decode OPCODE_OP_BOTTOM3 {
|
||||
0x0: mov_Rd_Cd();
|
||||
0x1: mov_Rd_Dd();
|
||||
0x2: mov_Cd_Rd();
|
||||
0x2: Inst::MOV(Cd,Rd);
|
||||
0x3: mov_Dd_Rd();
|
||||
0x4: mov_Rd_Td();
|
||||
0x6: mov_Td_Rd();
|
||||
@@ -397,9 +451,58 @@
|
||||
// no prefix
|
||||
0x0: decode OPCODE_OP_BOTTOM3 {
|
||||
0x0: pshufw_Pq_Qq_Ib();
|
||||
0x1: group13_pshimw();
|
||||
0x2: group14_pshimd();
|
||||
0x3: group15_pshimq();
|
||||
//0x1: group13_pshimw();
|
||||
0x1: decode MODRM_REG {
|
||||
0x2: decode LEGACY_OP {
|
||||
0x0: psrlw_PRq_Ib();
|
||||
0x1: psrlw_VRo_Ib();
|
||||
}
|
||||
0x4: decode LEGACY_OP {
|
||||
0x0: psraw_PRq_Ib();
|
||||
0x1: psraw_VRo_Ib();
|
||||
}
|
||||
0x6: decode LEGACY_OP {
|
||||
0x0: psllw_PRq_Ib();
|
||||
0x1: psllw_VRo_Ib();
|
||||
}
|
||||
default: Inst::UD2();
|
||||
}
|
||||
//0x2: group14_pshimd();
|
||||
0x2: decode MODRM_REG {
|
||||
0x2: decode LEGACY_OP {
|
||||
0x0: psrld_PRq_Ib();
|
||||
0x1: psrld_VRo_Ib();
|
||||
}
|
||||
0x4: decode LEGACY_OP {
|
||||
0x0: psrad_PRq_Ib();
|
||||
0x1: psrad_VRo_Ib();
|
||||
}
|
||||
0x6: decode LEGACY_OP {
|
||||
0x0: pslld_PRq_Ib();
|
||||
0x1: pslld_VRo_Ib();
|
||||
}
|
||||
default: Inst::UD2();
|
||||
}
|
||||
//0x3: group15_pshimq();
|
||||
0x3: decode MODRM_REG {
|
||||
0x2: decode LEGACY_OP {
|
||||
0x0: psrlq_PRq_Ib();
|
||||
0x1: psrlq_VRo_Ib();
|
||||
}
|
||||
0x3: decode LEGACY_OP {
|
||||
0x0: Inst::UD2();
|
||||
0x1: psrldq_VRo_Ib();
|
||||
}
|
||||
0x6: decode LEGACY_OP {
|
||||
0x0: psllq_PRq_Ib();
|
||||
0x1: psllq_VRo_Ib();
|
||||
}
|
||||
0x7: decode LEGACY_OP {
|
||||
0x0: Inst::UD2();
|
||||
0x1: pslldq_VRo_Ib();
|
||||
}
|
||||
default: Inst::UD2();
|
||||
}
|
||||
0x4: pcmpeqb_Pq_Qq();
|
||||
0x5: pcmpeqw_Pq_Qq();
|
||||
0x6: pcmpeqd_Pq_Qq();
|
||||
@@ -413,9 +516,58 @@
|
||||
// operand size (0x66)
|
||||
0x1: decode OPCODE_OP_BOTTOM3 {
|
||||
0x0: pshufd_Vo_Wo_Ib();
|
||||
0x1: group13_pshimw();
|
||||
0x2: group14_pshimd();
|
||||
0x3: group15_pshimq_dq();
|
||||
//0x1: group13_pshimw();
|
||||
0x1: decode MODRM_REG {
|
||||
0x2: decode LEGACY_OP {
|
||||
0x0: psrlw_PRq_Ib();
|
||||
0x1: psrlw_VRo_Ib();
|
||||
}
|
||||
0x4: decode LEGACY_OP {
|
||||
0x0: psraw_PRq_Ib();
|
||||
0x1: psraw_VRo_Ib();
|
||||
}
|
||||
0x6: decode LEGACY_OP {
|
||||
0x0: psllw_PRq_Ib();
|
||||
0x1: psllw_VRo_Ib();
|
||||
}
|
||||
default: Inst::UD2();
|
||||
}
|
||||
//0x2: group14_pshimd();
|
||||
0x2: decode MODRM_REG {
|
||||
0x2: decode LEGACY_OP {
|
||||
0x0: psrld_PRq_Ib();
|
||||
0x1: psrld_VRo_Ib();
|
||||
}
|
||||
0x4: decode LEGACY_OP {
|
||||
0x0: psrad_PRq_Ib();
|
||||
0x1: psrad_VRo_Ib();
|
||||
}
|
||||
0x6: decode LEGACY_OP {
|
||||
0x0: pslld_PRq_Ib();
|
||||
0x1: pslld_VRo_Ib();
|
||||
}
|
||||
default: Inst::UD2();
|
||||
}
|
||||
//0x3: group15_pshimq();
|
||||
0x3: decode MODRM_REG {
|
||||
0x2: decode LEGACY_OP {
|
||||
0x0: psrlq_PRq_Ib();
|
||||
0x1: psrlq_VRo_Ib();
|
||||
}
|
||||
0x3: decode LEGACY_OP {
|
||||
0x0: Inst::UD2();
|
||||
0x1: psrldq_VRo_Ib();
|
||||
}
|
||||
0x6: decode LEGACY_OP {
|
||||
0x0: psllq_PRq_Ib();
|
||||
0x1: psllq_VRo_Ib();
|
||||
}
|
||||
0x7: decode LEGACY_OP {
|
||||
0x0: Inst::UD2();
|
||||
0x1: pslldq_VRo_Ib();
|
||||
}
|
||||
default: Inst::UD2();
|
||||
}
|
||||
0x4: pcmpeqb_Vo_Wo();
|
||||
0x5: pcmpeqw_Vo_Wo();
|
||||
0x6: pcmpeqd_Vo_Wo();
|
||||
@@ -505,7 +657,7 @@
|
||||
0x0: push_fs();
|
||||
0x1: pop_fs();
|
||||
0x2: Inst::CPUID(rAd);
|
||||
0x3: bt_Ev_Gv();
|
||||
0x3: Inst::BT(Ev,Gv);
|
||||
0x4: shld_Ev_Gv_Ib();
|
||||
0x5: shld_Ev_Gv_rCl();
|
||||
0x6: xbts_and_cmpxchg();
|
||||
@@ -515,17 +667,31 @@
|
||||
0x0: push_gs();
|
||||
0x1: pop_gs();
|
||||
0x2: rsm_smm();
|
||||
0x3: bts_Ev_Gv();
|
||||
0x3: Inst::BTS(Ev,Gv);
|
||||
0x4: shrd_Ev_Gv_Ib();
|
||||
0x5: shrd_Ev_Gv_rCl();
|
||||
0x6: group16();
|
||||
//0x6: group16();
|
||||
0x6: decode MODRM_MOD {
|
||||
0x3: decode MODRM_REG {
|
||||
0x5: lfence();
|
||||
0x6: mfence();
|
||||
0x7: sfence();
|
||||
default: Inst::UD2();
|
||||
}
|
||||
default: decode MODRM_REG {
|
||||
0x0: fxsave();
|
||||
0x1: fxrstor();
|
||||
0x7: clflush();
|
||||
default: Inst::UD2();
|
||||
}
|
||||
}
|
||||
0x7: Inst::IMUL(Gv,Ev);
|
||||
}
|
||||
0x16: decode OPCODE_OP_BOTTOM3 {
|
||||
0x0: Inst::CMPXCHG(Eb,Gb);
|
||||
0x1: Inst::CMPXCHG(Ev,Gv);
|
||||
0x2: lss_Gz_Mp();
|
||||
0x3: btr_Ev_Gv();
|
||||
0x3: Inst::BTR(Ev,Gv);
|
||||
0x4: lfs_Gz_Mp();
|
||||
0x5: lgs_Gz_Mp();
|
||||
//The size of the second operand in these instructions should
|
||||
@@ -536,9 +702,19 @@
|
||||
}
|
||||
0x17: decode OPCODE_OP_BOTTOM3 {
|
||||
0x0: jmpe_Jz(); // IA-64?
|
||||
0x1: group11_UD2();
|
||||
0x2: group8_Ev_Ib();
|
||||
0x3: btc_Ev_Gv();
|
||||
format Inst {
|
||||
//0x1: group11_UD2();
|
||||
0x1: UD2();
|
||||
//0x2: group8_Ev_Ib();
|
||||
0x2: decode MODRM_REG {
|
||||
0x4: BT(Ev,Ib);
|
||||
0x5: BTS(Ev,Ib);
|
||||
0x6: BTR(Ev,Ib);
|
||||
0x7: BTC(Ev,Ib);
|
||||
default: UD2();
|
||||
}
|
||||
0x3: BTC(Ev,Gv);
|
||||
}
|
||||
0x4: bsf_Gv_Ev();
|
||||
0x5: bsr_Gv_Ev();
|
||||
//The size of the second operand in these instructions should
|
||||
@@ -550,7 +726,19 @@
|
||||
0x18: decode OPCODE_OP_BOTTOM3 {
|
||||
0x0: xadd_Eb_Gb();
|
||||
0x1: xadd_Ev_Gv();
|
||||
0x7: group9();
|
||||
//0x7: group9();
|
||||
0x7: decode MODRM_REG {
|
||||
0x1: cmpxchg_Mq();
|
||||
0x6: decode LEGACY_OP {
|
||||
0x1: vmclear_Mq();
|
||||
default: decode LEGACY_REP {
|
||||
0x1: vmxon_Mq();
|
||||
0x0: vmptrld_Mq();
|
||||
}
|
||||
}
|
||||
0x7: vmptrst_Mq();
|
||||
default: Inst::UD2();
|
||||
}
|
||||
default: decode LEGACY_DECODEVAL {
|
||||
// no prefix
|
||||
0x0: decode OPCODE_OP_BOTTOM3 {
|
||||
|
||||
@@ -53,14 +53,242 @@
|
||||
#
|
||||
# Authors: Gabe Black
|
||||
|
||||
microcode = ""
|
||||
#let {{
|
||||
# class BT(Inst):
|
||||
# "GenFault ${new UnimpInstFault}"
|
||||
# class BTC(Inst):
|
||||
# "GenFault ${new UnimpInstFault}"
|
||||
# class BTR(Inst):
|
||||
# "GenFault ${new UnimpInstFault}"
|
||||
# class BTS(Inst):
|
||||
# "GenFault ${new UnimpInstFault}"
|
||||
#}};
|
||||
microcode = '''
|
||||
def macroop BT_R_I {
|
||||
sexti t0, reg, imm, flags=(CF,)
|
||||
};
|
||||
|
||||
def macroop BT_M_I {
|
||||
limm t1, imm
|
||||
# This fudges just a tiny bit, but it's reasonable to expect the
|
||||
# microcode generation logic to have the log of the various sizes
|
||||
# floating around as well.
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
add t2, t2, base
|
||||
ld t1, seg, [scale, index, t2], disp
|
||||
sexti t0, t1, imm, flags=(CF,)
|
||||
};
|
||||
|
||||
def macroop BT_P_I {
|
||||
rdip t7
|
||||
limm t1, imm
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
ld t1, seg, [1, t2, t7]
|
||||
sexti t0, t1, imm, flags=(CF,)
|
||||
};
|
||||
|
||||
def macroop BT_R_R {
|
||||
sext t0, reg, regm, flags=(CF,)
|
||||
};
|
||||
|
||||
def macroop BT_M_R {
|
||||
limm t1, imm
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
add t2, t2, base
|
||||
ld t1, seg, [scale, index, t2], disp
|
||||
sext t0, t1, reg, flags=(CF,)
|
||||
};
|
||||
|
||||
def macroop BT_P_R {
|
||||
rdip t7
|
||||
limm t1, imm
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
ld t1, seg, [1, t2, t7]
|
||||
sext t0, t1, reg, flags=(CF,)
|
||||
};
|
||||
|
||||
def macroop BTC_R_I {
|
||||
sexti t0, reg, imm, flags=(CF,)
|
||||
limm t1, 1
|
||||
roli t1, t1, imm
|
||||
xor reg, reg, t1
|
||||
};
|
||||
|
||||
def macroop BTC_M_I {
|
||||
limm t1, imm
|
||||
# This fudges just a tiny bit, but it's reasonable to expect the
|
||||
# microcode generation logic to have the log of the various sizes
|
||||
# floating around as well.
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
add t2, t2, base
|
||||
limm t3, 1
|
||||
roli t3, t3, imm
|
||||
ldst t1, seg, [scale, index, t2], disp
|
||||
sexti t0, t1, imm, flags=(CF,)
|
||||
xor t1, t1, t3
|
||||
st t1, seg, [scale, index, t2], disp
|
||||
};
|
||||
|
||||
def macroop BTC_P_I {
|
||||
rdip t7
|
||||
limm t1, imm
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
limm t3, 1
|
||||
roli t3, t3, imm
|
||||
ldst t1, seg, [1, t2, t7]
|
||||
sexti t0, t1, imm, flags=(CF,)
|
||||
xor t1, t1, t3
|
||||
st t1, seg, [scale, index, t2], disp
|
||||
};
|
||||
|
||||
def macroop BTC_R_R {
|
||||
sext t0, reg, regm, flags=(CF,)
|
||||
limm t1, 1
|
||||
rol t1, t1, regm
|
||||
xor reg, reg, t1
|
||||
};
|
||||
|
||||
def macroop BTC_M_R {
|
||||
limm t1, imm
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
add t2, t2, base
|
||||
limm t3, 1
|
||||
rol t3, t3, reg
|
||||
ldst t1, seg, [scale, index, t2], disp
|
||||
sext t0, t1, reg, flags=(CF,)
|
||||
xor t1, t1, t3
|
||||
st t1, seg, [scale, index, t2], disp
|
||||
};
|
||||
|
||||
def macroop BTC_P_R {
|
||||
rdip t7
|
||||
limm t1, imm
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
limm t3, 1
|
||||
rol t3, t3, reg
|
||||
ldst t1, seg, [1, t2, t7]
|
||||
sext t0, t1, reg, flags=(CF,)
|
||||
xor t1, t1, t3
|
||||
st t1, seg, [scale, index, t2], disp
|
||||
};
|
||||
|
||||
def macroop BTR_R_I {
|
||||
sexti t0, reg, imm, flags=(CF,)
|
||||
limm t1, "(uint64_t(-(2ULL)))"
|
||||
roli t1, t1, imm
|
||||
and reg, reg, t1
|
||||
};
|
||||
|
||||
def macroop BTR_M_I {
|
||||
limm t1, imm
|
||||
# This fudges just a tiny bit, but it's reasonable to expect the
|
||||
# microcode generation logic to have the log of the various sizes
|
||||
# floating around as well.
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
add t2, t2, base
|
||||
limm t3, "(uint64_t(-(2ULL)))"
|
||||
roli t3, t3, imm
|
||||
ldst t1, seg, [scale, index, t2], disp
|
||||
sexti t0, t1, imm, flags=(CF,)
|
||||
and t1, t1, t3
|
||||
st t1, seg, [scale, index, t2], disp
|
||||
};
|
||||
|
||||
def macroop BTR_P_I {
|
||||
rdip t7
|
||||
limm t1, imm
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
limm t3, "(uint64_t(-(2ULL)))"
|
||||
roli t3, t3, imm
|
||||
ldst t1, seg, [1, t2, t7]
|
||||
sexti t0, t1, imm, flags=(CF,)
|
||||
and t1, t1, t3
|
||||
st t1, seg, [scale, index, t2], disp
|
||||
};
|
||||
|
||||
def macroop BTR_R_R {
|
||||
sext t0, reg, regm, flags=(CF,)
|
||||
limm t1, "(uint64_t(-(2ULL)))"
|
||||
rol t1, t1, regm
|
||||
and reg, reg, t1
|
||||
};
|
||||
|
||||
def macroop BTR_M_R {
|
||||
limm t1, imm
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
add t2, t2, base
|
||||
limm t3, "(uint64_t(-(2ULL)))"
|
||||
rol t3, t3, reg
|
||||
ldst t1, seg, [scale, index, t2], disp
|
||||
sext t0, t1, reg, flags=(CF,)
|
||||
and t1, t1, t3
|
||||
st t1, seg, [scale, index, t2], disp
|
||||
};
|
||||
|
||||
def macroop BTR_P_R {
|
||||
rdip t7
|
||||
limm t1, imm
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
limm t3, "(uint64_t(-(2ULL)))"
|
||||
rol t3, t3, reg
|
||||
ldst t1, seg, [1, t2, t7]
|
||||
sext t0, t1, reg, flags=(CF,)
|
||||
and t1, t1, t3
|
||||
st t1, seg, [scale, index, t2], disp
|
||||
};
|
||||
|
||||
def macroop BTS_R_I {
|
||||
sexti t0, reg, imm, flags=(CF,)
|
||||
limm t1, 1
|
||||
roli t1, t1, imm
|
||||
or reg, reg, t1
|
||||
};
|
||||
|
||||
def macroop BTS_M_I {
|
||||
limm t1, imm
|
||||
# This fudges just a tiny bit, but it's reasonable to expect the
|
||||
# microcode generation logic to have the log of the various sizes
|
||||
# floating around as well.
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
add t2, t2, base
|
||||
limm t3, 1
|
||||
roli t3, t3, imm
|
||||
ldst t1, seg, [scale, index, t2], disp
|
||||
sexti t0, t1, imm, flags=(CF,)
|
||||
or t1, t1, t3
|
||||
st t1, seg, [scale, index, t2], disp
|
||||
};
|
||||
|
||||
def macroop BTS_P_I {
|
||||
rdip t7
|
||||
limm t1, imm
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
limm t3, 1
|
||||
roli t3, t3, imm
|
||||
ldst t1, seg, [1, t2, t7]
|
||||
sexti t0, t1, imm, flags=(CF,)
|
||||
or t1, t1, t3
|
||||
st t1, seg, [scale, index, t2], disp
|
||||
};
|
||||
|
||||
def macroop BTS_R_R {
|
||||
sext t0, reg, regm, flags=(CF,)
|
||||
limm t1, 1
|
||||
rol t1, t1, regm
|
||||
or reg, reg, t1
|
||||
};
|
||||
|
||||
def macroop BTS_M_R {
|
||||
limm t1, imm
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
add t2, t2, base
|
||||
limm t3, 1
|
||||
rol t3, t3, reg
|
||||
ldst t1, seg, [scale, index, t2], disp
|
||||
sext t0, t1, reg, flags=(CF,)
|
||||
or t1, t1, t3
|
||||
st t1, seg, [scale, index, t2], disp
|
||||
};
|
||||
|
||||
def macroop BTS_P_R {
|
||||
rdip t7
|
||||
limm t1, imm
|
||||
srai t2, t1, "(env.dataSize == 8) ? 3 : ((env.dataSize == 4) ? 2 : 1)"
|
||||
limm t3, 1
|
||||
rol t3, t3, reg
|
||||
ldst t1, seg, [1, t2, t7]
|
||||
sext t0, t1, reg, flags=(CF,)
|
||||
or t1, t1, t3
|
||||
st t1, seg, [scale, index, t2], disp
|
||||
};
|
||||
'''
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
microcode = '''
|
||||
def macroop CDQE_R {
|
||||
sext reg, reg, "env.dataSize << 2"
|
||||
sexti reg, reg, "env.dataSize << 2 - 1"
|
||||
};
|
||||
|
||||
def macroop CQO_R_R {
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
|
||||
microcode = '''
|
||||
def macroop XLAT {
|
||||
zext t1, rax, 8
|
||||
zexti t1, rax, 7
|
||||
# Here, t1 can be used directly. The value of al is supposed to be treated
|
||||
# as unsigned. Since we zero extended it from 8 bits above and the address
|
||||
# size has to be at least 16 bits, t1 will not be sign extended.
|
||||
|
||||
@@ -111,48 +111,48 @@ def macroop MOV_P_I {
|
||||
#
|
||||
|
||||
def macroop MOVSXD_R_R {
|
||||
sext reg, regm, 32
|
||||
sexti reg, regm, 31
|
||||
};
|
||||
|
||||
def macroop MOVSXD_R_M {
|
||||
ld t1, seg, sib, disp, dataSize=4
|
||||
sext reg, t1, 32
|
||||
sexti reg, t1, 31
|
||||
};
|
||||
|
||||
def macroop MOVSXD_R_P {
|
||||
rdip t7
|
||||
ld t1, seg, riprel, disp, dataSize=4
|
||||
sext reg, t1, 32
|
||||
sexti reg, t1, 31
|
||||
};
|
||||
|
||||
def macroop MOVSX_B_R_R {
|
||||
sext reg, regm, 8
|
||||
sexti reg, regm, 7
|
||||
};
|
||||
|
||||
def macroop MOVSX_B_R_M {
|
||||
ld reg, seg, sib, disp, dataSize=1
|
||||
sext reg, reg, 8
|
||||
sexti reg, reg, 7
|
||||
};
|
||||
|
||||
def macroop MOVSX_B_R_P {
|
||||
rdip t7
|
||||
ld reg, seg, riprel, disp, dataSize=1
|
||||
sext reg, reg, 8
|
||||
sexti reg, reg, 7
|
||||
};
|
||||
|
||||
def macroop MOVSX_W_R_R {
|
||||
sext reg, regm, 16
|
||||
sexti reg, regm, 15
|
||||
};
|
||||
|
||||
def macroop MOVSX_W_R_M {
|
||||
ld reg, seg, sib, disp, dataSize=2
|
||||
sext reg, reg, 16
|
||||
sexti reg, reg, 15
|
||||
};
|
||||
|
||||
def macroop MOVSX_W_R_P {
|
||||
rdip t7
|
||||
ld reg, seg, riprel, disp, dataSize=2
|
||||
sext reg, reg, 16
|
||||
sexti reg, reg, 15
|
||||
};
|
||||
|
||||
#
|
||||
@@ -160,33 +160,37 @@ def macroop MOVSX_W_R_P {
|
||||
#
|
||||
|
||||
def macroop MOVZX_B_R_R {
|
||||
zext reg, regm, 8
|
||||
zexti reg, regm, 7
|
||||
};
|
||||
|
||||
def macroop MOVZX_B_R_M {
|
||||
ld t1, seg, sib, disp, dataSize=1
|
||||
zext reg, t1, 8
|
||||
zexti reg, t1, 7
|
||||
};
|
||||
|
||||
def macroop MOVZX_B_R_P {
|
||||
rdip t7
|
||||
ld t1, seg, riprel, disp, dataSize=1
|
||||
zext reg, t1, 8
|
||||
zexti reg, t1, 7
|
||||
};
|
||||
|
||||
def macroop MOVZX_W_R_R {
|
||||
zext reg, regm, 16
|
||||
zexti reg, regm, 15
|
||||
};
|
||||
|
||||
def macroop MOVZX_W_R_M {
|
||||
ld t1, seg, sib, disp, dataSize=2
|
||||
zext reg, t1, 16
|
||||
zexti reg, t1, 15
|
||||
};
|
||||
|
||||
def macroop MOVZX_W_R_P {
|
||||
rdip t7
|
||||
ld t1, seg, riprel, disp, dataSize=2
|
||||
zext reg, t1, 16
|
||||
zexti reg, t1, 15
|
||||
};
|
||||
|
||||
def macroop MOV_C_R {
|
||||
wrcr reg, regm
|
||||
};
|
||||
'''
|
||||
#let {{
|
||||
|
||||
@@ -162,9 +162,9 @@ def macroop ENTER_I_I {
|
||||
|
||||
# Pull the different components out of the immediate
|
||||
limm t1, imm
|
||||
zext t2, t1, 16, dataSize=2
|
||||
zexti t2, t1, 15, dataSize=2
|
||||
srl t1, t1, 16
|
||||
zext t1, t1, 6
|
||||
zexti t1, t1, 5
|
||||
# t1 is now the masked nesting level, and t2 is the amount of storage.
|
||||
|
||||
# Push rbp.
|
||||
|
||||
@@ -62,7 +62,7 @@ microcode = '''
|
||||
|
||||
def macroop IN_R_R {
|
||||
limm t1, "IntAddrPrefixIO"
|
||||
zext t2, regm, 16, dataSize=2
|
||||
zexti t2, regm, 15, dataSize=2
|
||||
ld reg, intseg, [1, t1, t2], addressSize=8
|
||||
};
|
||||
|
||||
@@ -74,7 +74,7 @@ microcode = '''
|
||||
|
||||
def macroop OUT_R_R {
|
||||
limm t1, "IntAddrPrefixIO"
|
||||
zext t2, reg, 16, dataSize=2
|
||||
zexti t2, reg, 15, dataSize=2
|
||||
st regm, intseg, [1, t1, t2], addressSize=8
|
||||
};
|
||||
'''
|
||||
|
||||
@@ -62,7 +62,7 @@ def macroop INS_M_R {
|
||||
mov t3, t3, t4, flags=(nCEZF,), dataSize=asz
|
||||
|
||||
limm t1, "IntAddrPrefixIO"
|
||||
zext t2, reg, 16, dataSize=2
|
||||
zexti t2, reg, 15, dataSize=2
|
||||
|
||||
ld t6, intseg, [1, t1, t2], addressSize=8
|
||||
st t6, es, [1, t0, rdi]
|
||||
@@ -78,7 +78,7 @@ def macroop INS_E_M_R {
|
||||
mov t3, t3, t4, flags=(nCEZF,), dataSize=asz
|
||||
|
||||
limm t1, "IntAddrPrefixIO"
|
||||
zext t2, reg, 16, dataSize=2
|
||||
zexti t2, reg, 15, dataSize=2
|
||||
|
||||
topOfLoop:
|
||||
ld t6, intseg, [1, t1, t2], addressSize=8
|
||||
@@ -98,7 +98,7 @@ def macroop OUTS_R_M {
|
||||
mov t3, t3, t4, flags=(nCEZF,), dataSize=asz
|
||||
|
||||
limm t1, "IntAddrPrefixIO"
|
||||
zext t2, reg, 16, dataSize=2
|
||||
zexti t2, reg, 15, dataSize=2
|
||||
|
||||
ld t6, ds, [1, t0, rsi]
|
||||
st t6, intseg, [1, t1, t2], addressSize=8
|
||||
@@ -114,7 +114,7 @@ def macroop OUTS_E_R_M {
|
||||
mov t3, t3, t4, flags=(nCEZF,), dataSize=asz
|
||||
|
||||
limm t1, "IntAddrPrefixIO"
|
||||
zext t2, reg, 16, dataSize=2
|
||||
zexti t2, reg, 15, dataSize=2
|
||||
|
||||
topOfLoop:
|
||||
ld t6, ds, [1, t0, rsi]
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
# Authors: Gabe Black
|
||||
|
||||
microcode = '''
|
||||
def macroop WRMSR
|
||||
def macroop RDMSR
|
||||
{
|
||||
limm t1, "IntAddrPrefixMSR >> 3"
|
||||
ld t2, intseg, [8, t1, rcx], dataSize=8, addressSize=4
|
||||
@@ -63,7 +63,7 @@ def macroop WRMSR
|
||||
mov rdx, rdx, t2, dataSize=4
|
||||
};
|
||||
|
||||
def macroop RDMSR
|
||||
def macroop WRMSR
|
||||
{
|
||||
limm t1, "IntAddrPrefixMSR >> 3"
|
||||
mov t2, t2, rdx, dataSize=4
|
||||
|
||||
@@ -108,11 +108,14 @@ let {{
|
||||
|
||||
# This segment selects an internal address space mapped to MSRs,
|
||||
# CPUID info, etc.
|
||||
assembler.symbols["intseg"] = "NUM_SEGMENTREGS"
|
||||
assembler.symbols["intseg"] = "SEGMENT_REG_INT"
|
||||
|
||||
for reg in ('ax', 'bx', 'cx', 'dx', 'sp', 'bp', 'si', 'di'):
|
||||
assembler.symbols["r%s" % reg] = "INTREG_R%s" % reg.upper()
|
||||
|
||||
for reg in range(15):
|
||||
assembler.symbols["cr%d" % reg] = "MISCREG_CR%d" % reg
|
||||
|
||||
for flag in ('CF', 'PF', 'ECF', 'AF', 'EZF', 'ZF', 'SF', 'OF'):
|
||||
assembler.symbols[flag] = flag + "Bit"
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ def template MicroLoadExecute {{
|
||||
%(ea_code)s;
|
||||
DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA);
|
||||
|
||||
fault = read(xc, EA, Mem, (%(mem_flags)s) | (1 << segment));
|
||||
fault = read(xc, EA, Mem, (%(mem_flags)s) | segment);
|
||||
|
||||
if(fault == NoFault)
|
||||
{
|
||||
@@ -150,7 +150,7 @@ def template MicroLoadInitiateAcc {{
|
||||
%(ea_code)s;
|
||||
DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA);
|
||||
|
||||
fault = read(xc, EA, Mem, (%(mem_flags)s) | (1 << segment));
|
||||
fault = read(xc, EA, Mem, (%(mem_flags)s) | segment);
|
||||
|
||||
return fault;
|
||||
}
|
||||
@@ -197,7 +197,7 @@ def template MicroStoreExecute {{
|
||||
|
||||
if(fault == NoFault)
|
||||
{
|
||||
fault = write(xc, Mem, EA, (%(mem_flags)s) | (1 << segment));
|
||||
fault = write(xc, Mem, EA, (%(mem_flags)s) | segment);
|
||||
if(fault == NoFault)
|
||||
{
|
||||
%(op_wb)s;
|
||||
@@ -224,7 +224,7 @@ def template MicroStoreInitiateAcc {{
|
||||
|
||||
if(fault == NoFault)
|
||||
{
|
||||
fault = write(xc, Mem, EA, (%(mem_flags)s) | (1 << segment));
|
||||
fault = write(xc, Mem, EA, (%(mem_flags)s) | segment);
|
||||
if(fault == NoFault)
|
||||
{
|
||||
%(op_wb)s;
|
||||
|
||||
@@ -318,7 +318,7 @@ let {{
|
||||
|
||||
# If there's something optional to do with flags, generate
|
||||
# a version without it and fix up this version to use it.
|
||||
if flag_code is not "" or cond_check is not "true":
|
||||
if flag_code != "" or cond_check != "true":
|
||||
self.buildCppClasses(name, Name, suffix,
|
||||
code, "", "true", else_code)
|
||||
suffix = "Flags" + suffix
|
||||
@@ -835,7 +835,7 @@ let {{
|
||||
'''
|
||||
|
||||
class Wrip(WrRegOp, CondRegOp):
|
||||
code = 'RIP = psrc1 + sop2'
|
||||
code = 'RIP = psrc1 + sop2 + CSBase'
|
||||
else_code="RIP = RIP;"
|
||||
|
||||
class Br(WrRegOp, CondRegOp):
|
||||
@@ -846,7 +846,7 @@ let {{
|
||||
code = 'ccFlagBits = psrc1 ^ op2'
|
||||
|
||||
class Rdip(RdRegOp):
|
||||
code = 'DestReg = RIP'
|
||||
code = 'DestReg = RIP - CSBase'
|
||||
|
||||
class Ruflags(RdRegOp):
|
||||
code = 'DestReg = ccFlagBits'
|
||||
@@ -866,12 +866,74 @@ let {{
|
||||
class Sext(RegOp):
|
||||
code = '''
|
||||
IntReg val = psrc1;
|
||||
int sign_bit = bits(val, imm8-1, imm8-1);
|
||||
uint64_t maskVal = mask(imm8);
|
||||
// Mask the bit position so that it wraps.
|
||||
int bitPos = op2 & (dataSize * 8 - 1);
|
||||
int sign_bit = bits(val, bitPos, bitPos);
|
||||
uint64_t maskVal = mask(bitPos+1);
|
||||
val = sign_bit ? (val | ~maskVal) : (val & maskVal);
|
||||
DestReg = merge(DestReg, val, dataSize);
|
||||
'''
|
||||
flag_code = '''
|
||||
if (!sign_bit)
|
||||
ccFlagBits = ccFlagBits &
|
||||
~(ext & (CFBit | ECFBit | ZFBit | EZFBit));
|
||||
else
|
||||
ccFlagBits = ccFlagBits |
|
||||
(ext & (CFBit | ECFBit | ZFBit | EZFBit));
|
||||
'''
|
||||
|
||||
class Zext(RegOp):
|
||||
code = 'DestReg = bits(psrc1, imm8-1, 0);'
|
||||
code = 'DestReg = bits(psrc1, op2, 0);'
|
||||
|
||||
class Wrcr(RegOp):
|
||||
def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
|
||||
super(Wrcr, self).__init__(dest, \
|
||||
src1, "NUM_INTREGS", flags, dataSize)
|
||||
code = '''
|
||||
if (dest == 1 || (dest > 4 && dest < 8) || (dest > 8)) {
|
||||
fault = new InvalidOpcode();
|
||||
} else {
|
||||
// There are *s in the line below so it doesn't confuse the
|
||||
// parser. They may be unnecessary.
|
||||
//Mis*cReg old*Val = pick(Cont*rolDest, 0, dat*aSize);
|
||||
MiscReg newVal = psrc1;
|
||||
|
||||
// Check for any modifications that would cause a fault.
|
||||
switch(dest) {
|
||||
case 0:
|
||||
{
|
||||
Efer efer = EferOp;
|
||||
CR0 cr0 = newVal;
|
||||
CR4 oldCr4 = CR4Op;
|
||||
if (bits(newVal, 63, 32) ||
|
||||
(!cr0.pe && cr0.pg) ||
|
||||
(!cr0.cd && cr0.nw) ||
|
||||
(cr0.pg && efer.lme && !oldCr4.pae))
|
||||
fault = new GeneralProtection(0);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
CR4 cr4 = newVal;
|
||||
// PAE can't be disabled in long mode.
|
||||
if (bits(newVal, 63, 11) ||
|
||||
(machInst.mode.mode == LongMode && !cr4.pae))
|
||||
fault = new GeneralProtection(0);
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
{
|
||||
if (bits(newVal, 63, 4))
|
||||
fault = new GeneralProtection(0);
|
||||
}
|
||||
default:
|
||||
panic("Unrecognized control register %d.\\n", dest);
|
||||
}
|
||||
ControlDest = newVal;
|
||||
}
|
||||
'''
|
||||
}};
|
||||
|
||||
@@ -122,5 +122,10 @@ def operands {{
|
||||
# instructions don't map their indexes with an old value.
|
||||
'TOP': ('ControlReg', 'ub', 'MISCREG_X87_TOP', None, 61),
|
||||
'SegBase': ('ControlReg', 'uqw', 'MISCREG_SEG_BASE(segment)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 70),
|
||||
'ControlDest': ('ControlReg', 'uqw', 'MISCREG_CR(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 71),
|
||||
'ControlSrc1': ('ControlReg', 'uqw', 'MISCREG_CR(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 72),
|
||||
'EferOp': ('ControlReg', 'uqw', 'MISCREG_EFER', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 73),
|
||||
'CR4Op': ('ControlReg', 'uqw', 'MISCREG_CR4', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 74),
|
||||
'CSBase': ('ControlReg', 'udw', 'MISCREG_CS_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 80),
|
||||
'Mem': ('Mem', 'uqw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 100)
|
||||
}};
|
||||
|
||||
@@ -153,7 +153,13 @@ let {{
|
||||
return doRipRelativeDecode(Name, opTypes, env)
|
||||
elif opType.tag == None or opType.size == None:
|
||||
raise Exception, "Problem parsing operand tag: %s" % opType.tag
|
||||
elif opType.tag in ("C", "D", "G", "P", "S", "T", "V"):
|
||||
elif opType.tag == "C":
|
||||
env.addReg(ModRMRegIndex)
|
||||
Name += "_C"
|
||||
elif opType.tag == "D":
|
||||
env.addReg(ModRMRegIndex)
|
||||
Name += "_D"
|
||||
elif opType.tag in ("G", "P", "S", "T", "V"):
|
||||
# Use the "reg" field of the ModRM byte to select the register
|
||||
env.addReg(ModRMRegIndex)
|
||||
Name += "_R"
|
||||
|
||||
@@ -59,6 +59,7 @@
|
||||
#define __ARCH_X86_ISATRAITS_HH__
|
||||
|
||||
#include "arch/x86/intregs.hh"
|
||||
#include "arch/x86/max_inst_regs.hh"
|
||||
#include "arch/x86/types.hh"
|
||||
#include "arch/x86/x86_traits.hh"
|
||||
#include "sim/host.hh"
|
||||
@@ -72,6 +73,8 @@ namespace X86ISA
|
||||
//This makes sure the little endian version of certain functions
|
||||
//are used.
|
||||
using namespace LittleEndianGuest;
|
||||
using X86ISAInst::MaxInstSrcRegs;
|
||||
using X86ISAInst::MaxInstDestRegs;
|
||||
|
||||
// X86 does not have a delay slot
|
||||
#define ISA_HAS_DELAY_SLOT 0
|
||||
@@ -121,10 +124,6 @@ namespace X86ISA
|
||||
// value
|
||||
const int SyscallPseudoReturnReg = INTREG_RDX;
|
||||
|
||||
//XXX These numbers are bogus
|
||||
const int MaxInstSrcRegs = 10;
|
||||
const int MaxInstDestRegs = 10;
|
||||
|
||||
//4k. This value is not constant on x86.
|
||||
const int LogVMPageSize = 12;
|
||||
const int VMPageSize = (1 << LogVMPageSize);
|
||||
|
||||
@@ -86,6 +86,8 @@
|
||||
*/
|
||||
|
||||
#include "arch/x86/miscregfile.hh"
|
||||
#include "arch/x86/tlb.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "sim/serialize.hh"
|
||||
|
||||
using namespace X86ISA;
|
||||
@@ -106,22 +108,15 @@ void MiscRegFile::clear()
|
||||
|
||||
MiscReg MiscRegFile::readRegNoEffect(int miscReg)
|
||||
{
|
||||
switch(miscReg)
|
||||
{
|
||||
case MISCREG_CR1:
|
||||
case MISCREG_CR5:
|
||||
case MISCREG_CR6:
|
||||
case MISCREG_CR7:
|
||||
case MISCREG_CR9:
|
||||
case MISCREG_CR10:
|
||||
case MISCREG_CR11:
|
||||
case MISCREG_CR12:
|
||||
case MISCREG_CR13:
|
||||
case MISCREG_CR14:
|
||||
case MISCREG_CR15:
|
||||
panic("Tried to read invalid control register %d\n", miscReg);
|
||||
break;
|
||||
}
|
||||
// Make sure we're not dealing with an illegal control register.
|
||||
// Instructions should filter out these indexes, and nothing else should
|
||||
// attempt to read them directly.
|
||||
assert( miscReg != MISCREG_CR1 &&
|
||||
!(miscReg > MISCREG_CR4 &&
|
||||
miscReg < MISCREG_CR8) &&
|
||||
!(miscReg > MISCREG_CR8 &&
|
||||
miscReg <= MISCREG_CR15));
|
||||
|
||||
return regVal[miscReg];
|
||||
}
|
||||
|
||||
@@ -132,29 +127,67 @@ MiscReg MiscRegFile::readReg(int miscReg, ThreadContext * tc)
|
||||
|
||||
void MiscRegFile::setRegNoEffect(int miscReg, const MiscReg &val)
|
||||
{
|
||||
switch(miscReg)
|
||||
{
|
||||
case MISCREG_CR1:
|
||||
case MISCREG_CR5:
|
||||
case MISCREG_CR6:
|
||||
case MISCREG_CR7:
|
||||
case MISCREG_CR9:
|
||||
case MISCREG_CR10:
|
||||
case MISCREG_CR11:
|
||||
case MISCREG_CR12:
|
||||
case MISCREG_CR13:
|
||||
case MISCREG_CR14:
|
||||
case MISCREG_CR15:
|
||||
panic("Tried to write invalid control register %d\n", miscReg);
|
||||
break;
|
||||
}
|
||||
// Make sure we're not dealing with an illegal control register.
|
||||
// Instructions should filter out these indexes, and nothing else should
|
||||
// attempt to write to them directly.
|
||||
assert( miscReg != MISCREG_CR1 &&
|
||||
!(miscReg > MISCREG_CR4 &&
|
||||
miscReg < MISCREG_CR8) &&
|
||||
!(miscReg > MISCREG_CR8 &&
|
||||
miscReg <= MISCREG_CR15));
|
||||
regVal[miscReg] = val;
|
||||
}
|
||||
|
||||
void MiscRegFile::setReg(int miscReg,
|
||||
const MiscReg &val, ThreadContext * tc)
|
||||
{
|
||||
setRegNoEffect(miscReg, val);
|
||||
MiscReg newVal = val;
|
||||
switch(miscReg)
|
||||
{
|
||||
case MISCREG_CR0:
|
||||
{
|
||||
CR0 toggled = regVal[miscReg] ^ val;
|
||||
CR0 newCR0 = val;
|
||||
Efer efer = regVal[MISCREG_EFER];
|
||||
if (toggled.pg && efer.lme) {
|
||||
if (newCR0.pg) {
|
||||
//Turning on long mode
|
||||
efer.lma = 1;
|
||||
regVal[MISCREG_EFER] = efer;
|
||||
} else {
|
||||
//Turning off long mode
|
||||
efer.lma = 0;
|
||||
regVal[MISCREG_EFER] = efer;
|
||||
}
|
||||
}
|
||||
if (toggled.pg) {
|
||||
tc->getITBPtr()->invalidateAll();
|
||||
tc->getDTBPtr()->invalidateAll();
|
||||
}
|
||||
//This must always be 1.
|
||||
newCR0.et = 1;
|
||||
newVal = newCR0;
|
||||
}
|
||||
break;
|
||||
case MISCREG_CR2:
|
||||
break;
|
||||
case MISCREG_CR3:
|
||||
tc->getITBPtr()->invalidateNonGlobal();
|
||||
tc->getDTBPtr()->invalidateNonGlobal();
|
||||
break;
|
||||
case MISCREG_CR4:
|
||||
{
|
||||
CR4 toggled = regVal[miscReg] ^ val;
|
||||
if (toggled.pae || toggled.pse || toggled.pge) {
|
||||
tc->getITBPtr()->invalidateAll();
|
||||
tc->getDTBPtr()->invalidateAll();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MISCREG_CR8:
|
||||
break;
|
||||
}
|
||||
setRegNoEffect(miscReg, newVal);
|
||||
}
|
||||
|
||||
void MiscRegFile::serialize(std::ostream & os)
|
||||
|
||||
@@ -258,6 +258,7 @@ namespace X86ISA
|
||||
MISCREG_DS,
|
||||
MISCREG_FS,
|
||||
MISCREG_GS,
|
||||
MISCREG_INT, // This isn't actually used.
|
||||
|
||||
// Hidden segment base field
|
||||
MISCREG_SEG_BASE_BASE = MISCREG_SEG_SEL_BASE + NumSegments,
|
||||
@@ -267,6 +268,7 @@ namespace X86ISA
|
||||
MISCREG_DS_BASE,
|
||||
MISCREG_FS_BASE,
|
||||
MISCREG_GS_BASE,
|
||||
MISCREG_INT_BASE,
|
||||
|
||||
// Hidden segment limit field
|
||||
MISCREG_SEG_LIMIT_BASE = MISCREG_SEG_BASE_BASE + NumSegments,
|
||||
@@ -276,6 +278,7 @@ namespace X86ISA
|
||||
MISCREG_DS_LIMIT,
|
||||
MISCREG_FS_LIMIT,
|
||||
MISCREG_GS_LIMIT,
|
||||
MISCREG_INT_LIMIT, // This isn't actually used.
|
||||
|
||||
// Hidden segment limit attributes
|
||||
MISCREG_SEG_ATTR_BASE = MISCREG_SEG_LIMIT_BASE + NumSegments,
|
||||
@@ -285,6 +288,7 @@ namespace X86ISA
|
||||
MISCREG_DS_ATTR,
|
||||
MISCREG_FS_ATTR,
|
||||
MISCREG_GS_ATTR,
|
||||
MISCREG_INT_ATTR, // This isn't actually used.
|
||||
|
||||
// System segment selectors
|
||||
MISCREG_SYSSEG_SEL_BASE = MISCREG_SEG_ATTR_BASE + NumSegments,
|
||||
|
||||
@@ -62,16 +62,26 @@
|
||||
#include <string>
|
||||
|
||||
#include "sim/host.hh"
|
||||
#include "base/bitunion.hh"
|
||||
#include "base/misc.hh"
|
||||
|
||||
class Checkpoint;
|
||||
|
||||
namespace X86ISA
|
||||
{
|
||||
struct VAddr
|
||||
{
|
||||
VAddr(Addr a) { panic("not implemented yet."); }
|
||||
};
|
||||
BitUnion64(VAddr)
|
||||
Bitfield<20, 12> longl1;
|
||||
Bitfield<29, 21> longl2;
|
||||
Bitfield<38, 30> longl3;
|
||||
Bitfield<47, 39> longl4;
|
||||
|
||||
Bitfield<20, 12> pael1;
|
||||
Bitfield<29, 21> pael2;
|
||||
Bitfield<31, 30> pael3;
|
||||
|
||||
Bitfield<21, 12> norml1;
|
||||
Bitfield<31, 22> norml2;
|
||||
EndBitUnion(VAddr)
|
||||
|
||||
struct TlbEntry
|
||||
{
|
||||
|
||||
533
src/arch/x86/pagetable_walker.cc
Normal file
533
src/arch/x86/pagetable_walker.cc
Normal file
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
* Copyright (c) 2007 The Hewlett-Packard Development Company
|
||||
* 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 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
|
||||
* 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 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/pagetable.hh"
|
||||
#include "arch/x86/pagetable_walker.hh"
|
||||
#include "arch/x86/tlb.hh"
|
||||
#include "base/bitfield.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "mem/packet_access.hh"
|
||||
#include "mem/request.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
namespace X86ISA {
|
||||
|
||||
// Unfortunately, the placement of the base field in a page table entry is
|
||||
// very erratic and would make a mess here. It might be moved here at some
|
||||
// point in the future.
|
||||
BitUnion64(PageTableEntry)
|
||||
Bitfield<63> nx;
|
||||
Bitfield<11, 9> avl;
|
||||
Bitfield<8> g;
|
||||
Bitfield<7> ps;
|
||||
Bitfield<6> d;
|
||||
Bitfield<5> a;
|
||||
Bitfield<4> pcd;
|
||||
Bitfield<3> pwt;
|
||||
Bitfield<2> u;
|
||||
Bitfield<1> w;
|
||||
Bitfield<0> p;
|
||||
EndBitUnion(PageTableEntry)
|
||||
|
||||
void
|
||||
Walker::doNext(PacketPtr &read, PacketPtr &write)
|
||||
{
|
||||
assert(state != Ready && state != Waiting);
|
||||
write = NULL;
|
||||
PageTableEntry pte;
|
||||
if (size == 8)
|
||||
pte = read->get<uint64_t>();
|
||||
else
|
||||
pte = read->get<uint32_t>();
|
||||
VAddr vaddr = entry.vaddr;
|
||||
bool uncacheable = pte.pcd;
|
||||
Addr nextRead = 0;
|
||||
bool doWrite = false;
|
||||
bool badNX = pte.nx && (!tlb->allowNX() || !enableNX);
|
||||
switch(state) {
|
||||
case LongPML4:
|
||||
nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * size;
|
||||
doWrite = !pte.a;
|
||||
pte.a = 1;
|
||||
entry.writable = pte.w;
|
||||
entry.user = pte.u;
|
||||
if (badNX)
|
||||
panic("NX violation!\n");
|
||||
entry.noExec = pte.nx;
|
||||
if (!pte.p)
|
||||
panic("Page not present!\n");
|
||||
nextState = LongPDP;
|
||||
break;
|
||||
case LongPDP:
|
||||
nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * size;
|
||||
doWrite = !pte.a;
|
||||
pte.a = 1;
|
||||
entry.writable = entry.writable && pte.w;
|
||||
entry.user = entry.user && pte.u;
|
||||
if (badNX)
|
||||
panic("NX violation!\n");
|
||||
if (!pte.p)
|
||||
panic("Page not present!\n");
|
||||
nextState = LongPD;
|
||||
break;
|
||||
case LongPD:
|
||||
doWrite = !pte.a;
|
||||
pte.a = 1;
|
||||
entry.writable = entry.writable && pte.w;
|
||||
entry.user = entry.user && pte.u;
|
||||
if (badNX)
|
||||
panic("NX violation!\n");
|
||||
if (!pte.p)
|
||||
panic("Page not present!\n");
|
||||
if (!pte.ps) {
|
||||
// 4 KB page
|
||||
entry.size = 4 * (1 << 10);
|
||||
nextRead =
|
||||
((uint64_t)pte & (mask(40) << 12)) + vaddr.longl1 * size;
|
||||
nextState = LongPTE;
|
||||
break;
|
||||
} else {
|
||||
// 2 MB page
|
||||
entry.size = 2 * (1 << 20);
|
||||
entry.paddr = (uint64_t)pte & (mask(31) << 21);
|
||||
entry.uncacheable = uncacheable;
|
||||
entry.global = pte.g;
|
||||
entry.patBit = bits(pte, 12);
|
||||
entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
|
||||
tlb->insert(entry.vaddr, entry);
|
||||
nextState = Ready;
|
||||
delete read->req;
|
||||
delete read;
|
||||
read = NULL;
|
||||
return;
|
||||
}
|
||||
case LongPTE:
|
||||
doWrite = !pte.a;
|
||||
pte.a = 1;
|
||||
entry.writable = entry.writable && pte.w;
|
||||
entry.user = entry.user && pte.u;
|
||||
if (badNX)
|
||||
panic("NX violation!\n");
|
||||
if (!pte.p)
|
||||
panic("Page not present!\n");
|
||||
entry.paddr = (uint64_t)pte & (mask(40) << 12);
|
||||
entry.uncacheable = uncacheable;
|
||||
entry.global = pte.g;
|
||||
entry.patBit = bits(pte, 12);
|
||||
entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
|
||||
tlb->insert(entry.vaddr, entry);
|
||||
nextState = Ready;
|
||||
delete read->req;
|
||||
delete read;
|
||||
read = NULL;
|
||||
return;
|
||||
case PAEPDP:
|
||||
nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * size;
|
||||
if (!pte.p)
|
||||
panic("Page not present!\n");
|
||||
nextState = PAEPD;
|
||||
break;
|
||||
case PAEPD:
|
||||
doWrite = !pte.a;
|
||||
pte.a = 1;
|
||||
entry.writable = pte.w;
|
||||
entry.user = pte.u;
|
||||
if (badNX)
|
||||
panic("NX violation!\n");
|
||||
if (!pte.p)
|
||||
panic("Page not present!\n");
|
||||
if (!pte.ps) {
|
||||
// 4 KB page
|
||||
entry.size = 4 * (1 << 10);
|
||||
nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael1 * size;
|
||||
nextState = PAEPTE;
|
||||
break;
|
||||
} else {
|
||||
// 2 MB page
|
||||
entry.size = 2 * (1 << 20);
|
||||
entry.paddr = (uint64_t)pte & (mask(31) << 21);
|
||||
entry.uncacheable = uncacheable;
|
||||
entry.global = pte.g;
|
||||
entry.patBit = bits(pte, 12);
|
||||
entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
|
||||
tlb->insert(entry.vaddr, entry);
|
||||
nextState = Ready;
|
||||
delete read->req;
|
||||
delete read;
|
||||
read = NULL;
|
||||
return;
|
||||
}
|
||||
case PAEPTE:
|
||||
doWrite = !pte.a;
|
||||
pte.a = 1;
|
||||
entry.writable = entry.writable && pte.w;
|
||||
entry.user = entry.user && pte.u;
|
||||
if (badNX)
|
||||
panic("NX violation!\n");
|
||||
if (!pte.p)
|
||||
panic("Page not present!\n");
|
||||
entry.paddr = (uint64_t)pte & (mask(40) << 12);
|
||||
entry.uncacheable = uncacheable;
|
||||
entry.global = pte.g;
|
||||
entry.patBit = bits(pte, 7);
|
||||
entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
|
||||
tlb->insert(entry.vaddr, entry);
|
||||
nextState = Ready;
|
||||
delete read->req;
|
||||
delete read;
|
||||
read = NULL;
|
||||
return;
|
||||
case PSEPD:
|
||||
doWrite = !pte.a;
|
||||
pte.a = 1;
|
||||
entry.writable = pte.w;
|
||||
entry.user = pte.u;
|
||||
if (!pte.p)
|
||||
panic("Page not present!\n");
|
||||
if (!pte.ps) {
|
||||
// 4 KB page
|
||||
entry.size = 4 * (1 << 10);
|
||||
nextRead =
|
||||
((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
|
||||
nextState = PTE;
|
||||
break;
|
||||
} else {
|
||||
// 4 MB page
|
||||
entry.size = 4 * (1 << 20);
|
||||
entry.paddr = bits(pte, 20, 13) << 32 | bits(pte, 31, 22) << 22;
|
||||
entry.uncacheable = uncacheable;
|
||||
entry.global = pte.g;
|
||||
entry.patBit = bits(pte, 12);
|
||||
entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1);
|
||||
tlb->insert(entry.vaddr, entry);
|
||||
nextState = Ready;
|
||||
delete read->req;
|
||||
delete read;
|
||||
read = NULL;
|
||||
return;
|
||||
}
|
||||
case PD:
|
||||
doWrite = !pte.a;
|
||||
pte.a = 1;
|
||||
entry.writable = pte.w;
|
||||
entry.user = pte.u;
|
||||
if (!pte.p)
|
||||
panic("Page not present!\n");
|
||||
// 4 KB page
|
||||
entry.size = 4 * (1 << 10);
|
||||
nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
|
||||
nextState = PTE;
|
||||
break;
|
||||
nextState = PTE;
|
||||
break;
|
||||
case PTE:
|
||||
doWrite = !pte.a;
|
||||
pte.a = 1;
|
||||
entry.writable = pte.w;
|
||||
entry.user = pte.u;
|
||||
if (!pte.p)
|
||||
panic("Page not present!\n");
|
||||
entry.paddr = (uint64_t)pte & (mask(20) << 12);
|
||||
entry.uncacheable = uncacheable;
|
||||
entry.global = pte.g;
|
||||
entry.patBit = bits(pte, 7);
|
||||
entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
|
||||
tlb->insert(entry.vaddr, entry);
|
||||
nextState = Ready;
|
||||
delete read->req;
|
||||
delete read;
|
||||
read = NULL;
|
||||
return;
|
||||
default:
|
||||
panic("Unknown page table walker state %d!\n");
|
||||
}
|
||||
PacketPtr oldRead = read;
|
||||
//If we didn't return, we're setting up another read.
|
||||
uint32_t flags = oldRead->req->getFlags();
|
||||
if (uncacheable)
|
||||
flags |= UNCACHEABLE;
|
||||
else
|
||||
flags &= ~UNCACHEABLE;
|
||||
RequestPtr request =
|
||||
new Request(nextRead, oldRead->getSize(), flags);
|
||||
read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
|
||||
read->allocate();
|
||||
//If we need to write, adjust the read packet to write the modified value
|
||||
//back to memory.
|
||||
if (doWrite) {
|
||||
write = oldRead;
|
||||
write->set<uint64_t>(pte);
|
||||
write->cmd = MemCmd::WriteReq;
|
||||
write->setDest(Packet::Broadcast);
|
||||
} else {
|
||||
write = NULL;
|
||||
delete oldRead->req;
|
||||
delete oldRead;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Walker::start(ThreadContext * _tc, Addr vaddr)
|
||||
{
|
||||
assert(state == Ready);
|
||||
assert(!tc);
|
||||
tc = _tc;
|
||||
|
||||
VAddr addr = vaddr;
|
||||
|
||||
//Figure out what we're doing.
|
||||
CR3 cr3 = tc->readMiscRegNoEffect(MISCREG_CR3);
|
||||
Addr top = 0;
|
||||
// Check if we're in long mode or not
|
||||
Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
|
||||
size = 8;
|
||||
if (efer.lma) {
|
||||
// Do long mode.
|
||||
state = LongPML4;
|
||||
top = (cr3.longPdtb << 12) + addr.longl4 * size;
|
||||
} else {
|
||||
// We're in some flavor of legacy mode.
|
||||
CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4);
|
||||
if (cr4.pae) {
|
||||
// Do legacy PAE.
|
||||
state = PAEPDP;
|
||||
top = (cr3.paePdtb << 5) + addr.pael3 * size;
|
||||
} else {
|
||||
size = 4;
|
||||
top = (cr3.pdtb << 12) + addr.norml2 * size;
|
||||
if (cr4.pse) {
|
||||
// Do legacy PSE.
|
||||
state = PSEPD;
|
||||
} else {
|
||||
// Do legacy non PSE.
|
||||
state = PD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nextState = Ready;
|
||||
entry.vaddr = vaddr;
|
||||
|
||||
enableNX = efer.nxe;
|
||||
|
||||
RequestPtr request =
|
||||
new Request(top, size, PHYSICAL | cr3.pcd ? UNCACHEABLE : 0);
|
||||
read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
|
||||
read->allocate();
|
||||
Enums::MemoryMode memMode = sys->getMemoryMode();
|
||||
if (memMode == Enums::timing) {
|
||||
tc->suspend();
|
||||
port.sendTiming(read);
|
||||
} else if (memMode == Enums::atomic) {
|
||||
do {
|
||||
port.sendAtomic(read);
|
||||
PacketPtr write = NULL;
|
||||
doNext(read, write);
|
||||
state = nextState;
|
||||
nextState = Ready;
|
||||
if (write)
|
||||
port.sendAtomic(write);
|
||||
} while(read);
|
||||
tc = NULL;
|
||||
state = Ready;
|
||||
nextState = Waiting;
|
||||
} else {
|
||||
panic("Unrecognized memory system mode.\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Walker::WalkerPort::recvTiming(PacketPtr pkt)
|
||||
{
|
||||
return walker->recvTiming(pkt);
|
||||
}
|
||||
|
||||
bool
|
||||
Walker::recvTiming(PacketPtr pkt)
|
||||
{
|
||||
inflight--;
|
||||
if (pkt->isResponse() && !pkt->wasNacked()) {
|
||||
if (pkt->isRead()) {
|
||||
assert(inflight);
|
||||
assert(state == Waiting);
|
||||
assert(!read);
|
||||
state = nextState;
|
||||
nextState = Ready;
|
||||
PacketPtr write = NULL;
|
||||
doNext(pkt, write);
|
||||
state = Waiting;
|
||||
read = pkt;
|
||||
if (write) {
|
||||
writes.push_back(write);
|
||||
}
|
||||
sendPackets();
|
||||
} else {
|
||||
sendPackets();
|
||||
}
|
||||
if (inflight == 0 && read == NULL && writes.size() == 0) {
|
||||
tc->activate(0);
|
||||
tc = NULL;
|
||||
state = Ready;
|
||||
nextState = Waiting;
|
||||
}
|
||||
} else if (pkt->wasNacked()) {
|
||||
pkt->reinitNacked();
|
||||
if (!port.sendTiming(pkt)) {
|
||||
retrying = true;
|
||||
if (pkt->isWrite()) {
|
||||
writes.push_back(pkt);
|
||||
} else {
|
||||
assert(!read);
|
||||
read = pkt;
|
||||
}
|
||||
} else {
|
||||
inflight++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Tick
|
||||
Walker::WalkerPort::recvAtomic(PacketPtr pkt)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Walker::WalkerPort::recvFunctional(PacketPtr pkt)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
Walker::WalkerPort::recvStatusChange(Status status)
|
||||
{
|
||||
if (status == RangeChange) {
|
||||
if (!snoopRangeSent) {
|
||||
snoopRangeSent = true;
|
||||
sendStatusChange(Port::RangeChange);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
panic("Unexpected recvStatusChange.\n");
|
||||
}
|
||||
|
||||
void
|
||||
Walker::WalkerPort::recvRetry()
|
||||
{
|
||||
walker->recvRetry();
|
||||
}
|
||||
|
||||
void
|
||||
Walker::recvRetry()
|
||||
{
|
||||
retrying = false;
|
||||
sendPackets();
|
||||
}
|
||||
|
||||
void
|
||||
Walker::sendPackets()
|
||||
{
|
||||
//If we're already waiting for the port to become available, just return.
|
||||
if (retrying)
|
||||
return;
|
||||
|
||||
//Reads always have priority
|
||||
if (read) {
|
||||
if (!port.sendTiming(read)) {
|
||||
retrying = true;
|
||||
return;
|
||||
} else {
|
||||
inflight++;
|
||||
delete read->req;
|
||||
delete read;
|
||||
read = NULL;
|
||||
}
|
||||
}
|
||||
//Send off as many of the writes as we can.
|
||||
while (writes.size()) {
|
||||
PacketPtr write = writes.back();
|
||||
if (!port.sendTiming(write)) {
|
||||
retrying = true;
|
||||
return;
|
||||
} else {
|
||||
inflight++;
|
||||
delete write->req;
|
||||
delete write;
|
||||
writes.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Port *
|
||||
Walker::getPort(const std::string &if_name, int idx)
|
||||
{
|
||||
if (if_name == "port")
|
||||
return &port;
|
||||
else
|
||||
panic("No page table walker port named %s!\n", if_name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
X86ISA::Walker *
|
||||
X86PagetableWalkerParams::create()
|
||||
{
|
||||
return new X86ISA::Walker(this);
|
||||
}
|
||||
189
src/arch/x86/pagetable_walker.hh
Normal file
189
src/arch/x86/pagetable_walker.hh
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (c) 2007 The Hewlett-Packard Development Company
|
||||
* 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 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
|
||||
* 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 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
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_X86_PAGE_TABLE_WALKER_HH__
|
||||
#define __ARCH_X86_PAGE_TABLE_WALKER_HH__
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "arch/x86/pagetable.hh"
|
||||
#include "arch/x86/tlb.hh"
|
||||
#include "mem/mem_object.hh"
|
||||
#include "mem/packet.hh"
|
||||
#include "params/X86PagetableWalker.hh"
|
||||
#include "sim/host.hh"
|
||||
|
||||
class ThreadContext;
|
||||
|
||||
namespace X86ISA
|
||||
{
|
||||
class Walker : public MemObject
|
||||
{
|
||||
public:
|
||||
enum State {
|
||||
Ready,
|
||||
Waiting,
|
||||
// Long mode
|
||||
LongPML4, LongPDP, LongPD, LongPTE,
|
||||
// PAE legacy mode
|
||||
PAEPDP, PAEPD, PAEPTE,
|
||||
// Non PAE legacy mode with and without PSE
|
||||
PSEPD, PD, PTE
|
||||
};
|
||||
|
||||
// Act on the current state and determine what to do next. read
|
||||
// should be the packet that just came back from a read and write
|
||||
// should be NULL. When the function returns, read is either NULL
|
||||
// if the machine is finished, or points to a packet to initiate
|
||||
// the next read. If any write is required to update an "accessed"
|
||||
// bit, write will point to a packet to do the write. Otherwise it
|
||||
// will be NULL.
|
||||
void doNext(PacketPtr &read, PacketPtr &write);
|
||||
|
||||
// Kick off the state machine.
|
||||
void start(ThreadContext * _tc, Addr vaddr);
|
||||
|
||||
protected:
|
||||
|
||||
/*
|
||||
* State having to do with sending packets.
|
||||
*/
|
||||
PacketPtr read;
|
||||
std::vector<PacketPtr> writes;
|
||||
|
||||
// How many memory operations are in flight.
|
||||
unsigned inflight;
|
||||
|
||||
bool retrying;
|
||||
|
||||
/*
|
||||
* Functions for dealing with packets.
|
||||
*/
|
||||
bool recvTiming(PacketPtr pkt);
|
||||
void recvRetry();
|
||||
|
||||
void sendPackets();
|
||||
|
||||
/*
|
||||
* Port for accessing memory
|
||||
*/
|
||||
class WalkerPort : public Port
|
||||
{
|
||||
public:
|
||||
WalkerPort(const std::string &_name, Walker * _walker) :
|
||||
Port(_name, _walker), walker(_walker),
|
||||
snoopRangeSent(false)
|
||||
{}
|
||||
|
||||
protected:
|
||||
Walker * walker;
|
||||
|
||||
bool snoopRangeSent;
|
||||
|
||||
bool recvTiming(PacketPtr pkt);
|
||||
Tick recvAtomic(PacketPtr pkt);
|
||||
void recvFunctional(PacketPtr pkt);
|
||||
void recvStatusChange(Status status);
|
||||
void recvRetry();
|
||||
void getDeviceAddressRanges(AddrRangeList &resp,
|
||||
bool &snoop)
|
||||
{
|
||||
resp.clear();
|
||||
snoop = true;
|
||||
}
|
||||
};
|
||||
|
||||
Port *getPort(const std::string &if_name, int idx = -1);
|
||||
|
||||
friend class WalkerPort;
|
||||
|
||||
WalkerPort port;
|
||||
|
||||
// The TLB we're supposed to load.
|
||||
TLB * tlb;
|
||||
System * sys;
|
||||
|
||||
/*
|
||||
* State machine state.
|
||||
*/
|
||||
ThreadContext * tc;
|
||||
State state;
|
||||
State nextState;
|
||||
int size;
|
||||
bool enableNX;
|
||||
TlbEntry entry;
|
||||
|
||||
public:
|
||||
|
||||
void setTLB(TLB * _tlb)
|
||||
{
|
||||
tlb = _tlb;
|
||||
}
|
||||
|
||||
typedef X86PagetableWalkerParams Params;
|
||||
|
||||
Walker(const Params *params) :
|
||||
MemObject(params),
|
||||
read(NULL), inflight(0), retrying(false),
|
||||
port(name() + ".port", this),
|
||||
tlb(NULL), sys(params->system),
|
||||
tc(NULL), state(Ready), nextState(Ready)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // __ARCH_X86_PAGE_TABLE_WALKER_HH__
|
||||
@@ -461,6 +461,8 @@ X86LiveProcess::argsInit(int intSize, int pageSize)
|
||||
threadContexts[0]->setIntReg(StackPointerReg, stack_min);
|
||||
|
||||
Addr prog_entry = objFile->entryPoint();
|
||||
// There doesn't need to be any segment base added in since we're dealing
|
||||
// with the flat segmentation model.
|
||||
threadContexts[0]->setPC(prog_entry);
|
||||
threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ namespace X86ISA
|
||||
SEGMENT_REG_DS,
|
||||
SEGMENT_REG_FS,
|
||||
SEGMENT_REG_GS,
|
||||
SEGMENT_REG_INT,
|
||||
|
||||
NUM_SEGMENTREGS
|
||||
};
|
||||
|
||||
@@ -64,11 +64,15 @@
|
||||
#include "arch/x86/x86_traits.hh"
|
||||
#include "base/bitfield.hh"
|
||||
#include "base/trace.hh"
|
||||
#include "config/full_system.hh"
|
||||
#include "cpu/thread_context.hh"
|
||||
#include "cpu/base.hh"
|
||||
#include "mem/packet_access.hh"
|
||||
#include "mem/request.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
#if FULL_SYSTEM
|
||||
#include "arch/x86/pagetable_walker.hh"
|
||||
#endif
|
||||
|
||||
namespace X86ISA {
|
||||
|
||||
@@ -79,6 +83,11 @@ TLB::TLB(const Params *p) : SimObject(p), size(p->size)
|
||||
|
||||
for (int x = 0; x < size; x++)
|
||||
freeList.push_back(&tlb[x]);
|
||||
|
||||
#if FULL_SYSTEM
|
||||
walker = p->walker;
|
||||
walker->setTLB(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@@ -119,14 +128,38 @@ TLB::lookup(Addr va, bool update_lru)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if FULL_SYSTEM
|
||||
void
|
||||
TLB::walk(ThreadContext * _tc, Addr vaddr)
|
||||
{
|
||||
walker->start(_tc, vaddr);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
TLB::invalidateAll()
|
||||
{
|
||||
DPRINTF(TLB, "Invalidating all entries.\n");
|
||||
while (!entryList.empty()) {
|
||||
TlbEntry *entry = entryList.front();
|
||||
entryList.pop_front();
|
||||
freeList.push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TLB::invalidateNonGlobal()
|
||||
{
|
||||
DPRINTF(TLB, "Invalidating all non global entries.\n");
|
||||
EntryList::iterator entryIt;
|
||||
for (entryIt = entryList.begin(); entryIt != entryList.end();) {
|
||||
if (!(*entryIt)->global) {
|
||||
freeList.push_back(*entryIt);
|
||||
entryList.erase(entryIt++);
|
||||
} else {
|
||||
entryIt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -150,7 +183,8 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
|
||||
|
||||
// If this is true, we're dealing with a request to read an internal
|
||||
// value.
|
||||
if (seg == NUM_SEGMENTREGS) {
|
||||
if (seg == SEGMENT_REG_INT) {
|
||||
DPRINTF(TLB, "Addresses references internal memory.\n");
|
||||
Addr prefix = vaddr & IntAddrPrefixMask;
|
||||
if (prefix == IntAddrPrefixCPUID) {
|
||||
panic("CPUID memory space not yet implemented!\n");
|
||||
@@ -448,10 +482,12 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
|
||||
|
||||
// If protected mode has been enabled...
|
||||
if (cr0.pe) {
|
||||
DPRINTF(TLB, "In protected mode.\n");
|
||||
Efer efer = tc->readMiscRegNoEffect(MISCREG_EFER);
|
||||
SegAttr csAttr = tc->readMiscRegNoEffect(MISCREG_CS_ATTR);
|
||||
// If we're not in 64-bit mode, do protection/limit checks
|
||||
if (!efer.lma || !csAttr.longMode) {
|
||||
DPRINTF(TLB, "Not in long mode. Checking segment protection.\n");
|
||||
SegAttr attr = tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg));
|
||||
if (!attr.writable && write)
|
||||
return new GeneralProtection(0);
|
||||
@@ -460,6 +496,7 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
|
||||
Addr base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(seg));
|
||||
Addr limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(seg));
|
||||
if (!attr.expandDown) {
|
||||
DPRINTF(TLB, "Checking an expand down segment.\n");
|
||||
// We don't have to worry about the access going around the
|
||||
// end of memory because accesses will be broken up into
|
||||
// pieces at boundaries aligned on sizes smaller than an
|
||||
@@ -484,25 +521,28 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
|
||||
}
|
||||
// If paging is enabled, do the translation.
|
||||
if (cr0.pg) {
|
||||
DPRINTF(TLB, "Paging enabled.\n");
|
||||
// The vaddr already has the segment base applied.
|
||||
TlbEntry *entry = lookup(vaddr);
|
||||
if (!entry) {
|
||||
#if FULL_SYSTEM
|
||||
return new TlbFault();
|
||||
#else
|
||||
return new TlbFault(vaddr);
|
||||
#endif
|
||||
} else {
|
||||
// Do paging protection checks.
|
||||
Addr paddr = entry->paddr | (vaddr & mask(12));
|
||||
DPRINTF(TLB, "Entry found with paddr %#x, doing protection checks.\n", entry->paddr);
|
||||
Addr paddr = entry->paddr | (vaddr & (entry->size-1));
|
||||
DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, paddr);
|
||||
req->setPaddr(paddr);
|
||||
}
|
||||
} else {
|
||||
//Use the address which already has segmentation applied.
|
||||
DPRINTF(TLB, "Paging disabled.\n");
|
||||
DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, vaddr);
|
||||
req->setPaddr(vaddr);
|
||||
}
|
||||
} else {
|
||||
// Real mode
|
||||
DPRINTF(TLB, "In real mode.\n");
|
||||
DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, vaddr);
|
||||
req->setPaddr(vaddr);
|
||||
}
|
||||
return NoFault;
|
||||
|
||||
@@ -59,10 +59,13 @@
|
||||
#define __ARCH_X86_TLB_HH__
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "arch/x86/pagetable.hh"
|
||||
#include "arch/x86/segmentregs.hh"
|
||||
#include "config/full_system.hh"
|
||||
#include "mem/mem_object.hh"
|
||||
#include "mem/request.hh"
|
||||
#include "params/X86DTB.hh"
|
||||
#include "params/X86ITB.hh"
|
||||
@@ -74,16 +77,26 @@ class Packet;
|
||||
|
||||
namespace X86ISA
|
||||
{
|
||||
class Walker;
|
||||
|
||||
static const unsigned StoreCheck = 1 << NUM_SEGMENTREGS;
|
||||
|
||||
class TLB;
|
||||
|
||||
class TLB : public SimObject
|
||||
{
|
||||
#if !FULL_SYSTEM
|
||||
protected:
|
||||
friend class FakeITLBFault;
|
||||
friend class FakeDTLBFault;
|
||||
#endif
|
||||
|
||||
bool _allowNX;
|
||||
|
||||
public:
|
||||
bool allowNX() const
|
||||
{
|
||||
return _allowNX;
|
||||
}
|
||||
|
||||
typedef X86TLBParams Params;
|
||||
TLB(const Params *p);
|
||||
|
||||
@@ -91,6 +104,21 @@ namespace X86ISA
|
||||
|
||||
TlbEntry *lookup(Addr va, bool update_lru = true);
|
||||
|
||||
#if FULL_SYSTEM
|
||||
protected:
|
||||
|
||||
Walker * walker;
|
||||
|
||||
void walk(ThreadContext * _tc, Addr vaddr);
|
||||
#endif
|
||||
|
||||
public:
|
||||
void invalidateAll();
|
||||
|
||||
void invalidateNonGlobal();
|
||||
|
||||
void demapPage(Addr va);
|
||||
|
||||
protected:
|
||||
int size;
|
||||
|
||||
@@ -100,19 +128,14 @@ namespace X86ISA
|
||||
EntryList freeList;
|
||||
EntryList entryList;
|
||||
|
||||
void insert(Addr vpn, TlbEntry &entry);
|
||||
|
||||
void invalidateAll();
|
||||
|
||||
void invalidateNonGlobal();
|
||||
|
||||
void demapPage(Addr va);
|
||||
|
||||
template<class TlbFault>
|
||||
Fault translate(RequestPtr &req, ThreadContext *tc,
|
||||
bool write, bool execute);
|
||||
|
||||
public:
|
||||
|
||||
void insert(Addr vpn, TlbEntry &entry);
|
||||
|
||||
// Checkpointing
|
||||
virtual void serialize(std::ostream &os);
|
||||
virtual void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
@@ -124,6 +147,7 @@ namespace X86ISA
|
||||
typedef X86ITBParams Params;
|
||||
ITB(const Params *p) : TLB(p)
|
||||
{
|
||||
_allowNX = false;
|
||||
}
|
||||
|
||||
Fault translate(RequestPtr &req, ThreadContext *tc);
|
||||
@@ -137,6 +161,7 @@ namespace X86ISA
|
||||
typedef X86DTBParams Params;
|
||||
DTB(const Params *p) : TLB(p)
|
||||
{
|
||||
_allowNX = true;
|
||||
}
|
||||
Fault translate(RequestPtr &req, ThreadContext *tc, bool write);
|
||||
#if FULL_SYSTEM
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
#include "arch/x86/segmentregs.hh"
|
||||
#include "arch/x86/utility.hh"
|
||||
#include "arch/x86/x86_traits.hh"
|
||||
#include "sim/system.hh"
|
||||
|
||||
namespace X86ISA {
|
||||
|
||||
@@ -253,20 +254,177 @@ void initCPU(ThreadContext *tc, int cpuId)
|
||||
|
||||
#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.
|
||||
// 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.
|
||||
|
||||
// Enable paging, turn on long mode, etc.
|
||||
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();
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// 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.
|
||||
|
||||
// Page Map Level 4
|
||||
|
||||
// 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);
|
||||
|
||||
// Page Directory Pointer Table
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* Far jump into 64 bit mode.
|
||||
*/
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void startupCPU(ThreadContext *tc, int cpuId)
|
||||
{
|
||||
tc->activate(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} //namespace X86_ISA
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace m5 {
|
||||
//
|
||||
|
||||
namespace __hash_namespace {
|
||||
#if !defined(__LP64__) && !defined(__alpha__) && !defined(__SUNPRO_CC)
|
||||
#if defined(__APPLE__) || !defined(__LP64__) && !defined(__alpha__) && !defined(__SUNPRO_CC)
|
||||
template<>
|
||||
struct hash<uint64_t> {
|
||||
size_t operator()(uint64_t r) const {
|
||||
|
||||
@@ -58,7 +58,7 @@ class DerivO3CPU(BaseCPU):
|
||||
cachePorts = Param.Unsigned(200, "Cache Ports")
|
||||
icache_port = Port("Instruction Port")
|
||||
dcache_port = Port("Data Port")
|
||||
_mem_ports = ['icache_port', 'dcache_port']
|
||||
_mem_ports = BaseCPU._mem_ports + ['icache_port', 'dcache_port']
|
||||
|
||||
decodeToFetchDelay = Param.Unsigned(1, "Decode to fetch delay")
|
||||
renameToFetchDelay = Param.Unsigned(1 ,"Rename to fetch delay")
|
||||
|
||||
@@ -289,9 +289,13 @@ O3ThreadContext<Impl>::copyArchRegs(ThreadContext *tc)
|
||||
// Copy the misc regs.
|
||||
TheISA::copyMiscRegs(tc, this);
|
||||
|
||||
// Then finally set the PC and the next PC.
|
||||
// Then finally set the PC, the next PC, the nextNPC, the micropc, and the
|
||||
// next micropc.
|
||||
cpu->setPC(tc->readPC(), tid);
|
||||
cpu->setNextPC(tc->readNextPC(), tid);
|
||||
cpu->setNextNPC(tc->readNextNPC(), tid);
|
||||
cpu->setMicroPC(tc->readMicroPC(), tid);
|
||||
cpu->setNextMicroPC(tc->readNextMicroPC(), tid);
|
||||
#if !FULL_SYSTEM
|
||||
this->thread->funcExeInst = tc->readFuncExeInst();
|
||||
#endif
|
||||
@@ -448,6 +452,30 @@ O3ThreadContext<Impl>::setNextPC(uint64_t val)
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
O3ThreadContext<Impl>::setMicroPC(uint64_t val)
|
||||
{
|
||||
cpu->setMicroPC(val, thread->readTid());
|
||||
|
||||
// Squash if we're not already in a state update mode.
|
||||
if (!thread->trapPending && !thread->inSyscall) {
|
||||
cpu->squashFromTC(thread->readTid());
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
O3ThreadContext<Impl>::setNextMicroPC(uint64_t val)
|
||||
{
|
||||
cpu->setNextMicroPC(val, thread->readTid());
|
||||
|
||||
// Squash if we're not already in a state update mode.
|
||||
if (!thread->trapPending && !thread->inSyscall) {
|
||||
cpu->squashFromTC(thread->readTid());
|
||||
}
|
||||
}
|
||||
|
||||
template <class Impl>
|
||||
void
|
||||
O3ThreadContext<Impl>::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
|
||||
|
||||
@@ -41,4 +41,5 @@ class AtomicSimpleCPU(BaseCPU):
|
||||
icache_port = Port("Instruction Port")
|
||||
dcache_port = Port("Data Port")
|
||||
physmem_port = Port("Physical Memory Port")
|
||||
_mem_ports = ['icache_port', 'dcache_port', 'physmem_port']
|
||||
_mem_ports = BaseCPU._mem_ports + \
|
||||
['icache_port', 'dcache_port', 'physmem_port']
|
||||
|
||||
@@ -38,4 +38,4 @@ class TimingSimpleCPU(BaseCPU):
|
||||
profile = Param.Latency('0ns', "trace the kernel stack")
|
||||
icache_port = Port("Instruction Port")
|
||||
dcache_port = Port("Data Port")
|
||||
_mem_ports = ['icache_port', 'dcache_port']
|
||||
_mem_ports = BaseCPU._mem_ports + ['icache_port', 'dcache_port']
|
||||
|
||||
@@ -156,7 +156,7 @@ PageTable::serialize(std::ostream &os)
|
||||
PTableItr iter = pTable.begin();
|
||||
PTableItr end = pTable.end();
|
||||
while (iter != end) {
|
||||
os << "\n[" << csprintf("%s.Entry%d", name(), count) << "]\n";
|
||||
os << "\n[" << csprintf("%s.Entry%d", process->name(), count) << "]\n";
|
||||
|
||||
paramOut(os, "vaddr", iter->first);
|
||||
iter->second.serialize(os);
|
||||
@@ -178,9 +178,9 @@ PageTable::unserialize(Checkpoint *cp, const std::string §ion)
|
||||
pTable.clear();
|
||||
|
||||
while(i < count) {
|
||||
paramIn(cp, csprintf("%s.Entry%d", name(), i), "vaddr", vaddr);
|
||||
paramIn(cp, csprintf("%s.Entry%d", process->name(), i), "vaddr", vaddr);
|
||||
entry = new TheISA::TlbEntry();
|
||||
entry->unserialize(cp, csprintf("%s.Entry%d", name(), i));
|
||||
entry->unserialize(cp, csprintf("%s.Entry%d", process->name(), i));
|
||||
pTable[vaddr] = *entry;
|
||||
++i;
|
||||
}
|
||||
|
||||
@@ -793,12 +793,14 @@ class SimObject(object):
|
||||
# necessary to construct it. Does *not* recursively create
|
||||
# children.
|
||||
def getCCObject(self):
|
||||
params = self.getCCParams()
|
||||
if not self._ccObject:
|
||||
self._ccObject = -1 # flag to catch cycles in recursion
|
||||
# Cycles in the configuration heirarchy are not supported. This
|
||||
# will catch the resulting recursion and stop.
|
||||
self._ccObject = -1
|
||||
params = self.getCCParams()
|
||||
self._ccObject = params.create()
|
||||
elif self._ccObject == -1:
|
||||
raise RuntimeError, "%s: recursive call to getCCObject()" \
|
||||
raise RuntimeError, "%s: Cycle found in configuration heirarchy." \
|
||||
% self.path()
|
||||
return self._ccObject
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ optparser.add_option('--scons-opts', dest='scons_opts', default='',
|
||||
help='scons options', metavar='OPTS')
|
||||
optparser.add_option('-j', '--jobs', type='int', default=1,
|
||||
help='number of parallel jobs to use')
|
||||
optparser.add_option('-k', '--keep-going', action='store_true',
|
||||
help='keep going after errors')
|
||||
|
||||
(options, tests) = optparser.parse_args()
|
||||
|
||||
@@ -105,6 +107,8 @@ else:
|
||||
scons_opts = options.scons_opts
|
||||
if options.jobs != 1:
|
||||
scons_opts += ' -j %d' % options.jobs
|
||||
if options.keep_going:
|
||||
scons_opts += ' -k'
|
||||
|
||||
system('scons IGNORE_STYLE=True %s %s' % (scons_opts, ' '.join(targets)))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user