process.cc revision 11793
1793SN/A/* 211193SN/A * Copyright (c) 2003-2004 The Regents of The University of Michigan 39957SN/A * All rights reserved. 49957SN/A * 59957SN/A * Redistribution and use in source and binary forms, with or without 69957SN/A * modification, are permitted provided that the following conditions are 79957SN/A * met: redistributions of source code must retain the above copyright 89957SN/A * notice, this list of conditions and the following disclaimer; 99957SN/A * redistributions in binary form must reproduce the above copyright 109957SN/A * notice, this list of conditions and the following disclaimer in the 119957SN/A * documentation and/or other materials provided with the distribution; 129957SN/A * neither the name of the copyright holders nor the names of its 139957SN/A * contributors may be used to endorse or promote products derived from 141762SN/A * this software without specific prior written permission. 15793SN/A * 16793SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17793SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18793SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19793SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20793SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21793SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22793SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23793SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24793SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25793SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26793SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27793SN/A * 28793SN/A * Authors: Gabe Black 29793SN/A * Ali Saidi 30793SN/A */ 31793SN/A 32793SN/A#include "arch/sparc/process.hh" 33793SN/A 34793SN/A#include "arch/sparc/asi.hh" 35793SN/A#include "arch/sparc/handlers.hh" 36793SN/A#include "arch/sparc/isa_traits.hh" 37793SN/A#include "arch/sparc/registers.hh" 38793SN/A#include "arch/sparc/types.hh" 392665SN/A#include "base/loader/elf_object.hh" 402665SN/A#include "base/loader/object_file.hh" 412665SN/A#include "base/misc.hh" 422665SN/A#include "cpu/thread_context.hh" 43793SN/A#include "debug/Stack.hh" 44793SN/A#include "mem/page_table.hh" 45793SN/A#include "sim/process_impl.hh" 46793SN/A#include "sim/system.hh" 47793SN/A 48793SN/Ausing namespace std; 4911260Sandreas.sandberg@arm.comusing namespace SparcISA; 5011260Sandreas.sandberg@arm.com 51793SN/Astatic const int FirstArgumentReg = 8; 52793SN/A 53793SN/A 54793SN/ASparcLiveProcess::SparcLiveProcess(LiveProcessParams * params, 55793SN/A ObjectFile *objFile, Addr _StackBias) 567676SN/A : LiveProcess(params, objFile), StackBias(_StackBias) 57793SN/A{ 587676SN/A 59793SN/A // XXX all the below need to be updated for SPARC - Ali 6011260Sandreas.sandberg@arm.com brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize(); 612565SN/A brk_point = roundUp(brk_point, PageBytes); 623348SN/A 632565SN/A // Set pointer for next thread stack. Reserve 8M for main stack. 644167SN/A next_thread_stack_base = stack_base - (8 * 1024 * 1024); 65793SN/A 662846SN/A // Initialize these to 0s 6711244SN/A fillStart = 0; 689957SN/A spillStart = 0; 6911244SN/A} 709957SN/A 7110479SN/Avoid 7210479SN/ASparcLiveProcess::handleTrap(int trapNum, ThreadContext *tc) 7310479SN/A{ 749957SN/A PCState pc = tc->pcState(); 759957SN/A switch (trapNum) { 7610479SN/A case 0x01: // Software breakpoint 7710479SN/A warn("Software breakpoint encountered at pc %#x.\n", pc.pc()); 7810479SN/A break; 7910479SN/A case 0x02: // Division by zero 809957SN/A warn("Software signaled a division by zero at pc %#x.\n", pc.pc()); 8111244SN/A break; 8211244SN/A case 0x03: // Flush window trap 8311244SN/A flushWindows(tc); 849957SN/A break; 8511244SN/A case 0x04: // Clean windows 86793SN/A warn("Ignoring process request for clean register " 8711244SN/A "windows at pc %#x.\n", pc.pc()); 8811244SN/A break; 8911244SN/A case 0x05: // Range check 904982SN/A warn("Software signaled a range check at pc %#x.\n", pc.pc()); 914982SN/A break; 924982SN/A case 0x06: // Fix alignment 934982SN/A warn("Ignoring process request for os assisted unaligned accesses " 944982SN/A "at pc %#x.\n", pc.pc()); 954982SN/A break; 964982SN/A case 0x07: // Integer overflow 974982SN/A warn("Software signaled an integer overflow at pc %#x.\n", pc.pc()); 984982SN/A break; 994982SN/A case 0x32: // Get integer condition codes 1004982SN/A warn("Ignoring process request to get the integer condition codes " 1014982SN/A "at pc %#x.\n", pc.pc()); 1024982SN/A break; 1034982SN/A case 0x33: // Set integer condition codes 1044982SN/A warn("Ignoring process request to set the integer condition codes " 1054982SN/A "at pc %#x.\n", pc.pc()); 1064982SN/A break; 1074982SN/A default: 1084982SN/A panic("Unimplemented trap to operating system: trap number %#x.\n", trapNum); 1094982SN/A } 1104982SN/A} 1114982SN/A 1124982SN/Avoid 1139957SN/ASparcLiveProcess::initState() 1149957SN/A{ 1159957SN/A LiveProcess::initState(); 1164982SN/A 1174982SN/A ThreadContext *tc = system->getThreadContext(contextIds[0]); 1184982SN/A // From the SPARC ABI 1194982SN/A 1204982SN/A // Setup default FP state 1219957SN/A tc->setMiscRegNoEffect(MISCREG_FSR, 0); 1229957SN/A 1239957SN/A tc->setMiscRegNoEffect(MISCREG_TICK, 0); 1249957SN/A 1259957SN/A /* 12610479SN/A * Register window management registers 12710479SN/A */ 1289957SN/A 1299957SN/A // No windows contain info from other programs 1309957SN/A // tc->setMiscRegNoEffect(MISCREG_OTHERWIN, 0); 1319957SN/A tc->setIntReg(NumIntArchRegs + 6, 0); 13210479SN/A // There are no windows to pop 13310479SN/A // tc->setMiscRegNoEffect(MISCREG_CANRESTORE, 0); 1349957SN/A tc->setIntReg(NumIntArchRegs + 4, 0); 1359957SN/A // All windows are available to save into 1369957SN/A // tc->setMiscRegNoEffect(MISCREG_CANSAVE, NWindows - 2); 1379957SN/A tc->setIntReg(NumIntArchRegs + 3, NWindows - 2); 1389957SN/A // All windows are "clean" 1399957SN/A // tc->setMiscRegNoEffect(MISCREG_CLEANWIN, NWindows); 1409957SN/A tc->setIntReg(NumIntArchRegs + 5, NWindows); 1419957SN/A // Start with register window 0 14210479SN/A tc->setMiscReg(MISCREG_CWP, 0); 14310479SN/A // Always use spill and fill traps 0 1449957SN/A // tc->setMiscRegNoEffect(MISCREG_WSTATE, 0); 1459957SN/A tc->setIntReg(NumIntArchRegs + 7, 0); 1469957SN/A // Set the trap level to 0 1479957SN/A tc->setMiscRegNoEffect(MISCREG_TL, 0); 1489957SN/A // Set the ASI register to something fixed 1499957SN/A tc->setMiscReg(MISCREG_ASI, ASI_PRIMARY); 1509957SN/A 1519957SN/A /* 1529957SN/A * T1 specific registers 1539957SN/A */ 1549957SN/A // Turn on the icache, dcache, dtb translation, and itb translation. 15510479SN/A tc->setMiscRegNoEffect(MISCREG_MMU_LSU_CTRL, 15); 1569957SN/A} 15710479SN/A 1589957SN/Avoid 1599957SN/ASparc32LiveProcess::initState() 1609957SN/A{ 1619957SN/A SparcLiveProcess::initState(); 1629957SN/A 1639957SN/A ThreadContext *tc = system->getThreadContext(contextIds[0]); 1649957SN/A // The process runs in user mode with 32 bit addresses 1659957SN/A PSTATE pstate = 0; 1669957SN/A pstate.ie = 1; 1679957SN/A pstate.am = 1; 16810479SN/A tc->setMiscReg(MISCREG_PSTATE, pstate); 16910479SN/A 17010479SN/A argsInit(32 / 8, PageBytes); 17110479SN/A} 17210479SN/A 17310479SN/Avoid 17410479SN/ASparc64LiveProcess::initState() 17510479SN/A{ 17610479SN/A SparcLiveProcess::initState(); 17710479SN/A 1789957SN/A ThreadContext *tc = system->getThreadContext(contextIds[0]); 1799957SN/A // The process runs in user mode 18010479SN/A PSTATE pstate = 0; 18110479SN/A pstate.ie = 1; 1829957SN/A tc->setMiscReg(MISCREG_PSTATE, pstate); 1839957SN/A 1849957SN/A argsInit(sizeof(IntReg), PageBytes); 1859957SN/A} 1869957SN/A 1879957SN/Atemplate<class IntType> 1889957SN/Avoid 1899957SN/ASparcLiveProcess::argsInit(int pageSize) 1909957SN/A{ 1919957SN/A int intSize = sizeof(IntType); 1924982SN/A 1934982SN/A typedef AuxVector<IntType> auxv_t; 1944982SN/A 1954982SN/A std::vector<auxv_t> auxv; 1964982SN/A 1974982SN/A string filename; 1984982SN/A if (argv.size() < 1) 1995834SN/A filename = ""; 2005834SN/A else 2015834SN/A filename = argv[0]; 2025834SN/A 2035834SN/A // Even for a 32 bit process, the ABI says we still need to 2045834SN/A // maintain double word alignment of the stack pointer. 2055834SN/A uint64_t align = 16; 2064982SN/A 2075834SN/A // Patch the ld_bias for dynamic executables. 20810359SN/A updateBias(); 2095834SN/A 2105834SN/A // load object file into target memory 2115834SN/A objFile->loadSections(initVirtMem); 2125834SN/A 2135834SN/A enum hardwareCaps 2145834SN/A { 2155834SN/A M5_HWCAP_SPARC_FLUSH = 1, 2164982SN/A M5_HWCAP_SPARC_STBAR = 2, 2174982SN/A M5_HWCAP_SPARC_SWAP = 4, 2182846SN/A M5_HWCAP_SPARC_MULDIV = 8, 2192846SN/A M5_HWCAP_SPARC_V9 = 16, 2202846SN/A // This one should technically only be set 2219807SN/A // if there is a cheetah or cheetah_plus tlb, 2222846SN/A // but we'll use it all the time 2232846SN/A M5_HWCAP_SPARC_ULTRA3 = 32 22410479SN/A }; 22510479SN/A 22610479SN/A const int64_t hwcap = 22710479SN/A M5_HWCAP_SPARC_FLUSH | 22810479SN/A M5_HWCAP_SPARC_STBAR | 22910479SN/A M5_HWCAP_SPARC_SWAP | 23010479SN/A M5_HWCAP_SPARC_MULDIV | 23110479SN/A M5_HWCAP_SPARC_V9 | 23210479SN/A M5_HWCAP_SPARC_ULTRA3; 23310479SN/A 23410479SN/A // Setup the auxilliary vectors. These will already have endian conversion. 23510479SN/A // Auxilliary vectors are loaded only for elf formatted executables. 23610479SN/A ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile); 23710479SN/A if (elfObject) { 23810479SN/A // Bits which describe the system hardware capabilities 23910479SN/A auxv.push_back(auxv_t(M5_AT_HWCAP, hwcap)); 24010479SN/A // The system page size 24110479SN/A auxv.push_back(auxv_t(M5_AT_PAGESZ, SparcISA::PageBytes)); 24210479SN/A // Defined to be 100 in the kernel source. 24310479SN/A // Frequency at which times() increments 24410479SN/A auxv.push_back(auxv_t(M5_AT_CLKTCK, 100)); 24510479SN/A // For statically linked executables, this is the virtual address of the 24610479SN/A // program header tables if they appear in the executable image 2472846SN/A auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable())); 2482846SN/A // This is the size of a program header entry from the elf file. 2492846SN/A auxv.push_back(auxv_t(M5_AT_PHENT, elfObject->programHeaderSize())); 25011260Sandreas.sandberg@arm.com // This is the number of program headers from the original elf file. 2513083SN/A auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount())); 25211244SN/A // This is the base address of the ELF interpreter; it should be 2532846SN/A // zero for static executables or contain the base address for 2542846SN/A // dynamic executables. 2552846SN/A auxv.push_back(auxv_t(M5_AT_BASE, getBias())); 2562846SN/A // This is hardwired to 0 in the elf loading code in the kernel 25711260Sandreas.sandberg@arm.com auxv.push_back(auxv_t(M5_AT_FLAGS, 0)); 2583083SN/A // The entry point to the program 25911244SN/A auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint())); 2602846SN/A // Different user and group IDs 2612846SN/A auxv.push_back(auxv_t(M5_AT_UID, uid())); 2622846SN/A auxv.push_back(auxv_t(M5_AT_EUID, euid())); 2632846SN/A auxv.push_back(auxv_t(M5_AT_GID, gid())); 26411260Sandreas.sandberg@arm.com auxv.push_back(auxv_t(M5_AT_EGID, egid())); 2653083SN/A // Whether to enable "secure mode" in the executable 26611244SN/A auxv.push_back(auxv_t(M5_AT_SECURE, 0)); 2672846SN/A } 2682846SN/A 2692846SN/A // Figure out how big the initial stack needs to be 2702846SN/A 2712846SN/A // The unaccounted for 8 byte 0 at the top of the stack 2724870SN/A int sentry_size = 8; 2732846SN/A 2742846SN/A // This is the name of the file which is present on the initial stack 275793SN/A // It's purpose is to let the user space linker examine the original file. 276793SN/A int file_name_size = filename.size() + 1; 2778711SN/A 2789807SN/A int env_data_size = 0; 2792565SN/A for (int i = 0; i < envp.size(); ++i) { 2808711SN/A env_data_size += envp[i].size() + 1; 2812565SN/A } 2822565SN/A int arg_data_size = 0; 2832565SN/A for (int i = 0; i < argv.size(); ++i) { 2848711SN/A arg_data_size += argv[i].size() + 1; 2858711SN/A } 2862565SN/A 2872565SN/A // The info_block. 2882846SN/A int base_info_block_size = 2899807SN/A sentry_size + file_name_size + env_data_size + arg_data_size; 290793SN/A 2912846SN/A int info_block_size = roundUp(base_info_block_size, align); 29210479SN/A 29310479SN/A int info_block_padding = info_block_size - base_info_block_size; 29410479SN/A 29510479SN/A // Each auxilliary vector is two words 29610479SN/A int aux_array_size = intSize * 2 * (auxv.size() + 1); 29710479SN/A 29810479SN/A int envp_array_size = intSize * (envp.size() + 1); 29910479SN/A int argv_array_size = intSize * (argv.size() + 1); 30010479SN/A 30110479SN/A int argc_size = intSize; 30210479SN/A int window_save_size = intSize * 16; 30310479SN/A 30410479SN/A // Figure out the size of the contents of the actual initial frame 30510479SN/A int frame_size = 30610479SN/A aux_array_size + 30710479SN/A envp_array_size + 30810479SN/A argv_array_size + 3091155SN/A argc_size + 3102846SN/A window_save_size; 3112846SN/A 3122846SN/A // There needs to be padding after the auxiliary vector data so that the 3132846SN/A // very bottom of the stack is aligned properly. 3142846SN/A int aligned_partial_size = roundUp(frame_size, align); 3155777SN/A int aux_padding = aligned_partial_size - frame_size; 3162846SN/A 3172846SN/A int space_needed = 3185777SN/A info_block_size + 3192846SN/A aux_padding + 3202846SN/A frame_size; 3212846SN/A 3222846SN/A stack_min = stack_base - space_needed; 3232846SN/A stack_min = roundDown(stack_min, align); 3242846SN/A stack_size = stack_base - stack_min; 3252846SN/A 3262846SN/A // Allocate space for the stack 3272846SN/A allocateMem(roundDown(stack_min, pageSize), roundUp(stack_size, pageSize)); 3282846SN/A 3292846SN/A // map out initial stack contents 3302846SN/A IntType sentry_base = stack_base - sentry_size; 3312846SN/A IntType file_name_base = sentry_base - file_name_size; 33211260Sandreas.sandberg@arm.com IntType env_data_base = file_name_base - env_data_size; 3333083SN/A IntType arg_data_base = env_data_base - arg_data_size; 33411244SN/A IntType auxv_array_base = arg_data_base - 3352846SN/A info_block_padding - aux_array_size - aux_padding; 3362846SN/A IntType envp_array_base = auxv_array_base - envp_array_size; 3372846SN/A IntType argv_array_base = envp_array_base - argv_array_size; 3382846SN/A IntType argc_base = argv_array_base - argc_size; 3392846SN/A#if TRACING_ON 3402846SN/A IntType window_save_base = argc_base - window_save_size; 3415777SN/A#endif 3422846SN/A 3432846SN/A DPRINTF(Stack, "The addresses of items on the initial stack:\n"); 3445777SN/A DPRINTF(Stack, "%#x - sentry NULL\n", sentry_base); 3452846SN/A DPRINTF(Stack, "filename = %s\n", filename); 3462846SN/A DPRINTF(Stack, "%#x - file name\n", file_name_base); 3472846SN/A DPRINTF(Stack, "%#x - env data\n", env_data_base); 3482846SN/A DPRINTF(Stack, "%#x - arg data\n", arg_data_base); 3492846SN/A DPRINTF(Stack, "%#x - auxv array\n", auxv_array_base); 3502846SN/A DPRINTF(Stack, "%#x - envp array\n", envp_array_base); 35111260Sandreas.sandberg@arm.com DPRINTF(Stack, "%#x - argv array\n", argv_array_base); 3523083SN/A DPRINTF(Stack, "%#x - argc \n", argc_base); 35311244SN/A DPRINTF(Stack, "%#x - window save\n", window_save_base); 3542846SN/A DPRINTF(Stack, "%#x - stack min\n", stack_min); 3552846SN/A 3562846SN/A assert(window_save_base == stack_min); 3572846SN/A 3582846SN/A // write contents to stack 3592846SN/A 3602846SN/A // figure out argc 3612846SN/A IntType argc = argv.size(); 3622846SN/A IntType guestArgc = SparcISA::htog(argc); 3632846SN/A 3643086SN/A // Write out the sentry void * 3653086SN/A uint64_t sentry_NULL = 0; 366793SN/A initVirtMem.writeBlob(sentry_base, 3675834SN/A (uint8_t*)&sentry_NULL, sentry_size); 3685834SN/A 3695834SN/A // Write the file name 3705834SN/A initVirtMem.writeString(file_name_base, filename.c_str()); 371795SN/A 3725834SN/A // Copy the aux stuff 3735834SN/A for (int x = 0; x < auxv.size(); x++) { 3742565SN/A initVirtMem.writeBlob(auxv_array_base + x * 2 * intSize, 3755834SN/A (uint8_t*)&(auxv[x].a_type), intSize); 3765834SN/A initVirtMem.writeBlob(auxv_array_base + (x * 2 + 1) * intSize, 3775834SN/A (uint8_t*)&(auxv[x].a_val), intSize); 3785834SN/A } 3795834SN/A 3805834SN/A // Write out the terminating zeroed auxilliary vector 3815834SN/A const IntType zero = 0; 3825834SN/A initVirtMem.writeBlob(auxv_array_base + intSize * 2 * auxv.size(), 3835834SN/A (uint8_t*)&zero, intSize); 3845834SN/A initVirtMem.writeBlob(auxv_array_base + intSize * (2 * auxv.size() + 1), 38511244SN/A (uint8_t*)&zero, intSize); 38611244SN/A 3878851SN/A copyStringArray(envp, envp_array_base, env_data_base, initVirtMem); 3885834SN/A copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem); 3893086SN/A 3905834SN/A initVirtMem.writeBlob(argc_base, (uint8_t*)&guestArgc, intSize); 3915834SN/A 3922846SN/A // Set up space for the trap handlers into the processes address space. 3932846SN/A // Since the stack grows down and there is reserved address space abov 3942846SN/A // it, we can put stuff above it and stay out of the way. 3952565SN/A fillStart = stack_base; 3962846SN/A spillStart = fillStart + sizeof(MachInst) * numFillInsts; 3972846SN/A 3982846SN/A ThreadContext *tc = system->getThreadContext(contextIds[0]); 3992846SN/A // Set up the thread context to start running the process 4002846SN/A // assert(NumArgumentRegs >= 2); 4012846SN/A // tc->setIntReg(ArgumentReg[0], argc); 4022846SN/A // tc->setIntReg(ArgumentReg[1], argv_array_base); 4032846SN/A tc->setIntReg(StackPointerReg, stack_min - StackBias); 4042846SN/A 4052846SN/A // %g1 is a pointer to a function that should be run at exit. Since we 4062846SN/A // don't have anything like that, it should be set to 0. 4072846SN/A tc->setIntReg(1, 0); 4082846SN/A 4092846SN/A tc->pcState(getStartPC()); 4102846SN/A 41111260Sandreas.sandberg@arm.com // Align the "stack_min" to a page boundary. 4122846SN/A stack_min = roundDown(stack_min, pageSize); 41311260Sandreas.sandberg@arm.com 4143083SN/A// num_processes++; 41511244SN/A} 4162846SN/A 4172565SN/Avoid 4182565SN/ASparc64LiveProcess::argsInit(int intSize, int pageSize) 4192846SN/A{ 4202565SN/A SparcLiveProcess::argsInit<uint64_t>(pageSize); 4214870SN/A 4222846SN/A // Stuff the trap handlers into the process address space 423793SN/A initVirtMem.writeBlob(fillStart, 424793SN/A (uint8_t*)fillHandler64, sizeof(MachInst) * numFillInsts); 425793SN/A initVirtMem.writeBlob(spillStart, 42610905SN/A (uint8_t*)spillHandler64, sizeof(MachInst) * numSpillInsts); 427793SN/A} 4281854SN/A 4291854SN/Avoid 4301854SN/ASparc32LiveProcess::argsInit(int intSize, int pageSize) 4319957SN/A{ 4329957SN/A SparcLiveProcess::argsInit<uint32_t>(pageSize); 43310905SN/A 43410905SN/A // Stuff the trap handlers into the process address space 43510905SN/A initVirtMem.writeBlob(fillStart, 4369957SN/A (uint8_t*)fillHandler32, sizeof(MachInst) * numFillInsts); 43710905SN/A initVirtMem.writeBlob(spillStart, 43810905SN/A (uint8_t*)spillHandler32, sizeof(MachInst) * numSpillInsts); 43910905SN/A} 4409957SN/A 44110905SN/Avoid Sparc32LiveProcess::flushWindows(ThreadContext *tc) 4429957SN/A{ 4439957SN/A IntReg Cansave = tc->readIntReg(NumIntArchRegs + 3); 4449957SN/A IntReg Canrestore = tc->readIntReg(NumIntArchRegs + 4); 44510905SN/A IntReg Otherwin = tc->readIntReg(NumIntArchRegs + 6); 44610905SN/A MiscReg CWP = tc->readMiscReg(MISCREG_CWP); 44710905SN/A MiscReg origCWP = CWP; 44810905SN/A CWP = (CWP + Cansave + 2) % NWindows; 4499957SN/A while (NWindows - 2 - Cansave != 0) { 4509957SN/A if (Otherwin) { 4519957SN/A panic("Otherwin non-zero.\n"); 45210479SN/A } else { 45310479SN/A tc->setMiscReg(MISCREG_CWP, CWP); 4549957SN/A // Do the stores 4559957SN/A IntReg sp = tc->readIntReg(StackPointerReg); 4569957SN/A for (int index = 16; index < 32; index++) { 4579957SN/A uint32_t regVal = tc->readIntReg(index); 4589957SN/A regVal = htog(regVal); 4599957SN/A if (!tc->getMemProxy().tryWriteBlob( 4609957SN/A sp + (index - 16) * 4, (uint8_t *)®Val, 4)) { 4619957SN/A warn("Failed to save register to the stack when " 4629957SN/A "flushing windows.\n"); 46310905SN/A } 4649957SN/A } 46510905SN/A Canrestore--; 4669957SN/A Cansave++; 46710905SN/A CWP = (CWP + 1) % NWindows; 4689957SN/A } 46910905SN/A } 4709957SN/A tc->setIntReg(NumIntArchRegs + 3, Cansave); 4719957SN/A tc->setIntReg(NumIntArchRegs + 4, Canrestore); 4729957SN/A tc->setMiscReg(MISCREG_CWP, origCWP); 47310905SN/A} 4749957SN/A 4759957SN/Avoid 4769957SN/ASparc64LiveProcess::flushWindows(ThreadContext *tc) 4779957SN/A{ 47810905SN/A IntReg Cansave = tc->readIntReg(NumIntArchRegs + 3); 47910905SN/A IntReg Canrestore = tc->readIntReg(NumIntArchRegs + 4); 48010905SN/A IntReg Otherwin = tc->readIntReg(NumIntArchRegs + 6); 48110905SN/A MiscReg CWP = tc->readMiscReg(MISCREG_CWP); 48210905SN/A MiscReg origCWP = CWP; 48310905SN/A CWP = (CWP + Cansave + 2) % NWindows; 48410905SN/A while (NWindows - 2 - Cansave != 0) { 48510905SN/A if (Otherwin) { 48610905SN/A panic("Otherwin non-zero.\n"); 48710905SN/A } else { 488793SN/A tc->setMiscReg(MISCREG_CWP, CWP); 489793SN/A // Do the stores 490793SN/A IntReg sp = tc->readIntReg(StackPointerReg); 49110905SN/A for (int index = 16; index < 32; index++) { 492793SN/A IntReg regVal = tc->readIntReg(index); 4931854SN/A regVal = htog(regVal); 4941854SN/A if (!tc->getMemProxy().tryWriteBlob( 4951854SN/A sp + 2047 + (index - 16) * 8, (uint8_t *)®Val, 8)) { 4961854SN/A warn("Failed to save register to the stack when " 4979957SN/A "flushing windows.\n"); 4989957SN/A } 4999957SN/A } 5009957SN/A Canrestore--; 50110905SN/A Cansave++; 5029957SN/A CWP = (CWP + 1) % NWindows; 50310905SN/A } 5049957SN/A } 50510905SN/A tc->setIntReg(NumIntArchRegs + 3, Cansave); 5069957SN/A tc->setIntReg(NumIntArchRegs + 4, Canrestore); 5079957SN/A tc->setMiscReg(MISCREG_CWP, origCWP); 50810905SN/A} 5099957SN/A 51010905SN/AIntReg 5119957SN/ASparc32LiveProcess::getSyscallArg(ThreadContext *tc, int &i) 51210905SN/A{ 5139957SN/A assert(i < 6); 5149957SN/A return bits(tc->readIntReg(FirstArgumentReg + i++), 31, 0); 51510905SN/A} 5169957SN/A 5179957SN/Avoid 5189957SN/ASparc32LiveProcess::setSyscallArg(ThreadContext *tc, int i, IntReg val) 5199957SN/A{ 52010905SN/A assert(i < 6); 5219957SN/A tc->setIntReg(FirstArgumentReg + i, bits(val, 31, 0)); 52210905SN/A} 5239957SN/A 52410905SN/AIntReg 5259957SN/ASparc64LiveProcess::getSyscallArg(ThreadContext *tc, int &i) 52610905SN/A{ 5279957SN/A assert(i < 6); 5289957SN/A return tc->readIntReg(FirstArgumentReg + i++); 5299957SN/A} 5309957SN/A 5319957SN/Avoid 5329957SN/ASparc64LiveProcess::setSyscallArg(ThreadContext *tc, int i, IntReg val) 5339957SN/A{ 5349957SN/A assert(i < 6); 5359957SN/A tc->setIntReg(FirstArgumentReg + i, val); 5369957SN/A} 5379957SN/A 5389957SN/Avoid 5399957SN/ASparcLiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn sysret) 5409957SN/A{ 5419957SN/A // check for error condition. SPARC syscall convention is to 5429957SN/A // indicate success/failure in reg the carry bit of the ccr 5439957SN/A // and put the return value itself in the standard return value reg (). 54410905SN/A PSTATE pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE); 5459957SN/A if (sysret.successful()) { 54610905SN/A // no error, clear XCC.C 5479957SN/A tc->setIntReg(NumIntArchRegs + 2, 54810905SN/A tc->readIntReg(NumIntArchRegs + 2) & 0xEE); 5499957SN/A IntReg val = sysret.returnValue(); 55010905SN/A if (pstate.am) 5519957SN/A val = bits(val, 31, 0); 5529957SN/A tc->setIntReg(ReturnValueReg, val); 5539957SN/A } else { 55410905SN/A // got an error, set XCC.C 5559957SN/A tc->setIntReg(NumIntArchRegs + 2, 5569957SN/A tc->readIntReg(NumIntArchRegs + 2) | 0x11); 5579957SN/A IntReg val = sysret.errnoValue(); 5589957SN/A if (pstate.am) 55910905SN/A val = bits(val, 31, 0); 5609957SN/A tc->setIntReg(ReturnValueReg, val); 56110905SN/A } 5629957SN/A} 56310905SN/A