When dealing with segmentation in x86, it is *usually* illegal to attempt to access a segment which has a null selector when in protected mode and not in 64 bit mode. While this is *almost* true, it is not actually technically true. What actually *is* true is that if you *set up* a segment using a null selector in those circumstances, that segment becomes unusable, and then tryint to use it causes a fault. When in real mode, it is perfectly legal to use a null selector to access memory, since that is just a selector with numerical value 0. When you then transition into protected mode, the selector would still be 0 (a null selector), but the segment itself would still be set up properly and usuable using the base value, limit, and other attributes it carried over from real mode. Rather than check if a segment has a null selector while handling segmentation, it's more correct for us to keep track of whether the segment is currently usable and check that in the TLB. Change-Id: Ic2c09e1cfa05afcb03900213b72733545c8f0f4c Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/55245 Maintainer: Gabe Black <gabe.black@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Bobby Bruce <bbruce@ucdavis.edu>
1043 lines
38 KiB
C++
1043 lines
38 KiB
C++
/*
|
|
* Copyright (c) 2014 Advanced Micro Devices, Inc.
|
|
* Copyright (c) 2007 The Hewlett-Packard Development Company
|
|
* All rights reserved.
|
|
*
|
|
* The license below extends only to copyright in the software and shall
|
|
* not be construed as granting a license to any other intellectual
|
|
* property including but not limited to intellectual property relating
|
|
* to a hardware implementation of the functionality of the software
|
|
* licensed hereunder. You may use the software subject to the license
|
|
* terms below provided that you ensure that this notice is replicated
|
|
* unmodified and in its entirety in all distributions of the software,
|
|
* modified or unmodified, in source code or in binary form.
|
|
*
|
|
* Copyright (c) 2003-2006 The Regents of The University of Michigan
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met: redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer;
|
|
* redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution;
|
|
* neither the name of the copyright holders nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include "arch/x86/process.hh"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "arch/x86/fs_workload.hh"
|
|
#include "arch/x86/page_size.hh"
|
|
#include "arch/x86/regs/int.hh"
|
|
#include "arch/x86/regs/misc.hh"
|
|
#include "arch/x86/regs/segment.hh"
|
|
#include "arch/x86/se_workload.hh"
|
|
#include "arch/x86/types.hh"
|
|
#include "base/loader/elf_object.hh"
|
|
#include "base/loader/object_file.hh"
|
|
#include "base/logging.hh"
|
|
#include "base/trace.hh"
|
|
#include "cpu/thread_context.hh"
|
|
#include "debug/Stack.hh"
|
|
#include "mem/multi_level_page_table.hh"
|
|
#include "mem/page_table.hh"
|
|
#include "params/Process.hh"
|
|
#include "sim/aux_vector.hh"
|
|
#include "sim/byteswap.hh"
|
|
#include "sim/process_impl.hh"
|
|
#include "sim/syscall_desc.hh"
|
|
#include "sim/syscall_return.hh"
|
|
#include "sim/system.hh"
|
|
|
|
namespace gem5
|
|
{
|
|
|
|
using namespace X86ISA;
|
|
|
|
template class MultiLevelPageTable<LongModePTE<47, 39>,
|
|
LongModePTE<38, 30>,
|
|
LongModePTE<29, 21>,
|
|
LongModePTE<20, 12> >;
|
|
typedef MultiLevelPageTable<LongModePTE<47, 39>,
|
|
LongModePTE<38, 30>,
|
|
LongModePTE<29, 21>,
|
|
LongModePTE<20, 12> > ArchPageTable;
|
|
|
|
X86Process::X86Process(const ProcessParams ¶ms,
|
|
loader::ObjectFile *objFile) :
|
|
Process(params, params.useArchPT ?
|
|
static_cast<EmulationPageTable *>(
|
|
new ArchPageTable(params.name, params.pid,
|
|
params.system, PageBytes)) :
|
|
new EmulationPageTable(params.name, params.pid,
|
|
PageBytes),
|
|
objFile)
|
|
{
|
|
}
|
|
|
|
void X86Process::clone(ThreadContext *old_tc, ThreadContext *new_tc,
|
|
Process *p, RegVal flags)
|
|
{
|
|
Process::clone(old_tc, new_tc, p, flags);
|
|
X86Process *process = (X86Process*)p;
|
|
*process = *this;
|
|
}
|
|
|
|
X86_64Process::X86_64Process(const ProcessParams ¶ms,
|
|
loader::ObjectFile *objFile) :
|
|
X86Process(params, objFile)
|
|
{
|
|
vsyscallPage.base = 0xffffffffff600000ULL;
|
|
vsyscallPage.size = PageBytes;
|
|
vsyscallPage.vtimeOffset = 0x400;
|
|
vsyscallPage.vgettimeofdayOffset = 0x0;
|
|
|
|
Addr brk_point = roundUp(image.maxAddr(), PageBytes);
|
|
Addr stack_base = 0x7FFFFFFFF000ULL;
|
|
Addr max_stack_size = 8 * 1024 * 1024;
|
|
Addr next_thread_stack_base = stack_base - max_stack_size;
|
|
Addr mmap_end = 0x7FFFF7FFF000ULL;
|
|
|
|
memState = std::make_shared<MemState>(
|
|
this, brk_point, stack_base, max_stack_size,
|
|
next_thread_stack_base, mmap_end);
|
|
}
|
|
|
|
|
|
I386Process::I386Process(const ProcessParams ¶ms,
|
|
loader::ObjectFile *objFile) :
|
|
X86Process(params, objFile)
|
|
{
|
|
if (kvmInSE)
|
|
panic("KVM CPU model does not support 32 bit processes");
|
|
|
|
_gdtStart = 0xffffd000ULL;
|
|
_gdtSize = PageBytes;
|
|
|
|
vsyscallPage.base = 0xffffe000ULL;
|
|
vsyscallPage.size = PageBytes;
|
|
vsyscallPage.vsyscallOffset = 0x400;
|
|
vsyscallPage.vsysexitOffset = 0x410;
|
|
|
|
Addr brk_point = roundUp(image.maxAddr(), PageBytes);
|
|
Addr stack_base = _gdtStart;
|
|
Addr max_stack_size = 8 * 1024 * 1024;
|
|
Addr next_thread_stack_base = stack_base - max_stack_size;
|
|
Addr mmap_end = 0xB7FFF000ULL;
|
|
|
|
memState = std::make_shared<MemState>(
|
|
this, brk_point, stack_base, max_stack_size,
|
|
next_thread_stack_base, mmap_end);
|
|
}
|
|
|
|
void
|
|
X86_64Process::initState()
|
|
{
|
|
X86Process::initState();
|
|
|
|
if (useForClone)
|
|
return;
|
|
|
|
argsInit(PageBytes);
|
|
|
|
// Set up the vsyscall page for this process.
|
|
memState->mapRegion(vsyscallPage.base, vsyscallPage.size, "vsyscall");
|
|
uint8_t vtimeBlob[] = {
|
|
0x48,0xc7,0xc0,0xc9,0x00,0x00,0x00, // mov $0xc9,%rax
|
|
0x0f,0x05, // syscall
|
|
0xc3 // retq
|
|
};
|
|
initVirtMem->writeBlob(vsyscallPage.base + vsyscallPage.vtimeOffset,
|
|
vtimeBlob, sizeof(vtimeBlob));
|
|
|
|
uint8_t vgettimeofdayBlob[] = {
|
|
0x48,0xc7,0xc0,0x60,0x00,0x00,0x00, // mov $0x60,%rax
|
|
0x0f,0x05, // syscall
|
|
0xc3 // retq
|
|
};
|
|
initVirtMem->writeBlob(
|
|
vsyscallPage.base + vsyscallPage.vgettimeofdayOffset,
|
|
vgettimeofdayBlob, sizeof(vgettimeofdayBlob));
|
|
|
|
if (kvmInSE) {
|
|
PortProxy physProxy = system->physProxy;
|
|
|
|
Addr syscallCodePhysAddr = seWorkload->allocPhysPages(1);
|
|
Addr gdtPhysAddr = seWorkload->allocPhysPages(1);
|
|
Addr idtPhysAddr = seWorkload->allocPhysPages(1);
|
|
Addr istPhysAddr = seWorkload->allocPhysPages(1);
|
|
Addr tssPhysAddr = seWorkload->allocPhysPages(1);
|
|
Addr pfHandlerPhysAddr = seWorkload->allocPhysPages(1);
|
|
|
|
/*
|
|
* Set up the gdt.
|
|
*/
|
|
uint8_t numGDTEntries = 0;
|
|
uint64_t nullDescriptor = 0;
|
|
physProxy.writeBlob(gdtPhysAddr + numGDTEntries * 8,
|
|
&nullDescriptor, 8);
|
|
numGDTEntries++;
|
|
|
|
SegDescriptor initDesc = 0;
|
|
initDesc.type.codeOrData = 0; // code or data type
|
|
initDesc.type.c = 0; // conforming
|
|
initDesc.type.r = 1; // readable
|
|
initDesc.dpl = 0; // privilege
|
|
initDesc.p = 1; // present
|
|
initDesc.l = 1; // longmode - 64 bit
|
|
initDesc.d = 0; // operand size
|
|
initDesc.g = 1;
|
|
initDesc.s = 1; // system segment
|
|
initDesc.limit = 0xFFFFFFFF;
|
|
initDesc.base = 0;
|
|
|
|
//64 bit code segment
|
|
SegDescriptor csLowPLDesc = initDesc;
|
|
csLowPLDesc.type.codeOrData = 1;
|
|
csLowPLDesc.dpl = 0;
|
|
uint64_t csLowPLDescVal = csLowPLDesc;
|
|
physProxy.writeBlob(gdtPhysAddr + numGDTEntries * 8,
|
|
&csLowPLDescVal, 8);
|
|
|
|
numGDTEntries++;
|
|
|
|
SegSelector csLowPL = 0;
|
|
csLowPL.si = numGDTEntries - 1;
|
|
csLowPL.rpl = 0;
|
|
|
|
//64 bit data segment
|
|
SegDescriptor dsLowPLDesc = initDesc;
|
|
dsLowPLDesc.type.codeOrData = 0;
|
|
dsLowPLDesc.dpl = 0;
|
|
uint64_t dsLowPLDescVal = dsLowPLDesc;
|
|
physProxy.writeBlob(gdtPhysAddr + numGDTEntries * 8,
|
|
&dsLowPLDescVal, 8);
|
|
|
|
numGDTEntries++;
|
|
|
|
SegSelector dsLowPL = 0;
|
|
dsLowPL.si = numGDTEntries - 1;
|
|
dsLowPL.rpl = 0;
|
|
|
|
//64 bit data segment
|
|
SegDescriptor dsDesc = initDesc;
|
|
dsDesc.type.codeOrData = 0;
|
|
dsDesc.dpl = 3;
|
|
uint64_t dsDescVal = dsDesc;
|
|
physProxy.writeBlob(gdtPhysAddr + numGDTEntries * 8,
|
|
&dsDescVal, 8);
|
|
|
|
numGDTEntries++;
|
|
|
|
SegSelector ds = 0;
|
|
ds.si = numGDTEntries - 1;
|
|
ds.rpl = 3;
|
|
|
|
//64 bit code segment
|
|
SegDescriptor csDesc = initDesc;
|
|
csDesc.type.codeOrData = 1;
|
|
csDesc.dpl = 3;
|
|
uint64_t csDescVal = csDesc;
|
|
physProxy.writeBlob(gdtPhysAddr + numGDTEntries * 8,
|
|
&csDescVal, 8);
|
|
|
|
numGDTEntries++;
|
|
|
|
SegSelector cs = 0;
|
|
cs.si = numGDTEntries - 1;
|
|
cs.rpl = 3;
|
|
|
|
SegSelector scall = 0;
|
|
scall.si = csLowPL.si;
|
|
scall.rpl = 0;
|
|
|
|
SegSelector sret = 0;
|
|
sret.si = dsLowPL.si;
|
|
sret.rpl = 3;
|
|
|
|
/* In long mode the TSS has been extended to 16 Bytes */
|
|
TSSlow TSSDescLow = 0;
|
|
TSSDescLow.type = 0xB;
|
|
TSSDescLow.dpl = 0; // Privelege level 0
|
|
TSSDescLow.p = 1; // Present
|
|
TSSDescLow.limit = 0xFFFFFFFF;
|
|
TSSDescLow.base = bits(TSSVirtAddr, 31, 0);
|
|
|
|
TSShigh TSSDescHigh = 0;
|
|
TSSDescHigh.base = bits(TSSVirtAddr, 63, 32);
|
|
|
|
struct TSSDesc
|
|
{
|
|
uint64_t low;
|
|
uint64_t high;
|
|
} tssDescVal = {TSSDescLow, TSSDescHigh};
|
|
|
|
physProxy.writeBlob(gdtPhysAddr + numGDTEntries * 8,
|
|
&tssDescVal, sizeof(tssDescVal));
|
|
|
|
numGDTEntries++;
|
|
|
|
SegSelector tssSel = 0;
|
|
tssSel.si = numGDTEntries - 1;
|
|
|
|
uint64_t tss_base_addr = (TSSDescHigh.base << 32) | TSSDescLow.base;
|
|
uint64_t tss_limit = TSSDescLow.limit;
|
|
|
|
SegAttr tss_attr = 0;
|
|
|
|
tss_attr.type = TSSDescLow.type;
|
|
tss_attr.dpl = TSSDescLow.dpl;
|
|
tss_attr.present = TSSDescLow.p;
|
|
tss_attr.granularity = TSSDescLow.g;
|
|
tss_attr.unusable = 0;
|
|
|
|
for (int i = 0; i < contextIds.size(); i++) {
|
|
ThreadContext *tc = system->threads[contextIds[i]];
|
|
|
|
tc->setMiscReg(MISCREG_CS, cs);
|
|
tc->setMiscReg(MISCREG_DS, ds);
|
|
tc->setMiscReg(MISCREG_ES, ds);
|
|
tc->setMiscReg(MISCREG_FS, ds);
|
|
tc->setMiscReg(MISCREG_GS, ds);
|
|
tc->setMiscReg(MISCREG_SS, ds);
|
|
|
|
// LDT
|
|
tc->setMiscReg(MISCREG_TSL, 0);
|
|
SegAttr tslAttr = 0;
|
|
tslAttr.unusable = 1;
|
|
tslAttr.present = 0;
|
|
tslAttr.type = 2;
|
|
tc->setMiscReg(MISCREG_TSL_ATTR, tslAttr);
|
|
|
|
tc->setMiscReg(MISCREG_TSG_BASE, GDTVirtAddr);
|
|
tc->setMiscReg(MISCREG_TSG_LIMIT, 8 * numGDTEntries - 1);
|
|
|
|
tc->setMiscReg(MISCREG_TR, tssSel);
|
|
tc->setMiscReg(MISCREG_TR_BASE, tss_base_addr);
|
|
tc->setMiscReg(MISCREG_TR_EFF_BASE, tss_base_addr);
|
|
tc->setMiscReg(MISCREG_TR_LIMIT, tss_limit);
|
|
tc->setMiscReg(MISCREG_TR_ATTR, tss_attr);
|
|
|
|
//Start using longmode segments.
|
|
installSegDesc(tc, SEGMENT_REG_CS, csDesc, true);
|
|
installSegDesc(tc, SEGMENT_REG_DS, dsDesc, true);
|
|
installSegDesc(tc, SEGMENT_REG_ES, dsDesc, true);
|
|
installSegDesc(tc, SEGMENT_REG_FS, dsDesc, true);
|
|
installSegDesc(tc, SEGMENT_REG_GS, dsDesc, true);
|
|
installSegDesc(tc, SEGMENT_REG_SS, dsDesc, true);
|
|
|
|
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.
|
|
efer.ffxsr = 0; // Disable 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.cd = 0; // Don't disable caching.
|
|
cr0.nw = 0; // This is bit is defined to be ignored.
|
|
cr0.am = 0; // No alignment checking
|
|
cr0.wp = 0; // Supervisor mode can write read only pages
|
|
cr0.ne = 1;
|
|
cr0.et = 1; // This should always be 1
|
|
cr0.ts = 0; // We don't do task switching, so causing fp exceptions
|
|
// would be pointless.
|
|
cr0.em = 0; // Allow x87 instructions to execute natively.
|
|
cr0.mp = 1; // This doesn't really matter, but the manual suggests
|
|
// setting it to one.
|
|
cr0.pe = 1; // We're definitely in protected mode.
|
|
tc->setMiscReg(MISCREG_CR0, cr0);
|
|
|
|
CR0 cr2 = 0;
|
|
tc->setMiscReg(MISCREG_CR2, cr2);
|
|
|
|
CR3 cr3 = dynamic_cast<ArchPageTable *>(pTable)->basePtr();
|
|
tc->setMiscReg(MISCREG_CR3, cr3);
|
|
|
|
CR4 cr4 = 0;
|
|
//Turn on pae.
|
|
cr4.osxsave = 0; // Disable XSAVE and Proc Extended States
|
|
cr4.osxmmexcpt = 0; // Operating System Unmasked Exception
|
|
cr4.osfxsr = 1; // Operating System FXSave/FSRSTOR Support
|
|
cr4.pce = 0; // Performance-Monitoring Counter Enable
|
|
cr4.pge = 0; // Page-Global Enable
|
|
cr4.mce = 0; // Machine Check Enable
|
|
cr4.pae = 1; // Physical-Address Extension
|
|
cr4.pse = 0; // Page Size Extensions
|
|
cr4.de = 0; // Debugging Extensions
|
|
cr4.tsd = 0; // Time Stamp Disable
|
|
cr4.pvi = 0; // Protected-Mode Virtual Interrupts
|
|
cr4.vme = 0; // Virtual-8086 Mode Extensions
|
|
|
|
tc->setMiscReg(MISCREG_CR4, cr4);
|
|
|
|
CR8 cr8 = 0;
|
|
tc->setMiscReg(MISCREG_CR8, cr8);
|
|
|
|
tc->setMiscReg(MISCREG_MXCSR, 0x1f80);
|
|
|
|
tc->setMiscReg(MISCREG_APIC_BASE, 0xfee00900);
|
|
|
|
tc->setMiscReg(MISCREG_TSG_BASE, GDTVirtAddr);
|
|
tc->setMiscReg(MISCREG_TSG_LIMIT, 0xffff);
|
|
|
|
tc->setMiscReg(MISCREG_IDTR_BASE, IDTVirtAddr);
|
|
tc->setMiscReg(MISCREG_IDTR_LIMIT, 0xffff);
|
|
|
|
/* enabling syscall and sysret */
|
|
RegVal star = ((RegVal)sret << 48) | ((RegVal)scall << 32);
|
|
tc->setMiscReg(MISCREG_STAR, star);
|
|
RegVal lstar = (RegVal)syscallCodeVirtAddr;
|
|
tc->setMiscReg(MISCREG_LSTAR, lstar);
|
|
RegVal sfmask = (1 << 8) | (1 << 10); // TF | DF
|
|
tc->setMiscReg(MISCREG_SF_MASK, sfmask);
|
|
}
|
|
|
|
/* Set up the content of the TSS and write it to physical memory. */
|
|
|
|
struct
|
|
{
|
|
uint32_t reserved0; // +00h
|
|
uint32_t RSP0_low; // +04h
|
|
uint32_t RSP0_high; // +08h
|
|
uint32_t RSP1_low; // +0Ch
|
|
uint32_t RSP1_high; // +10h
|
|
uint32_t RSP2_low; // +14h
|
|
uint32_t RSP2_high; // +18h
|
|
uint32_t reserved1; // +1Ch
|
|
uint32_t reserved2; // +20h
|
|
uint32_t IST1_low; // +24h
|
|
uint32_t IST1_high; // +28h
|
|
uint32_t IST2_low; // +2Ch
|
|
uint32_t IST2_high; // +30h
|
|
uint32_t IST3_low; // +34h
|
|
uint32_t IST3_high; // +38h
|
|
uint32_t IST4_low; // +3Ch
|
|
uint32_t IST4_high; // +40h
|
|
uint32_t IST5_low; // +44h
|
|
uint32_t IST5_high; // +48h
|
|
uint32_t IST6_low; // +4Ch
|
|
uint32_t IST6_high; // +50h
|
|
uint32_t IST7_low; // +54h
|
|
uint32_t IST7_high; // +58h
|
|
uint32_t reserved3; // +5Ch
|
|
uint32_t reserved4; // +60h
|
|
uint16_t reserved5; // +64h
|
|
uint16_t IO_MapBase; // +66h
|
|
} tss;
|
|
|
|
/** setting Interrupt Stack Table */
|
|
uint64_t IST_start = ISTVirtAddr + PageBytes;
|
|
tss.IST1_low = IST_start;
|
|
tss.IST1_high = IST_start >> 32;
|
|
tss.RSP0_low = tss.IST1_low;
|
|
tss.RSP0_high = tss.IST1_high;
|
|
tss.RSP1_low = tss.IST1_low;
|
|
tss.RSP1_high = tss.IST1_high;
|
|
tss.RSP2_low = tss.IST1_low;
|
|
tss.RSP2_high = tss.IST1_high;
|
|
physProxy.writeBlob(tssPhysAddr, &tss, sizeof(tss));
|
|
|
|
/* Setting IDT gates */
|
|
GateDescriptorLow PFGateLow = 0;
|
|
PFGateLow.offsetHigh = bits(PFHandlerVirtAddr, 31, 16);
|
|
PFGateLow.offsetLow = bits(PFHandlerVirtAddr, 15, 0);
|
|
PFGateLow.selector = csLowPL;
|
|
PFGateLow.p = 1;
|
|
PFGateLow.dpl = 0;
|
|
PFGateLow.type = 0xe; // gate interrupt type
|
|
PFGateLow.IST = 0; // setting IST to 0 and using RSP0
|
|
|
|
GateDescriptorHigh PFGateHigh = 0;
|
|
PFGateHigh.offset = bits(PFHandlerVirtAddr, 63, 32);
|
|
|
|
struct
|
|
{
|
|
uint64_t low;
|
|
uint64_t high;
|
|
} PFGate = {PFGateLow, PFGateHigh};
|
|
|
|
physProxy.writeBlob(idtPhysAddr + 0xE0, &PFGate, sizeof(PFGate));
|
|
|
|
/* System call handler */
|
|
uint8_t syscallBlob[] = {
|
|
// mov %rax, (0xffffc90000007000)
|
|
0x48, 0xa3, 0x00, 0x70, 0x00,
|
|
0x00, 0x00, 0xc9, 0xff, 0xff,
|
|
// sysret
|
|
0x48, 0x0f, 0x07
|
|
};
|
|
|
|
physProxy.writeBlob(syscallCodePhysAddr,
|
|
syscallBlob, sizeof(syscallBlob));
|
|
|
|
/** Page fault handler */
|
|
uint8_t faultBlob[] = {
|
|
// mov %rax, (0xffffc90000007000)
|
|
0x48, 0xa3, 0x00, 0x70, 0x00,
|
|
0x00, 0x00, 0xc9, 0xff, 0xff,
|
|
// add $0x8, %rsp # skip error
|
|
0x48, 0x83, 0xc4, 0x08,
|
|
// iretq
|
|
0x48, 0xcf
|
|
};
|
|
|
|
physProxy.writeBlob(pfHandlerPhysAddr, faultBlob, sizeof(faultBlob));
|
|
|
|
/* Syscall handler */
|
|
pTable->map(syscallCodeVirtAddr, syscallCodePhysAddr,
|
|
PageBytes, false);
|
|
/* GDT */
|
|
pTable->map(GDTVirtAddr, gdtPhysAddr, PageBytes, false);
|
|
/* IDT */
|
|
pTable->map(IDTVirtAddr, idtPhysAddr, PageBytes, false);
|
|
/* TSS */
|
|
pTable->map(TSSVirtAddr, tssPhysAddr, PageBytes, false);
|
|
/* IST */
|
|
pTable->map(ISTVirtAddr, istPhysAddr, PageBytes, false);
|
|
/* PF handler */
|
|
pTable->map(PFHandlerVirtAddr, pfHandlerPhysAddr, PageBytes, false);
|
|
/* MMIO region for m5ops */
|
|
auto m5op_range = system->m5opRange();
|
|
if (m5op_range.size()) {
|
|
pTable->map(MMIORegionVirtAddr, m5op_range.start(),
|
|
m5op_range.size(), false);
|
|
}
|
|
} else {
|
|
for (int i = 0; i < contextIds.size(); i++) {
|
|
ThreadContext * tc = system->threads[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.system = 1;
|
|
|
|
// Initialize the segment registers.
|
|
for (int seg = 0; seg < NUM_SEGMENTREGS; seg++) {
|
|
tc->setMiscRegNoEffect(MISCREG_SEG_BASE(seg), 0);
|
|
tc->setMiscRegNoEffect(MISCREG_SEG_EFF_BASE(seg), 0);
|
|
tc->setMiscRegNoEffect(MISCREG_SEG_ATTR(seg), dataAttr);
|
|
}
|
|
|
|
SegAttr csAttr = 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.cd = 0; // Don't disable caching.
|
|
cr0.nw = 0; // This is bit is defined to be ignored.
|
|
cr0.am = 0; // No alignment checking
|
|
cr0.wp = 0; // Supervisor mode can write read only pages
|
|
cr0.ne = 1;
|
|
cr0.et = 1; // This should always be 1
|
|
cr0.ts = 0; // We don't do task switching, so causing fp exceptions
|
|
// would be pointless.
|
|
cr0.em = 0; // Allow x87 instructions to execute natively.
|
|
cr0.mp = 1; // This doesn't really matter, but the manual suggests
|
|
// setting it to one.
|
|
cr0.pe = 1; // We're definitely in protected mode.
|
|
tc->setMiscReg(MISCREG_CR0, cr0);
|
|
|
|
tc->setMiscReg(MISCREG_MXCSR, 0x1f80);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
I386Process::initState()
|
|
{
|
|
X86Process::initState();
|
|
|
|
argsInit(PageBytes);
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
allocateMem(_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.
|
|
memState->mapRegion(vsyscallPage.base, vsyscallPage.size, "vsyscall");
|
|
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->threads[contextIds[i]];
|
|
|
|
SegAttr dataAttr = 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_BASE(seg), 0);
|
|
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.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);
|
|
SegAttr attr = 0;
|
|
attr.unusable = 1;
|
|
tc->setMiscRegNoEffect(MISCREG_TSL_ATTR, attr);
|
|
|
|
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.cd = 0; // Don't disable caching.
|
|
cr0.nw = 0; // This is bit is defined to be ignored.
|
|
cr0.am = 0; // No alignment checking
|
|
cr0.wp = 0; // Supervisor mode can write read only pages
|
|
cr0.ne = 1;
|
|
cr0.et = 1; // This should always be 1
|
|
cr0.ts = 0; // We don't do task switching, so causing fp exceptions
|
|
// would be pointless.
|
|
cr0.em = 0; // Allow x87 instructions to execute natively.
|
|
cr0.mp = 1; // This doesn't really matter, but the manual suggests
|
|
// setting it to one.
|
|
cr0.pe = 1; // We're definitely in protected mode.
|
|
tc->setMiscReg(MISCREG_CR0, cr0);
|
|
|
|
tc->setMiscReg(MISCREG_MXCSR, 0x1f80);
|
|
}
|
|
}
|
|
|
|
template<class IntType>
|
|
void
|
|
X86Process::argsInit(int pageSize,
|
|
std::vector<gem5::auxv::AuxVector<IntType>> extraAuxvs)
|
|
{
|
|
int intSize = sizeof(IntType);
|
|
|
|
std::vector<gem5::auxv::AuxVector<IntType>> auxv = extraAuxvs;
|
|
|
|
std::string filename;
|
|
if (argv.size() < 1)
|
|
filename = "";
|
|
else
|
|
filename = argv[0];
|
|
|
|
// We want 16 byte alignment
|
|
uint64_t align = 16;
|
|
|
|
enum X86CpuFeature
|
|
{
|
|
X86_OnboardFPU = 1 << 0,
|
|
X86_VirtualModeExtensions = 1 << 1,
|
|
X86_DebuggingExtensions = 1 << 2,
|
|
X86_PageSizeExtensions = 1 << 3,
|
|
|
|
X86_TimeStampCounter = 1 << 4,
|
|
X86_ModelSpecificRegisters = 1 << 5,
|
|
X86_PhysicalAddressExtensions = 1 << 6,
|
|
X86_MachineCheckExtensions = 1 << 7,
|
|
|
|
X86_CMPXCHG8Instruction = 1 << 8,
|
|
X86_OnboardAPIC = 1 << 9,
|
|
X86_SYSENTER_SYSEXIT = 1 << 11,
|
|
|
|
X86_MemoryTypeRangeRegisters = 1 << 12,
|
|
X86_PageGlobalEnable = 1 << 13,
|
|
X86_MachineCheckArchitecture = 1 << 14,
|
|
X86_CMOVInstruction = 1 << 15,
|
|
|
|
X86_PageAttributeTable = 1 << 16,
|
|
X86_36BitPSEs = 1 << 17,
|
|
X86_ProcessorSerialNumber = 1 << 18,
|
|
X86_CLFLUSHInstruction = 1 << 19,
|
|
|
|
X86_DebugTraceStore = 1 << 21,
|
|
X86_ACPIViaMSR = 1 << 22,
|
|
X86_MultimediaExtensions = 1 << 23,
|
|
|
|
X86_FXSAVE_FXRSTOR = 1 << 24,
|
|
X86_StreamingSIMDExtensions = 1 << 25,
|
|
X86_StreamingSIMDExtensions2 = 1 << 26,
|
|
X86_CPUSelfSnoop = 1 << 27,
|
|
|
|
X86_HyperThreading = 1 << 28,
|
|
X86_AutomaticClockControl = 1 << 29,
|
|
X86_IA64Processor = 1 << 30
|
|
};
|
|
|
|
// Setup the auxiliary vectors. These will already have endian
|
|
// conversion. Auxiliary vectors are loaded only for elf formatted
|
|
// executables; the auxv is responsible for passing information from
|
|
// the OS to the interpreter.
|
|
auto *elfObject = dynamic_cast<loader::ElfObject *>(objFile);
|
|
if (elfObject) {
|
|
uint64_t features =
|
|
X86_OnboardFPU |
|
|
X86_VirtualModeExtensions |
|
|
X86_DebuggingExtensions |
|
|
X86_PageSizeExtensions |
|
|
X86_TimeStampCounter |
|
|
X86_ModelSpecificRegisters |
|
|
X86_PhysicalAddressExtensions |
|
|
X86_MachineCheckExtensions |
|
|
X86_CMPXCHG8Instruction |
|
|
X86_OnboardAPIC |
|
|
X86_SYSENTER_SYSEXIT |
|
|
X86_MemoryTypeRangeRegisters |
|
|
X86_PageGlobalEnable |
|
|
X86_MachineCheckArchitecture |
|
|
X86_CMOVInstruction |
|
|
X86_PageAttributeTable |
|
|
X86_36BitPSEs |
|
|
// X86_ProcessorSerialNumber |
|
|
X86_CLFLUSHInstruction |
|
|
// X86_DebugTraceStore |
|
|
// X86_ACPIViaMSR |
|
|
X86_MultimediaExtensions |
|
|
X86_FXSAVE_FXRSTOR |
|
|
X86_StreamingSIMDExtensions |
|
|
X86_StreamingSIMDExtensions2 |
|
|
// X86_CPUSelfSnoop |
|
|
// X86_HyperThreading |
|
|
// X86_AutomaticClockControl |
|
|
// X86_IA64Processor |
|
|
0;
|
|
|
|
// Bits which describe the system hardware capabilities
|
|
// XXX Figure out what these should be
|
|
auxv.emplace_back(gem5::auxv::Hwcap, features);
|
|
// The system page size
|
|
auxv.emplace_back(gem5::auxv::Pagesz, X86ISA::PageBytes);
|
|
// Frequency at which times() increments
|
|
// Defined to be 100 in the kernel source.
|
|
auxv.emplace_back(gem5::auxv::Clktck, 100);
|
|
// This is the virtual address of the program header tables if they
|
|
// appear in the executable image.
|
|
auxv.emplace_back(gem5::auxv::Phdr, elfObject->programHeaderTable());
|
|
// This is the size of a program header entry from the elf file.
|
|
auxv.emplace_back(gem5::auxv::Phent, elfObject->programHeaderSize());
|
|
// This is the number of program headers from the original elf file.
|
|
auxv.emplace_back(gem5::auxv::Phnum, elfObject->programHeaderCount());
|
|
// This is the base address of the ELF interpreter; it should be
|
|
// zero for static executables or contain the base address for
|
|
// dynamic executables.
|
|
auxv.emplace_back(gem5::auxv::Base, getBias());
|
|
// XXX Figure out what this should be.
|
|
auxv.emplace_back(gem5::auxv::Flags, 0);
|
|
// The entry point to the program
|
|
auxv.emplace_back(gem5::auxv::Entry, objFile->entryPoint());
|
|
// Different user and group IDs
|
|
auxv.emplace_back(gem5::auxv::Uid, uid());
|
|
auxv.emplace_back(gem5::auxv::Euid, euid());
|
|
auxv.emplace_back(gem5::auxv::Gid, gid());
|
|
auxv.emplace_back(gem5::auxv::Egid, egid());
|
|
// Whether to enable "secure mode" in the executable
|
|
auxv.emplace_back(gem5::auxv::Secure, 0);
|
|
// The address of 16 "random" bytes.
|
|
auxv.emplace_back(gem5::auxv::Random, 0);
|
|
// The name of the program
|
|
auxv.emplace_back(gem5::auxv::Execfn, 0);
|
|
// The platform string
|
|
auxv.emplace_back(gem5::auxv::Platform, 0);
|
|
}
|
|
|
|
// Figure out how big the initial stack needs to be
|
|
|
|
// A sentry NULL void pointer at the top of the stack.
|
|
int sentry_size = intSize;
|
|
|
|
// This is the name of the file which is present on the initial stack
|
|
// It's purpose is to let the user space linker examine the original file.
|
|
int file_name_size = filename.size() + 1;
|
|
|
|
const int numRandomBytes = 16;
|
|
int aux_data_size = numRandomBytes;
|
|
|
|
std::string platform = "x86_64";
|
|
aux_data_size += platform.size() + 1;
|
|
|
|
int env_data_size = 0;
|
|
for (int i = 0; i < envp.size(); ++i)
|
|
env_data_size += envp[i].size() + 1;
|
|
int arg_data_size = 0;
|
|
for (int i = 0; i < argv.size(); ++i)
|
|
arg_data_size += argv[i].size() + 1;
|
|
|
|
// The info_block needs to be padded so its size is a multiple of the
|
|
// alignment mask. Also, it appears that there needs to be at least some
|
|
// padding, so if the size is already a multiple, we need to increase it
|
|
// anyway.
|
|
int base_info_block_size =
|
|
sentry_size + file_name_size + env_data_size + arg_data_size;
|
|
|
|
int info_block_size = roundUp(base_info_block_size, align);
|
|
|
|
int info_block_padding = info_block_size - base_info_block_size;
|
|
|
|
// Each auxiliary vector is two 8 byte words
|
|
int aux_array_size = intSize * 2 * (auxv.size() + 1);
|
|
|
|
int envp_array_size = intSize * (envp.size() + 1);
|
|
int argv_array_size = intSize * (argv.size() + 1);
|
|
|
|
int argc_size = intSize;
|
|
|
|
// Figure out the size of the contents of the actual initial frame
|
|
int frame_size =
|
|
aux_array_size +
|
|
envp_array_size +
|
|
argv_array_size +
|
|
argc_size;
|
|
|
|
// There needs to be padding after the auxiliary vector data so that the
|
|
// very bottom of the stack is aligned properly.
|
|
int partial_size = frame_size + aux_data_size;
|
|
int aligned_partial_size = roundUp(partial_size, align);
|
|
int aux_padding = aligned_partial_size - partial_size;
|
|
|
|
int space_needed =
|
|
info_block_size +
|
|
aux_data_size +
|
|
aux_padding +
|
|
frame_size;
|
|
|
|
Addr stack_base = memState->getStackBase();
|
|
|
|
Addr stack_min = stack_base - space_needed;
|
|
stack_min = roundDown(stack_min, align);
|
|
|
|
unsigned stack_size = stack_base - stack_min;
|
|
stack_size = roundUp(stack_size, pageSize);
|
|
memState->setStackSize(stack_size);
|
|
|
|
// map memory
|
|
Addr stack_end = roundDown(stack_base - stack_size, pageSize);
|
|
|
|
DPRINTF(Stack, "Mapping the stack: 0x%x %dB\n", stack_end, stack_size);
|
|
memState->mapRegion(stack_end, stack_size, "stack");
|
|
|
|
// map out initial stack contents
|
|
IntType sentry_base = stack_base - sentry_size;
|
|
IntType file_name_base = sentry_base - file_name_size;
|
|
IntType env_data_base = file_name_base - env_data_size;
|
|
IntType arg_data_base = env_data_base - arg_data_size;
|
|
IntType aux_data_base = arg_data_base - info_block_padding - aux_data_size;
|
|
IntType auxv_array_base = aux_data_base - aux_array_size - aux_padding;
|
|
IntType envp_array_base = auxv_array_base - envp_array_size;
|
|
IntType argv_array_base = envp_array_base - argv_array_size;
|
|
IntType argc_base = argv_array_base - argc_size;
|
|
|
|
DPRINTF(Stack, "The addresses of items on the initial stack:\n");
|
|
DPRINTF(Stack, "0x%x - file name\n", file_name_base);
|
|
DPRINTF(Stack, "0x%x - env data\n", env_data_base);
|
|
DPRINTF(Stack, "0x%x - arg data\n", arg_data_base);
|
|
DPRINTF(Stack, "0x%x - aux data\n", aux_data_base);
|
|
DPRINTF(Stack, "0x%x - auxv array\n", auxv_array_base);
|
|
DPRINTF(Stack, "0x%x - envp array\n", envp_array_base);
|
|
DPRINTF(Stack, "0x%x - argv array\n", argv_array_base);
|
|
DPRINTF(Stack, "0x%x - argc \n", argc_base);
|
|
DPRINTF(Stack, "0x%x - stack min\n", stack_min);
|
|
|
|
// write contents to stack
|
|
|
|
// figure out argc
|
|
IntType argc = argv.size();
|
|
IntType guestArgc = htole(argc);
|
|
|
|
// Write out the sentry void *
|
|
IntType sentry_NULL = 0;
|
|
initVirtMem->writeBlob(sentry_base, &sentry_NULL, sentry_size);
|
|
|
|
// Write the file name
|
|
initVirtMem->writeString(file_name_base, filename.c_str());
|
|
|
|
// Fix up the aux vectors which point to data
|
|
assert(auxv[auxv.size() - 3].type == gem5::auxv::Random);
|
|
auxv[auxv.size() - 3].val = aux_data_base;
|
|
assert(auxv[auxv.size() - 2].type == gem5::auxv::Execfn);
|
|
auxv[auxv.size() - 2].val = argv_array_base;
|
|
assert(auxv[auxv.size() - 1].type == gem5::auxv::Platform);
|
|
auxv[auxv.size() - 1].val = aux_data_base + numRandomBytes;
|
|
|
|
|
|
// Copy the aux stuff
|
|
Addr auxv_array_end = auxv_array_base;
|
|
for (const auto &aux: auxv) {
|
|
initVirtMem->write(auxv_array_end, aux, ByteOrder::little);
|
|
auxv_array_end += sizeof(aux);
|
|
}
|
|
// Write out the terminating zeroed auxiliary vector
|
|
const gem5::auxv::AuxVector<uint64_t> zero(0, 0);
|
|
initVirtMem->write(auxv_array_end, zero);
|
|
auxv_array_end += sizeof(zero);
|
|
|
|
initVirtMem->writeString(aux_data_base, platform.c_str());
|
|
|
|
copyStringArray(envp, envp_array_base, env_data_base,
|
|
ByteOrder::little, *initVirtMem);
|
|
copyStringArray(argv, argv_array_base, arg_data_base,
|
|
ByteOrder::little, *initVirtMem);
|
|
|
|
initVirtMem->writeBlob(argc_base, &guestArgc, intSize);
|
|
|
|
ThreadContext *tc = system->threads[contextIds[0]];
|
|
// Set the stack pointer register
|
|
tc->setIntReg(INTREG_RSP, stack_min);
|
|
|
|
// There doesn't need to be any segment base added in since we're dealing
|
|
// with the flat segmentation model.
|
|
tc->pcState(getStartPC());
|
|
|
|
// Align the "stack_min" to a page boundary.
|
|
memState->setStackMin(roundDown(stack_min, pageSize));
|
|
}
|
|
|
|
void
|
|
X86_64Process::argsInit(int pageSize)
|
|
{
|
|
std::vector<gem5::auxv::AuxVector<uint64_t> > extraAuxvs;
|
|
extraAuxvs.emplace_back(auxv::SysinfoEhdr, vsyscallPage.base);
|
|
X86Process::argsInit<uint64_t>(pageSize, extraAuxvs);
|
|
}
|
|
|
|
void
|
|
I386Process::argsInit(int pageSize)
|
|
{
|
|
std::vector<gem5::auxv::AuxVector<uint32_t> > extraAuxvs;
|
|
//Tell the binary where the vsyscall part of the vsyscall page is.
|
|
extraAuxvs.emplace_back(auxv::Sysinfo,
|
|
vsyscallPage.base + vsyscallPage.vsyscallOffset);
|
|
extraAuxvs.emplace_back(auxv::SysinfoEhdr, vsyscallPage.base);
|
|
X86Process::argsInit<uint32_t>(pageSize, extraAuxvs);
|
|
}
|
|
|
|
void
|
|
X86_64Process::clone(ThreadContext *old_tc, ThreadContext *new_tc,
|
|
Process *p, RegVal flags)
|
|
{
|
|
X86Process::clone(old_tc, new_tc, p, flags);
|
|
((X86_64Process*)p)->vsyscallPage = vsyscallPage;
|
|
}
|
|
|
|
void
|
|
I386Process::clone(ThreadContext *old_tc, ThreadContext *new_tc,
|
|
Process *p, RegVal flags)
|
|
{
|
|
X86Process::clone(old_tc, new_tc, p, flags);
|
|
((I386Process*)p)->vsyscallPage = vsyscallPage;
|
|
}
|
|
|
|
} // namespace gem5
|