From e996ff74978c09eda4903dc491ed5261b5def789 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 28 Jul 2007 20:33:42 -0700 Subject: X86: Fix up auxiliary vectors. The type constants should go into an architecture independent spot since they are universal to all Linux elf binaries. The right value for some of the vectors needs to be determined. Also, x86 does not store argc or argv_array_base in registers like some other architectures. --HG-- extra : convert_revision : 8d3f6a3e028d881d3c41e8ddf4f29d25738b529c --- src/arch/x86/process.cc | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) (limited to 'src/arch/x86/process.cc') diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc index 09962fdb6..713e5d0a2 100644 --- a/src/arch/x86/process.cc +++ b/src/arch/x86/process.cc @@ -187,7 +187,14 @@ X86LiveProcess::argsInit(int intSize, int pageSize) X86_AT_UID = 11, X86_AT_EUID = 12, X86_AT_GID = 13, - X86_AT_EGID = 14 + X86_AT_EGID = 14, + X86_AT_PLATFORM = 15, + X86_AT_HWCAP = 16, + X86_AT_CLKTCK = 17, + + X86_AT_SECURE = 13, + + X86_AT_VECTOR_SIZE = 44 }; //Setup the auxilliary vectors. These will already have endian conversion. @@ -195,36 +202,39 @@ X86LiveProcess::argsInit(int intSize, int pageSize) ElfObject * elfObject = dynamic_cast(objFile); if(elfObject) { - /* //Bits which describe the system hardware capabilities - auxv.push_back(auxv_t(SPARC_AT_HWCAP, hwcap)); + //XXX Figure out what these should be + auxv.push_back(auxv_t(X86_AT_HWCAP, 0)); //The system page size - auxv.push_back(auxv_t(SPARC_AT_PAGESZ, SparcISA::VMPageSize)); - //Defined to be 100 in the kernel source. + auxv.push_back(auxv_t(X86_AT_PAGESZ, X86ISA::VMPageSize)); //Frequency at which times() increments - auxv.push_back(auxv_t(SPARC_AT_CLKTCK, 100)); + auxv.push_back(auxv_t(X86_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(SPARC_AT_PHDR, elfObject->programHeaderTable())); + auxv.push_back(auxv_t(X86_AT_PHDR, elfObject->programHeaderTable())); // This is the size of a program header entry from the elf file. - auxv.push_back(auxv_t(SPARC_AT_PHENT, elfObject->programHeaderSize())); + auxv.push_back(auxv_t(X86_AT_PHENT, elfObject->programHeaderSize())); // This is the number of program headers from the original elf file. - auxv.push_back(auxv_t(SPARC_AT_PHNUM, elfObject->programHeaderCount())); + auxv.push_back(auxv_t(X86_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. - auxv.push_back(auxv_t(SPARC_AT_BASE, 0)); - //This is hardwired to 0 in the elf loading code in the kernel - auxv.push_back(auxv_t(SPARC_AT_FLAGS, 0)); + auxv.push_back(auxv_t(X86_AT_BASE, 0)); + + //XXX Figure out what this should be. + auxv.push_back(auxv_t(X86_AT_FLAGS, 0)); //The entry point to the program - auxv.push_back(auxv_t(SPARC_AT_ENTRY, objFile->entryPoint())); + auxv.push_back(auxv_t(X86_AT_ENTRY, objFile->entryPoint())); //Different user and group IDs - auxv.push_back(auxv_t(SPARC_AT_UID, uid())); - auxv.push_back(auxv_t(SPARC_AT_EUID, euid())); - auxv.push_back(auxv_t(SPARC_AT_GID, gid())); - auxv.push_back(auxv_t(SPARC_AT_EGID, egid())); + auxv.push_back(auxv_t(X86_AT_UID, uid())); + auxv.push_back(auxv_t(X86_AT_EUID, euid())); + auxv.push_back(auxv_t(X86_AT_GID, gid())); + auxv.push_back(auxv_t(X86_AT_EGID, egid())); //Whether to enable "secure mode" in the executable - auxv.push_back(auxv_t(SPARC_AT_SECURE, 0));*/ + auxv.push_back(auxv_t(X86_AT_SECURE, 0)); + //The string "x86_64" with unknown meaning + auxv.push_back(auxv_t(X86_AT_PLATFORM, 0)); } //Figure out how big the initial stack needs to be @@ -338,9 +348,6 @@ X86LiveProcess::argsInit(int intSize, int pageSize) initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize); //Set up the thread context to start running the process - assert(NumArgumentRegs >= 2); - threadContexts[0]->setIntReg(ArgumentReg[0], argc); - threadContexts[0]->setIntReg(ArgumentReg[1], argv_array_base); threadContexts[0]->setIntReg(StackPointerReg, stack_min); Addr prog_entry = objFile->entryPoint(); -- cgit v1.2.3 From dc86f3229c2d3278bf5f32fb9b0b4bf039c0735e Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sat, 28 Jul 2007 21:18:53 -0700 Subject: X86: Fix a comment and adjust the stack base address. The stack base on my development machine starts one page below where it needs to. I don't know why it does, but I've duplicated it in m5. --HG-- extra : convert_revision : c4783ba885b90f17e843f61e07af0bc3330a74bc --- src/arch/x86/process.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/arch/x86/process.cc') diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc index 713e5d0a2..ff23be339 100644 --- a/src/arch/x86/process.cc +++ b/src/arch/x86/process.cc @@ -122,9 +122,10 @@ X86LiveProcess::X86LiveProcess(const std::string &nm, ObjectFile *objFile, // Set pointer for next thread stack. Reserve 8M for main stack. next_thread_stack_base = stack_base - (8 * 1024 * 1024); - // Set up stack. On SPARC Linux, stack goes from the top of memory - // downward, less the hole for the kernel address space. - stack_base = (Addr)0x80000000000ULL; + // Set up stack. On X86_64 Linux, stack goes from the top of memory + // downward, less the hole for the kernel address space plus one page + // for undertermined purposes. + stack_base = (Addr)0x7FFFFFFF000ULL; // Set up region for mmaps. Tru64 seems to start just above 0 and // grow up from there. -- cgit v1.2.3 From 5e34c62b3b3f54c826730841029a875607824c42 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 29 Jul 2007 01:33:06 -0700 Subject: X86: Initial stack frame fixes and constant shuffling. The initial stack frame for x86 is now substantially more correct. The fixes made here can be back ported to SPARC and possible the other ISAs as well. The auxiliary vector types were moved to the LiveProcess base class because they are independent of ISA. Some of the types may only apply to Linux, though, so they may have to be moved. --HG-- extra : convert_revision : 89ace35fcc8eb9586d2fee8eeccbc3686499ef24 --- src/arch/x86/process.cc | 167 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 118 insertions(+), 49 deletions(-) (limited to 'src/arch/x86/process.cc') diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc index ff23be339..6d30e53e3 100644 --- a/src/arch/x86/process.cc +++ b/src/arch/x86/process.cc @@ -125,7 +125,7 @@ X86LiveProcess::X86LiveProcess(const std::string &nm, ObjectFile *objFile, // Set up stack. On X86_64 Linux, stack goes from the top of memory // downward, less the hole for the kernel address space plus one page // for undertermined purposes. - stack_base = (Addr)0x7FFFFFFF000ULL; + stack_base = (Addr)0x7FFFFFFFF000ULL; // Set up region for mmaps. Tru64 seems to start just above 0 and // grow up from there. @@ -166,36 +166,49 @@ X86LiveProcess::argsInit(int intSize, int pageSize) else filename = argv[0]; - Addr alignmentMask = ~(intSize - 1); + //We want 16 byte alignment + Addr alignmentMask = ~mask(4); // load object file into target memory objFile->loadSections(initVirtMem); - //These are the auxilliary vector types - enum auxTypes - { - X86_AT_NULL = 0, - X86_AT_IGNORE = 1, - X86_AT_EXECFD = 2, - X86_AT_PHDR = 3, - X86_AT_PHENT = 4, - X86_AT_PHNUM = 5, - X86_AT_PAGESZ = 6, - X86_AT_BASE = 7, - X86_AT_FLAGS = 8, - X86_AT_ENTRY = 9, - X86_AT_NOTELF = 10, - X86_AT_UID = 11, - X86_AT_EUID = 12, - X86_AT_GID = 13, - X86_AT_EGID = 14, - X86_AT_PLATFORM = 15, - X86_AT_HWCAP = 16, - X86_AT_CLKTCK = 17, - - X86_AT_SECURE = 13, - - X86_AT_VECTOR_SIZE = 44 + 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 auxilliary vectors. These will already have endian conversion. @@ -203,39 +216,71 @@ X86LiveProcess::argsInit(int intSize, int pageSize) ElfObject * elfObject = dynamic_cast(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.push_back(auxv_t(X86_AT_HWCAP, 0)); + auxv.push_back(auxv_t(M5_AT_HWCAP, features)); //The system page size - auxv.push_back(auxv_t(X86_AT_PAGESZ, X86ISA::VMPageSize)); + auxv.push_back(auxv_t(M5_AT_PAGESZ, X86ISA::VMPageSize)); //Frequency at which times() increments - auxv.push_back(auxv_t(X86_AT_CLKTCK, 100)); + 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(X86_AT_PHDR, elfObject->programHeaderTable())); + auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable())); // This is the size of a program header entry from the elf file. - auxv.push_back(auxv_t(X86_AT_PHENT, elfObject->programHeaderSize())); + 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(X86_AT_PHNUM, elfObject->programHeaderCount())); + 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. - auxv.push_back(auxv_t(X86_AT_BASE, 0)); + auxv.push_back(auxv_t(M5_AT_BASE, 0)); //XXX Figure out what this should be. - auxv.push_back(auxv_t(X86_AT_FLAGS, 0)); + auxv.push_back(auxv_t(M5_AT_FLAGS, 0)); //The entry point to the program - auxv.push_back(auxv_t(X86_AT_ENTRY, objFile->entryPoint())); + auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint())); //Different user and group IDs - auxv.push_back(auxv_t(X86_AT_UID, uid())); - auxv.push_back(auxv_t(X86_AT_EUID, euid())); - auxv.push_back(auxv_t(X86_AT_GID, gid())); - auxv.push_back(auxv_t(X86_AT_EGID, egid())); + auxv.push_back(auxv_t(M5_AT_UID, uid())); + auxv.push_back(auxv_t(M5_AT_EUID, euid())); + auxv.push_back(auxv_t(M5_AT_GID, gid())); + auxv.push_back(auxv_t(M5_AT_EGID, egid())); //Whether to enable "secure mode" in the executable - auxv.push_back(auxv_t(X86_AT_SECURE, 0)); + auxv.push_back(auxv_t(M5_AT_SECURE, 0)); //The string "x86_64" with unknown meaning - auxv.push_back(auxv_t(X86_AT_PLATFORM, 0)); + auxv.push_back(auxv_t(M5_AT_PLATFORM, 0)); } //Figure out how big the initial stack needs to be @@ -245,29 +290,39 @@ X86LiveProcess::argsInit(int intSize, int pageSize) //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; + int file_name_size = filename.size(); + + string platform = "x86_64"; + int 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; + env_data_size += envp[i].size(); } int arg_data_size = 0; for (int i = 0; i < argv.size(); ++i) { - arg_data_size += argv[i].size() + 1; + arg_data_size += argv[i].size(); } + //The auxiliary vector data needs to be padded so it's size is a multiple + //of the alignment mask. + int aux_padding = + ((aux_data_size + ~alignmentMask) & alignmentMask) - aux_data_size; + //The info_block needs to be padded so it's 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 info_block_size = - (file_name_size + + (mysterious_size + + file_name_size + env_data_size + arg_data_size + - intSize) & alignmentMask; + ~alignmentMask) & alignmentMask; int info_block_padding = info_block_size - + mysterious_size - file_name_size - env_data_size - arg_data_size; @@ -281,8 +336,9 @@ X86LiveProcess::argsInit(int intSize, int pageSize) int argc_size = intSize; int space_needed = - mysterious_size + info_block_size + + aux_data_size + + aux_padding + aux_array_size + envp_array_size + argv_array_size + @@ -301,7 +357,8 @@ X86LiveProcess::argsInit(int intSize, int pageSize) Addr file_name_base = mysterious_base - file_name_size; Addr env_data_base = file_name_base - env_data_size; Addr arg_data_base = env_data_base - arg_data_size; - Addr auxv_array_base = arg_data_base - aux_array_size - info_block_padding; + Addr aux_data_base = arg_data_base - aux_data_size - info_block_padding; + Addr auxv_array_base = aux_data_base - aux_array_size - aux_padding; Addr envp_array_base = auxv_array_base - envp_array_size; Addr argv_array_base = envp_array_base - argv_array_size; Addr argc_base = argv_array_base - argc_size; @@ -310,6 +367,7 @@ X86LiveProcess::argsInit(int intSize, int pageSize) DPRINTF(X86, "0x%x - file name\n", file_name_base); DPRINTF(X86, "0x%x - env data\n", env_data_base); DPRINTF(X86, "0x%x - arg data\n", arg_data_base); + DPRINTF(X86, "0x%x - aux data\n", aux_data_base); DPRINTF(X86, "0x%x - auxv array\n", auxv_array_base); DPRINTF(X86, "0x%x - envp array\n", envp_array_base); DPRINTF(X86, "0x%x - argv array\n", argv_array_base); @@ -330,6 +388,10 @@ X86LiveProcess::argsInit(int intSize, int pageSize) //Write the file name initVirtMem->writeString(file_name_base, filename.c_str()); + //Fix up the aux vector which points to the "platform" string + assert(auxv[auxv.size() - 1].a_type = M5_AT_PLATFORM); + auxv[auxv.size() - 1].a_val = aux_data_base; + //Copy the aux stuff for(int x = 0; x < auxv.size(); x++) { @@ -343,12 +405,19 @@ X86LiveProcess::argsInit(int intSize, int pageSize) initVirtMem->writeBlob(auxv_array_base + 2 * intSize * auxv.size(), (uint8_t*)&zero, 2 * intSize); + initVirtMem->writeString(aux_data_base, platform.c_str()); + copyStringArray(envp, envp_array_base, env_data_base, initVirtMem); copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem); initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize); //Set up the thread context to start running the process + //Because of the peculiarities of how syscall works, I believe + //a process starts with r11 containing the value of eflags or maybe r11 + //from before the call to execve. Empirically this value is 0x200. + threadContexts[0]->setIntReg(INTREG_R11, 0x200); + //Set the stack pointer register threadContexts[0]->setIntReg(StackPointerReg, stack_min); Addr prog_entry = objFile->entryPoint(); -- cgit v1.2.3