*/
#include "arch/x86/isa_traits.hh"
+#include "arch/x86/miscregs.hh"
#include "arch/x86/process.hh"
#include "arch/x86/segmentregs.hh"
#include "arch/x86/types.hh"
using namespace std;
using namespace X86ISA;
+static const int ArgumentReg[] = {
+ INTREG_RDI,
+ INTREG_RSI,
+ INTREG_RDX,
+ //This argument register is r10 for syscalls and rcx for C.
+ INTREG_R10W,
+ //INTREG_RCX,
+ INTREG_R8W,
+ INTREG_R9W
+};
+static const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int);
+static const int ArgumentReg32[] = {
+ INTREG_EBX,
+ INTREG_ECX,
+ INTREG_EDX,
+ INTREG_ESI,
+ INTREG_EDI,
+};
+static const int NumArgumentRegs32 = sizeof(ArgumentReg) / sizeof(const int);
X86LiveProcess::X86LiveProcess(LiveProcessParams * params, ObjectFile *objFile,
SyscallDesc *_syscallDescs, int _numSyscallDescs) :
mmap_start = mmap_end = (Addr)0x2aaaaaaab000ULL;
}
+void
+I386LiveProcess::syscall(int64_t callnum, ThreadContext *tc)
+{
+ Addr eip = tc->readPC();
+ if (eip >= vsyscallPage.base &&
+ eip < vsyscallPage.base + vsyscallPage.size) {
+ tc->setNextPC(vsyscallPage.base + vsyscallPage.vsysexitOffset);
+ }
+ X86LiveProcess::syscall(callnum, tc);
+}
+
+
I386LiveProcess::I386LiveProcess(LiveProcessParams *params,
ObjectFile *objFile, SyscallDesc *_syscallDescs,
int _numSyscallDescs) :
X86LiveProcess(params, objFile, _syscallDescs, _numSyscallDescs)
{
- stack_base = (Addr)0xffffe000ULL;
+ _gdtStart = 0x100000000;
+ _gdtSize = VMPageSize;
+
+ vsyscallPage.base = 0xffffe000ULL;
+ vsyscallPage.size = VMPageSize;
+ vsyscallPage.vsyscallOffset = 0x400;
+ vsyscallPage.vsysexitOffset = 0x410;
+
+ stack_base = vsyscallPage.base;
// Set pointer for next thread stack. Reserve 8M for main stack.
next_thread_stack_base = stack_base - (8 * 1024 * 1024);
// Set up region for mmaps. This was determined empirically and may not
// always be correct.
- mmap_start = mmap_end = (Addr)0xf7ffd000ULL;
+ mmap_start = mmap_end = (Addr)0xf7ffe000ULL;
}
SyscallDesc*
ThreadContext * tc = system->getThreadContext(contextIds[i]);
SegAttr dataAttr = 0;
+ dataAttr.dpl = 3;
+ dataAttr.unusable = 0;
+ dataAttr.defaultSize = 1;
+ dataAttr.longMode = 1;
+ dataAttr.avl = 0;
+ dataAttr.granularity = 1;
+ dataAttr.present = 1;
+ dataAttr.type = 3;
dataAttr.writable = 1;
dataAttr.readable = 1;
dataAttr.expandDown = 0;
- dataAttr.dpl = 3;
- dataAttr.defaultSize = 0;
- dataAttr.longMode = 1;
+ dataAttr.system = 1;
//Initialize the segment registers.
for(int seg = 0; seg < NUM_SEGMENTREGS; seg++) {
}
SegAttr csAttr = 0;
- csAttr.writable = 0;
- csAttr.readable = 1;
- csAttr.expandDown = 0;
csAttr.dpl = 3;
+ csAttr.unusable = 0;
csAttr.defaultSize = 0;
csAttr.longMode = 1;
+ csAttr.avl = 0;
+ csAttr.granularity = 1;
+ csAttr.present = 1;
+ csAttr.type = 10;
+ csAttr.writable = 0;
+ csAttr.readable = 1;
+ csAttr.expandDown = 0;
+ csAttr.system = 1;
tc->setMiscRegNoEffect(MISCREG_CS_ATTR, csAttr);
+ Efer efer = 0;
+ efer.sce = 1; // Enable system call extensions.
+ efer.lme = 1; // Enable long mode.
+ efer.lma = 1; // Activate long mode.
+ efer.nxe = 1; // Enable nx support.
+ efer.svme = 0; // Disable svm support for now. It isn't implemented.
+ efer.ffxsr = 1; // Turn on fast fxsave and fxrstor.
+ tc->setMiscReg(MISCREG_EFER, efer);
+
//Set up the registers that describe the operating mode.
CR0 cr0 = 0;
cr0.pg = 1; // Turn on paging.
cr0.pe = 1; // We're definitely in protected mode.
tc->setMiscReg(MISCREG_CR0, cr0);
- Efer efer = 0;
- efer.sce = 1; // Enable system call extensions.
- efer.lme = 1; // Enable long mode.
- efer.lma = 1; // Activate long mode.
- efer.nxe = 1; // Enable nx support.
- efer.svme = 0; // Disable svm support for now. It isn't implemented.
- efer.ffxsr = 1; // Turn on fast fxsave and fxrstor.
- tc->setMiscReg(MISCREG_EFER, efer);
+ tc->setMiscReg(MISCREG_MXCSR, 0x1f80);
}
}
argsInit(sizeof(uint32_t), VMPageSize);
+ /*
+ * Set up a GDT for this process. The whole GDT wouldn't really be for
+ * this process, but the only parts we care about are.
+ */
+ pTable->allocate(_gdtStart, _gdtSize);
+ uint64_t zero = 0;
+ assert(_gdtSize % sizeof(zero) == 0);
+ for (Addr gdtCurrent = _gdtStart;
+ gdtCurrent < _gdtStart + _gdtSize; gdtCurrent += sizeof(zero)) {
+ initVirtMem->write(gdtCurrent, zero);
+ }
+
+ // Set up the vsyscall page for this process.
+ pTable->allocate(vsyscallPage.base, vsyscallPage.size);
+ uint8_t vsyscallBlob[] = {
+ 0x51, // push %ecx
+ 0x52, // push %edp
+ 0x55, // push %ebp
+ 0x89, 0xe5, // mov %esp, %ebp
+ 0x0f, 0x34 // sysenter
+ };
+ initVirtMem->writeBlob(vsyscallPage.base + vsyscallPage.vsyscallOffset,
+ vsyscallBlob, sizeof(vsyscallBlob));
+
+ uint8_t vsysexitBlob[] = {
+ 0x5d, // pop %ebp
+ 0x5a, // pop %edx
+ 0x59, // pop %ecx
+ 0xc3 // ret
+ };
+ initVirtMem->writeBlob(vsyscallPage.base + vsyscallPage.vsysexitOffset,
+ vsysexitBlob, sizeof(vsysexitBlob));
+
for (int i = 0; i < contextIds.size(); i++) {
ThreadContext * tc = system->getThreadContext(contextIds[i]);
SegAttr dataAttr = 0;
- dataAttr.writable = 1;
- dataAttr.readable = 1;
- dataAttr.expandDown = 0;
dataAttr.dpl = 3;
+ dataAttr.unusable = 0;
dataAttr.defaultSize = 1;
dataAttr.longMode = 0;
+ dataAttr.avl = 0;
+ dataAttr.granularity = 1;
+ dataAttr.present = 1;
+ dataAttr.type = 3;
+ dataAttr.writable = 1;
+ dataAttr.readable = 1;
+ dataAttr.expandDown = 0;
+ dataAttr.system = 1;
//Initialize the segment registers.
for(int seg = 0; seg < NUM_SEGMENTREGS; seg++) {
tc->setMiscRegNoEffect(MISCREG_SEG_EFF_BASE(seg), 0);
tc->setMiscRegNoEffect(MISCREG_SEG_ATTR(seg), dataAttr);
tc->setMiscRegNoEffect(MISCREG_SEG_SEL(seg), 0xB);
+ tc->setMiscRegNoEffect(MISCREG_SEG_LIMIT(seg), (uint32_t)(-1));
}
SegAttr csAttr = 0;
- csAttr.writable = 0;
- csAttr.readable = 1;
- csAttr.expandDown = 0;
csAttr.dpl = 3;
+ csAttr.unusable = 0;
csAttr.defaultSize = 1;
csAttr.longMode = 0;
+ csAttr.avl = 0;
+ csAttr.granularity = 1;
+ csAttr.present = 1;
+ csAttr.type = 0xa;
+ csAttr.writable = 0;
+ csAttr.readable = 1;
+ csAttr.expandDown = 0;
+ csAttr.system = 1;
tc->setMiscRegNoEffect(MISCREG_CS_ATTR, csAttr);
+ tc->setMiscRegNoEffect(MISCREG_TSG_BASE, _gdtStart);
+ tc->setMiscRegNoEffect(MISCREG_TSG_EFF_BASE, _gdtStart);
+ tc->setMiscRegNoEffect(MISCREG_TSG_LIMIT, _gdtStart + _gdtSize - 1);
+
+ // Set the LDT selector to 0 to deactivate it.
+ tc->setMiscRegNoEffect(MISCREG_TSL, 0);
+
+ Efer efer = 0;
+ efer.sce = 1; // Enable system call extensions.
+ efer.lme = 1; // Enable long mode.
+ efer.lma = 0; // Deactivate long mode.
+ efer.nxe = 1; // Enable nx support.
+ efer.svme = 0; // Disable svm support for now. It isn't implemented.
+ efer.ffxsr = 1; // Turn on fast fxsave and fxrstor.
+ tc->setMiscReg(MISCREG_EFER, efer);
+
//Set up the registers that describe the operating mode.
CR0 cr0 = 0;
cr0.pg = 1; // Turn on paging.
cr0.pe = 1; // We're definitely in protected mode.
tc->setMiscReg(MISCREG_CR0, cr0);
- Efer efer = 0;
- efer.sce = 1; // Enable system call extensions.
- efer.lme = 1; // Enable long mode.
- efer.lma = 0; // Deactivate long mode.
- efer.nxe = 1; // Enable nx support.
- efer.svme = 0; // Disable svm support for now. It isn't implemented.
- efer.ffxsr = 1; // Turn on fast fxsave and fxrstor.
- tc->setMiscReg(MISCREG_EFER, efer);
+ tc->setMiscReg(MISCREG_MXCSR, 0x1f80);
}
}
template<class IntType>
void
-X86LiveProcess::argsInit(int pageSize)
+X86LiveProcess::argsInit(int pageSize,
+ std::vector<AuxVector<IntType> > extraAuxvs)
{
int intSize = sizeof(IntType);
typedef AuxVector<IntType> auxv_t;
- std::vector<auxv_t> auxv;
+ std::vector<auxv_t> auxv = extraAuxvs;
string filename;
if(argv.size() < 1)
//The system page size
auxv.push_back(auxv_t(M5_AT_PAGESZ, X86ISA::VMPageSize));
//Frequency at which times() increments
+ //Defined to be 100 in the kernel source.
auxv.push_back(auxv_t(M5_AT_CLKTCK, 100));
// For statically linked executables, this is the virtual address of the
// program header tables if they appear in the executable image
auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize()));
// This is the number of program headers from the original elf file.
auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
- //Defined to be 100 in the kernel source.
//This is the address of the elf "interpreter", It should be set
//to 0 for regular executables. It should be something else
//(not sure what) for dynamic libraries.
void
X86_64LiveProcess::argsInit(int intSize, int pageSize)
{
- X86LiveProcess::argsInit<uint64_t>(pageSize);
+ std::vector<AuxVector<uint64_t> > extraAuxvs;
+ X86LiveProcess::argsInit<uint64_t>(pageSize, extraAuxvs);
}
void
I386LiveProcess::argsInit(int intSize, int pageSize)
{
- X86LiveProcess::argsInit<uint32_t>(pageSize);
+ std::vector<AuxVector<uint32_t> > extraAuxvs;
+ //Tell the binary where the vsyscall part of the vsyscall page is.
+ extraAuxvs.push_back(AuxVector<uint32_t>(0x20,
+ vsyscallPage.base + vsyscallPage.vsyscallOffset));
+ extraAuxvs.push_back(AuxVector<uint32_t>(0x21, vsyscallPage.base));
+ X86LiveProcess::argsInit<uint32_t>(pageSize, extraAuxvs);
+}
+
+void
+X86LiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn return_value)
+{
+ tc->setIntReg(INTREG_RAX, return_value.value());
+}
+
+X86ISA::IntReg
+X86_64LiveProcess::getSyscallArg(ThreadContext *tc, int i)
+{
+ assert(i < NumArgumentRegs);
+ return tc->readIntReg(ArgumentReg[i]);
+}
+
+void
+X86_64LiveProcess::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val)
+{
+ assert(i < NumArgumentRegs);
+ return tc->setIntReg(ArgumentReg[i], val);
+}
+
+X86ISA::IntReg
+I386LiveProcess::getSyscallArg(ThreadContext *tc, int i)
+{
+ assert(i < NumArgumentRegs32);
+ return tc->readIntReg(ArgumentReg32[i]);
+}
+
+void
+I386LiveProcess::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val)
+{
+ assert(i < NumArgumentRegs);
+ return tc->setIntReg(ArgumentReg[i], val);
}