From 16e99e4677c24147e09ff10d375751a7b114a8d7 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Thu, 29 Nov 2007 00:00:02 -0800 Subject: SPARC: Combine the 64 and 32 bit process initialization code. Alignment is done as it was for 32 bit processes. --HG-- extra : convert_revision : 9368ad40dcc7911f8fc7ec1468c6a28aa92d196f --- src/arch/sparc/process.cc | 425 +++++++++------------------------------------- 1 file changed, 83 insertions(+), 342 deletions(-) (limited to 'src/arch/sparc/process.cc') diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc index 0c40fe58d..e1e7c24ad 100644 --- a/src/arch/sparc/process.cc +++ b/src/arch/sparc/process.cc @@ -48,8 +48,8 @@ using namespace SparcISA; SparcLiveProcess::SparcLiveProcess(LiveProcessParams * params, - ObjectFile *objFile) - : LiveProcess(params, objFile) + ObjectFile *objFile, Addr _StackBias) + : LiveProcess(params, objFile), StackBias(_StackBias) { // XXX all the below need to be updated for SPARC - Ali @@ -108,23 +108,17 @@ void SparcLiveProcess::handleTrap(int trapNum, ThreadContext *tc) } void -Sparc32LiveProcess::startup() +SparcLiveProcess::startup() { - if (checkpointRestored) - return; - - argsInit(32 / 8, VMPageSize); + Process::startup(); //From the SPARC ABI - //The process runs in user mode with 32 bit addresses - threadContexts[0]->setMiscReg(MISCREG_PSTATE, 0x0a); - //Setup default FP state threadContexts[0]->setMiscRegNoEffect(MISCREG_FSR, 0); threadContexts[0]->setMiscRegNoEffect(MISCREG_TICK, 0); - // + /* * Register window management registers */ @@ -159,73 +153,42 @@ Sparc32LiveProcess::startup() } void -Sparc64LiveProcess::startup() +Sparc32LiveProcess::startup() { if (checkpointRestored) return; - argsInit(sizeof(IntReg), VMPageSize); - - //From the SPARC ABI + SparcLiveProcess::startup(); - //The process runs in user mode - threadContexts[0]->setMiscReg(MISCREG_PSTATE, 0x02); + //The process runs in user mode with 32 bit addresses + threadContexts[0]->setMiscReg(MISCREG_PSTATE, 0x0a); - //Setup default FP state - threadContexts[0]->setMiscRegNoEffect(MISCREG_FSR, 0); + argsInit(32 / 8, VMPageSize); +} - threadContexts[0]->setMiscRegNoEffect(MISCREG_TICK, 0); +void +Sparc64LiveProcess::startup() +{ + if (checkpointRestored) + return; - /* - * Register window management registers - */ + SparcLiveProcess::startup(); - //No windows contain info from other programs - //threadContexts[0]->setMiscRegNoEffect(MISCREG_OTHERWIN, 0); - threadContexts[0]->setIntReg(NumIntArchRegs + 6, 0); - //There are no windows to pop - //threadContexts[0]->setMiscRegNoEffect(MISCREG_CANRESTORE, 0); - threadContexts[0]->setIntReg(NumIntArchRegs + 4, 0); - //All windows are available to save into - //threadContexts[0]->setMiscRegNoEffect(MISCREG_CANSAVE, NWindows - 2); - threadContexts[0]->setIntReg(NumIntArchRegs + 3, NWindows - 2); - //All windows are "clean" - //threadContexts[0]->setMiscRegNoEffect(MISCREG_CLEANWIN, NWindows); - threadContexts[0]->setIntReg(NumIntArchRegs + 5, NWindows); - //Start with register window 0 - threadContexts[0]->setMiscRegNoEffect(MISCREG_CWP, 0); - //Always use spill and fill traps 0 - //threadContexts[0]->setMiscRegNoEffect(MISCREG_WSTATE, 0); - threadContexts[0]->setIntReg(NumIntArchRegs + 7, 0); - //Set the trap level to 0 - threadContexts[0]->setMiscRegNoEffect(MISCREG_TL, 0); - //Set the ASI register to something fixed - threadContexts[0]->setMiscRegNoEffect(MISCREG_ASI, ASI_PRIMARY); + //The process runs in user mode + threadContexts[0]->setMiscReg(MISCREG_PSTATE, 0x02); - /* - * T1 specific registers - */ - //Turn on the icache, dcache, dtb translation, and itb translation. - threadContexts[0]->setMiscRegNoEffect(MISCREG_MMU_LSU_CTRL, 15); + argsInit(sizeof(IntReg), VMPageSize); } -M5_32_auxv_t::M5_32_auxv_t(int32_t type, int32_t val) +template +void +SparcLiveProcess::argsInit(int pageSize) { - a_type = TheISA::htog(type); - a_val = TheISA::htog(val); -} + int intSize = sizeof(IntType); -M5_64_auxv_t::M5_64_auxv_t(int64_t type, int64_t val) -{ - a_type = TheISA::htog(type); - a_val = TheISA::htog(val); -} + typedef M5_auxv_t auxv_t; -void -Sparc64LiveProcess::argsInit(int intSize, int pageSize) -{ - typedef M5_64_auxv_t auxv_t; - Process::startup(); + std::vector auxv; string filename; if(argv.size() < 1) @@ -233,7 +196,9 @@ Sparc64LiveProcess::argsInit(int intSize, int pageSize) else filename = argv[0]; - Addr alignmentMask = ~(intSize - 1); + //Even for a 32 bit process, the ABI says we still need to + //maintain double word alignment of the stack pointer. + Addr alignmentMask = ~(sizeof(uint64_t) - 1); // load object file into target memory objFile->loadSections(initVirtMem); @@ -259,7 +224,6 @@ Sparc64LiveProcess::argsInit(int intSize, int pageSize) M5_HWCAP_SPARC_V9 | M5_HWCAP_SPARC_ULTRA3; - //Setup the auxilliary vectors. These will already have endian conversion. //Auxilliary vectors are loaded only for elf formatted executables. ElfObject * elfObject = dynamic_cast(objFile); @@ -298,250 +262,6 @@ Sparc64LiveProcess::argsInit(int intSize, int pageSize) //Figure out how big the initial stack needs to be - // The unaccounted for 0 at the top of the stack - int mysterious_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; - - 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 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 + - env_data_size + - arg_data_size + - intSize) & alignmentMask; - - int info_block_padding = - info_block_size - - file_name_size - - env_data_size - - arg_data_size; - - //Each auxilliary 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; - int window_save_size = intSize * 16; - - int space_needed = - mysterious_size + - info_block_size + - aux_array_size + - envp_array_size + - argv_array_size + - argc_size + - window_save_size; - - stack_min = stack_base - space_needed; - stack_min &= alignmentMask; - stack_size = stack_base - stack_min; - - // map memory - pTable->allocate(roundDown(stack_min, pageSize), - roundUp(stack_size, pageSize)); - - // map out initial stack contents - Addr mysterious_base = stack_base - mysterious_size; - 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 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; -#ifndef NDEBUG - // only used in DPRINTF - Addr window_save_base = argc_base - window_save_size; -#endif - - DPRINTF(Sparc, "The addresses of items on the initial stack:\n"); - DPRINTF(Sparc, "0x%x - file name\n", file_name_base); - DPRINTF(Sparc, "0x%x - env data\n", env_data_base); - DPRINTF(Sparc, "0x%x - arg data\n", arg_data_base); - DPRINTF(Sparc, "0x%x - auxv array\n", auxv_array_base); - DPRINTF(Sparc, "0x%x - envp array\n", envp_array_base); - DPRINTF(Sparc, "0x%x - argv array\n", argv_array_base); - DPRINTF(Sparc, "0x%x - argc \n", argc_base); - DPRINTF(Sparc, "0x%x - window save\n", window_save_base); - DPRINTF(Sparc, "0x%x - stack min\n", stack_min); - - // write contents to stack - - // figure out argc - uint64_t argc = argv.size(); - uint64_t guestArgc = TheISA::htog(argc); - - //Write out the mysterious 0 - uint64_t mysterious_zero = 0; - initVirtMem->writeBlob(mysterious_base, - (uint8_t*)&mysterious_zero, mysterious_size); - - //Write the file name - initVirtMem->writeString(file_name_base, filename.c_str()); - - //Copy the aux stuff - for(int x = 0; x < auxv.size(); x++) - { - initVirtMem->writeBlob(auxv_array_base + x * 2 * intSize, - (uint8_t*)&(auxv[x].a_type), intSize); - initVirtMem->writeBlob(auxv_array_base + (x * 2 + 1) * intSize, - (uint8_t*)&(auxv[x].a_val), intSize); - } - //Write out the terminating zeroed auxilliary vector - const uint64_t zero = 0; - initVirtMem->writeBlob(auxv_array_base + 2 * intSize * auxv.size(), - (uint8_t*)&zero, 2 * intSize); - - 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); - - //Stuff the trap handlers into the processes address space. - //Since the stack grows down and is the highest area in the processes - //address space, we can put stuff above it and stay out of the way. - int fillSize = sizeof(MachInst) * numFillInsts; - int spillSize = sizeof(MachInst) * numSpillInsts; - fillStart = stack_base; - spillStart = fillStart + fillSize; - initVirtMem->writeBlob(fillStart, (uint8_t*)fillHandler64, fillSize); - initVirtMem->writeBlob(spillStart, (uint8_t*)spillHandler64, spillSize); - - //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 - 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)); - threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst))); - - //Align the "stack_min" to a page boundary. - stack_min = roundDown(stack_min, pageSize); - -// num_processes++; -} - -void -Sparc32LiveProcess::argsInit(int intSize, int pageSize) -{ - typedef M5_32_auxv_t auxv_t; - Process::startup(); - - string filename; - if(argv.size() < 1) - filename = ""; - else - filename = argv[0]; - - //Even though this is a 32 bit process, the ABI says we still need to - //maintain double word alignment of the stack pointer. - Addr alignmentMask = ~(8 - 1); - - // 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, - M5_HWCAP_SPARC_STBAR = 2, - M5_HWCAP_SPARC_SWAP = 4, - M5_HWCAP_SPARC_MULDIV = 8, - M5_HWCAP_SPARC_V9 = 16, - //This one should technically only be set - //if there is a cheetah or cheetah_plus tlb, - //but we'll use it all the time - M5_HWCAP_SPARC_ULTRA3 = 32 - }; - - const int64_t hwcap = - M5_HWCAP_SPARC_FLUSH | - M5_HWCAP_SPARC_STBAR | - M5_HWCAP_SPARC_SWAP | - M5_HWCAP_SPARC_MULDIV | - M5_HWCAP_SPARC_V9 | - M5_HWCAP_SPARC_ULTRA3; - - - //Setup the auxilliary vectors. These will already have endian conversion. - //Auxilliary vectors are loaded only for elf formatted executables. - ElfObject * elfObject = dynamic_cast(objFile); - if(elfObject) - { - //Bits which describe the system hardware capabilities - auxv.push_back(auxv_t(SPARC_AT_HWCAP, hwcap)); - //The system page size - auxv.push_back(auxv_t(SPARC_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)); - // 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())); - // This is the size of a program header entry from the elf file. - auxv.push_back(auxv_t(SPARC_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())); - //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)); - //The entry point to the program - auxv.push_back(auxv_t(SPARC_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())); - //Whether to enable "secure mode" in the executable - auxv.push_back(auxv_t(SPARC_AT_SECURE, 0)); - } - - //Figure out how big the initial stack needs to be - // The unaccounted for 8 byte 0 at the top of the stack int mysterious_size = 8; @@ -565,7 +285,7 @@ Sparc32LiveProcess::argsInit(int intSize, int pageSize) env_data_size + arg_data_size + intSize); - //Each auxilliary vector is two 4 byte words + //Each auxilliary vector is two words int aux_array_size = intSize * 2 * (auxv.size() + 1); int envp_array_size = intSize * (envp.size() + 1); @@ -586,39 +306,39 @@ Sparc32LiveProcess::argsInit(int intSize, int pageSize) stack_min &= alignmentMask; stack_size = stack_base - stack_min; - // map memory + // Allocate space for the stack pTable->allocate(roundDown(stack_min, pageSize), roundUp(stack_size, pageSize)); // map out initial stack contents - uint32_t window_save_base = stack_min; - uint32_t argc_base = window_save_base + window_save_size; - uint32_t argv_array_base = argc_base + argc_size; - uint32_t envp_array_base = argv_array_base + argv_array_size; - uint32_t auxv_array_base = envp_array_base + envp_array_size; + IntType window_save_base = stack_min; + IntType argc_base = window_save_base + window_save_size; + IntType argv_array_base = argc_base + argc_size; + IntType envp_array_base = argv_array_base + argv_array_size; + IntType auxv_array_base = envp_array_base + envp_array_size; //The info block is pushed up against the top of the stack, while //the rest of the initial stack frame is aligned to an 8 byte boudary. - uint32_t arg_data_base = stack_base - info_block_size + intSize; - uint32_t env_data_base = arg_data_base + arg_data_size; - uint32_t file_name_base = env_data_base + env_data_size; - uint32_t mysterious_base = file_name_base + file_name_size; + IntType arg_data_base = stack_base - info_block_size + intSize; + IntType env_data_base = arg_data_base + arg_data_size; + IntType file_name_base = env_data_base + env_data_size; + IntType mysterious_base = file_name_base + file_name_size; DPRINTF(Sparc, "The addresses of items on the initial stack:\n"); - DPRINTF(Sparc, "0x%x - file name\n", file_name_base); - DPRINTF(Sparc, "0x%x - env data\n", env_data_base); - DPRINTF(Sparc, "0x%x - arg data\n", arg_data_base); - DPRINTF(Sparc, "0x%x - auxv array\n", auxv_array_base); - DPRINTF(Sparc, "0x%x - envp array\n", envp_array_base); - DPRINTF(Sparc, "0x%x - argv array\n", argv_array_base); - DPRINTF(Sparc, "0x%x - argc \n", argc_base); - DPRINTF(Sparc, "0x%x - window save\n", window_save_base); - DPRINTF(Sparc, "0x%x - stack min\n", stack_min); + DPRINTF(Sparc, "%#x - file name\n", file_name_base); + DPRINTF(Sparc, "%#x - env data\n", env_data_base); + DPRINTF(Sparc, "%#x - arg data\n", arg_data_base); + DPRINTF(Sparc, "%#x - auxv array\n", auxv_array_base); + DPRINTF(Sparc, "%#x - envp array\n", envp_array_base); + DPRINTF(Sparc, "%#x - argv array\n", argv_array_base); + DPRINTF(Sparc, "%#x - argc \n", argc_base); + DPRINTF(Sparc, "%#x - window save\n", window_save_base); + DPRINTF(Sparc, "%#x - stack min\n", stack_min); // write contents to stack // figure out argc - uint32_t argc = argv.size(); - uint32_t guestArgc = TheISA::htog(argc); + IntType argc = argv.size(); + IntType guestArgc = TheISA::htog(argc); //Write out the mysterious 0 uint64_t mysterious_zero = 0; @@ -636,8 +356,9 @@ Sparc32LiveProcess::argsInit(int intSize, int pageSize) initVirtMem->writeBlob(auxv_array_base + (x * 2 + 1) * intSize, (uint8_t*)&(auxv[x].a_val), intSize); } + //Write out the terminating zeroed auxilliary vector - const uint64_t zero = 0; + const IntType zero = 0; initVirtMem->writeBlob(auxv_array_base + 2 * intSize * auxv.size(), (uint8_t*)&zero, 2 * intSize); @@ -646,27 +367,23 @@ Sparc32LiveProcess::argsInit(int intSize, int pageSize) initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize); - //Stuff the trap handlers into the processes address space. - //Since the stack grows down and is the highest area in the processes - //address space, we can put stuff above it and stay out of the way. - int fillSize = sizeof(MachInst) * numFillInsts; - int spillSize = sizeof(MachInst) * numSpillInsts; + //Set up space for the trap handlers into the processes address space. + //Since the stack grows down and there is reserved address space abov + //it, we can put stuff above it and stay out of the way. fillStart = stack_base; - spillStart = fillStart + fillSize; - initVirtMem->writeBlob(fillStart, (uint8_t*)fillHandler32, fillSize); - initVirtMem->writeBlob(spillStart, (uint8_t*)spillHandler32, spillSize); + spillStart = fillStart + sizeof(MachInst) * numFillInsts; //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); + 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); - uint32_t prog_entry = objFile->entryPoint(); + Addr prog_entry = objFile->entryPoint(); threadContexts[0]->setPC(prog_entry); threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst)); threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst))); @@ -677,6 +394,30 @@ Sparc32LiveProcess::argsInit(int intSize, int pageSize) // num_processes++; } +void +Sparc64LiveProcess::argsInit(int intSize, int pageSize) +{ + SparcLiveProcess::argsInit(pageSize); + + // Stuff the trap handlers into the process address space + initVirtMem->writeBlob(fillStart, + (uint8_t*)fillHandler64, sizeof(MachInst) * numFillInsts); + initVirtMem->writeBlob(spillStart, + (uint8_t*)spillHandler64, sizeof(MachInst) * numSpillInsts); +} + +void +Sparc32LiveProcess::argsInit(int intSize, int pageSize) +{ + SparcLiveProcess::argsInit(pageSize); + + // Stuff the trap handlers into the process address space + initVirtMem->writeBlob(fillStart, + (uint8_t*)fillHandler32, sizeof(MachInst) * numFillInsts); + initVirtMem->writeBlob(spillStart, + (uint8_t*)spillHandler32, sizeof(MachInst) * numSpillInsts); +} + void Sparc32LiveProcess::flushWindows(ThreadContext *tc) { IntReg Cansave = tc->readIntReg(NumIntArchRegs + 3); -- cgit v1.2.3