X86: Initial stack frame fixes and constant shuffling.
authorGabe Black <gblack@eecs.umich.edu>
Sun, 29 Jul 2007 08:33:06 +0000 (01:33 -0700)
committerGabe Black <gblack@eecs.umich.edu>
Sun, 29 Jul 2007 08:33:06 +0000 (01:33 -0700)
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/sparc/process.cc
src/arch/x86/process.cc
src/sim/process.hh

index bc950301a143d9bd6db644ebe684af20681cb417..41a1c21360e762a0fbb7bff461178e20e1015408 100644 (file)
@@ -194,25 +194,6 @@ Sparc64LiveProcess::argsInit(int intSize, int pageSize)
     // load object file into target memory
     objFile->loadSections(initVirtMem);
 
-    //These are the auxilliary vector types
-    enum auxTypes
-    {
-        SPARC_AT_HWCAP = 16,
-        SPARC_AT_PAGESZ = 6,
-        SPARC_AT_CLKTCK = 17,
-        SPARC_AT_PHDR = 3,
-        SPARC_AT_PHENT = 4,
-        SPARC_AT_PHNUM = 5,
-        SPARC_AT_BASE = 7,
-        SPARC_AT_FLAGS = 8,
-        SPARC_AT_ENTRY = 9,
-        SPARC_AT_UID = 11,
-        SPARC_AT_EUID = 12,
-        SPARC_AT_GID = 13,
-        SPARC_AT_EGID = 14,
-        SPARC_AT_SECURE = 23
-    };
-
     enum hardwareCaps
     {
         M5_HWCAP_SPARC_FLUSH = 1,
@@ -241,34 +222,34 @@ Sparc64LiveProcess::argsInit(int intSize, int pageSize)
     if(elfObject)
     {
         //Bits which describe the system hardware capabilities
-        auxv.push_back(auxv_t(SPARC_AT_HWCAP, hwcap));
+        auxv.push_back(auxv_t(M5_AT_HWCAP, hwcap));
         //The system page size
-        auxv.push_back(auxv_t(SPARC_AT_PAGESZ, SparcISA::VMPageSize));
+        auxv.push_back(auxv_t(M5_AT_PAGESZ, SparcISA::VMPageSize));
         //Defined to be 100 in the kernel source.
         //Frequency at which times() increments
-        auxv.push_back(auxv_t(SPARC_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(SPARC_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(SPARC_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(SPARC_AT_PHNUM, elfObject->programHeaderCount()));
+        auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
         //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));
+        auxv.push_back(auxv_t(M5_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(M5_AT_FLAGS, 0));
         //The entry point to the program
-        auxv.push_back(auxv_t(SPARC_AT_ENTRY, objFile->entryPoint()));
+        auxv.push_back(auxv_t(M5_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(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(SPARC_AT_SECURE, 0));
+        auxv.push_back(auxv_t(M5_AT_SECURE, 0));
     }
 
     //Figure out how big the initial stack needs to be
index ff23be33966b6c868d2c4a4630ea1ecf07f21753..6d30e53e3db5fa79396632803ee662d63bdb452c 100644 (file)
@@ -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<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.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();
index fa46b9c952e2d466cd110a94afa03f3915e8adbc..8c702da60b94b405ce600954a722a16bbc4da115 100644 (file)
@@ -214,6 +214,32 @@ class LiveProcess : public Process
 
   public:
 
+    enum AuxiliaryVectorType {
+        M5_AT_NULL = 0,
+        M5_AT_IGNORE = 1,
+        M5_AT_EXECFD = 2,
+        M5_AT_PHDR = 3,
+        M5_AT_PHENT = 4,
+        M5_AT_PHNUM = 5,
+        M5_AT_PAGESZ = 6,
+        M5_AT_BASE = 7,
+        M5_AT_FLAGS = 8,
+        M5_AT_ENTRY = 9,
+        M5_AT_NOTELF = 10,
+        M5_AT_UID = 11,
+        M5_AT_EUID = 12,
+        M5_AT_GID = 13,
+        M5_AT_EGID = 14,
+        // The following may be specific to Linux
+        M5_AT_PLATFORM = 15,
+        M5_AT_HWCAP = 16,
+        M5_AT_CLKTCK = 17,
+
+        M5_AT_SECURE = 23,
+
+        M5_AT_VECTOR_SIZE = 44
+    };
+
     inline uint64_t uid() {return __uid;}
     inline uint64_t euid() {return __euid;}
     inline uint64_t gid() {return __gid;}