#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <elf.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/auxv.h>
#include <sys/wait.h>

#include "types.h"
#include "log.h"
#include "asm/parasite-syscall.h"
#include "asm/restorer.h"
#include <compel/asm/fpu.h>
#include "asm/dump.h"
#include "cr_options.h"
#include "common/compiler.h"
#include "restorer.h"
#include "parasite-syscall.h"
#include "util.h"
#include "cpu.h"
#include <compel/plugins/std/syscall-codes.h>
#include "kerndat.h"

#include "protobuf.h"
#include "images/core.pb-c.h"
#include "images/creds.pb-c.h"


int save_task_regs(void *x, user_regs_struct_t *regs, user_fpregs_struct_t *fpregs)
{
    CoreEntry *core = x;

      /* Save the MIPS CPU state */
    core->ti_mips->gpregs->r0 = regs->regs[0];
    core->ti_mips->gpregs->r1 = regs->regs[1];
    core->ti_mips->gpregs->r2 = regs->regs[2];
    core->ti_mips->gpregs->r3 = regs->regs[3];
    core->ti_mips->gpregs->r4 = regs->regs[4];
    core->ti_mips->gpregs->r5 = regs->regs[5];
    core->ti_mips->gpregs->r6 = regs->regs[6];
    core->ti_mips->gpregs->r7 = regs->regs[7];
    core->ti_mips->gpregs->r8 = regs->regs[8];
    core->ti_mips->gpregs->r9 = regs->regs[9];
    core->ti_mips->gpregs->r10 = regs->regs[10];
    core->ti_mips->gpregs->r11 = regs->regs[11];
    core->ti_mips->gpregs->r12 = regs->regs[12];
    core->ti_mips->gpregs->r13 = regs->regs[13];
    core->ti_mips->gpregs->r14 = regs->regs[14];
    core->ti_mips->gpregs->r15 = regs->regs[15];
    core->ti_mips->gpregs->r16 = regs->regs[16];
    core->ti_mips->gpregs->r17 = regs->regs[17];
    core->ti_mips->gpregs->r18 = regs->regs[18];
    core->ti_mips->gpregs->r19 = regs->regs[19];
    core->ti_mips->gpregs->r20 = regs->regs[20];
    core->ti_mips->gpregs->r21 = regs->regs[21];
    core->ti_mips->gpregs->r22 = regs->regs[22];
    core->ti_mips->gpregs->r23 = regs->regs[23];
    core->ti_mips->gpregs->r24 = regs->regs[24];
    core->ti_mips->gpregs->r25 = regs->regs[25];
    core->ti_mips->gpregs->r26 = regs->regs[26];
    core->ti_mips->gpregs->r27 = regs->regs[27];
    core->ti_mips->gpregs->r28 = regs->regs[28];
    core->ti_mips->gpregs->r29 = regs->regs[29];
    core->ti_mips->gpregs->r30 = regs->regs[30];
    core->ti_mips->gpregs->r31 = regs->regs[31];
    
    core->ti_mips->gpregs->lo = regs->lo;
    core->ti_mips->gpregs->hi = regs->hi;
    core->ti_mips->gpregs->cp0_epc = regs->cp0_epc;
    core->ti_mips->gpregs->cp0_badvaddr = regs->cp0_badvaddr;
    core->ti_mips->gpregs->cp0_status = regs->cp0_status;
    core->ti_mips->gpregs->cp0_cause = regs->cp0_cause;
    
    core->ti_mips->fpregs->r0 = fpregs->regs[0];
    core->ti_mips->fpregs->r1 = fpregs->regs[1];
    core->ti_mips->fpregs->r2 = fpregs->regs[2];
    core->ti_mips->fpregs->r3 = fpregs->regs[3];
    core->ti_mips->fpregs->r4 = fpregs->regs[4];
    core->ti_mips->fpregs->r5 = fpregs->regs[5];
    core->ti_mips->fpregs->r6 = fpregs->regs[6];
    core->ti_mips->fpregs->r7 = fpregs->regs[7];
    core->ti_mips->fpregs->r8 = fpregs->regs[8];
    core->ti_mips->fpregs->r9 = fpregs->regs[9];
    core->ti_mips->fpregs->r10 = fpregs->regs[10];
    core->ti_mips->fpregs->r11 = fpregs->regs[11];
    core->ti_mips->fpregs->r12 = fpregs->regs[12];
    core->ti_mips->fpregs->r13 = fpregs->regs[13];
    core->ti_mips->fpregs->r14 = fpregs->regs[14];
    core->ti_mips->fpregs->r15 = fpregs->regs[15];
    core->ti_mips->fpregs->r16 = fpregs->regs[16];
    core->ti_mips->fpregs->r17 = fpregs->regs[17];
    core->ti_mips->fpregs->r18 = fpregs->regs[18];
    core->ti_mips->fpregs->r19 = fpregs->regs[19];
    core->ti_mips->fpregs->r20 = fpregs->regs[20];
    core->ti_mips->fpregs->r21 = fpregs->regs[21];
    core->ti_mips->fpregs->r22 = fpregs->regs[22];
    core->ti_mips->fpregs->r23 = fpregs->regs[23];
    core->ti_mips->fpregs->r24 = fpregs->regs[24];
    core->ti_mips->fpregs->r25 = fpregs->regs[25];
    core->ti_mips->fpregs->r26 = fpregs->regs[26];
    core->ti_mips->fpregs->r27 = fpregs->regs[27];
    core->ti_mips->fpregs->r28 = fpregs->regs[28];
    core->ti_mips->fpregs->r29 = fpregs->regs[29];
    core->ti_mips->fpregs->r30 = fpregs->regs[30];
    core->ti_mips->fpregs->r31 = fpregs->regs[31];
    core->ti_mips->fpregs->fpu_fcr31 = fpregs->fpu_fcr31;
    core->ti_mips->fpregs->fpu_id = fpregs->fpu_id;
    
    return 0;
}

int arch_alloc_thread_info(CoreEntry *core)
{
    ThreadInfoMips *ti_mips;
    UserMipsRegsEntry *gpregs;
    UserMipsFpregsEntry *fpregs;

    ti_mips = xmalloc(sizeof(*ti_mips));
    if (!ti_mips)
	goto err;

    thread_info_mips__init(ti_mips);
    core->ti_mips = ti_mips;

    gpregs = xmalloc(sizeof(*gpregs));
    if (!gpregs){
	xfree(ti_mips);
	goto err;
    }

    user_mips_regs_entry__init(gpregs);
    ti_mips->gpregs = gpregs;

    fpregs = xmalloc(sizeof(*fpregs));
    if (!fpregs){
	xfree(ti_mips);
	xfree(gpregs);
	goto err;
    }

    user_mips_fpregs_entry__init(fpregs);
    ti_mips->fpregs = fpregs;
    
    return 0;
err:
    return -1;
}

void arch_free_thread_info(CoreEntry *core)
{
    if (!core->ti_mips)
	return;

    if (core->ti_mips->gpregs)
	xfree(core->ti_mips->gpregs);
    
    if (core->ti_mips->fpregs)
	xfree(core->ti_mips->fpregs);

    xfree(core->ti_mips);
}

int restore_fpu(struct rt_sigframe *sigframe, CoreEntry *core)
{
    struct rt_sigframe *f = sigframe;
    UserMipsFpregsEntry *r = core->ti_mips->fpregs;

    f->rs_uc.uc_mcontext.sc_fpregs[0] = r->r0;
    f->rs_uc.uc_mcontext.sc_fpregs[1] = r->r1;
    f->rs_uc.uc_mcontext.sc_fpregs[2] = r->r2;
    f->rs_uc.uc_mcontext.sc_fpregs[3] = r->r3;
    f->rs_uc.uc_mcontext.sc_fpregs[4] = r->r4;
    f->rs_uc.uc_mcontext.sc_fpregs[5] = r->r5;
    f->rs_uc.uc_mcontext.sc_fpregs[6] = r->r6;
    f->rs_uc.uc_mcontext.sc_fpregs[7] = r->r7;
    f->rs_uc.uc_mcontext.sc_fpregs[8] = r->r8;
    f->rs_uc.uc_mcontext.sc_fpregs[9] = r->r9;
    f->rs_uc.uc_mcontext.sc_fpregs[10] = r->r10;
    f->rs_uc.uc_mcontext.sc_fpregs[11] = r->r11;
    f->rs_uc.uc_mcontext.sc_fpregs[12] = r->r12;
    f->rs_uc.uc_mcontext.sc_fpregs[13] = r->r13;
    f->rs_uc.uc_mcontext.sc_fpregs[14] = r->r14;
    f->rs_uc.uc_mcontext.sc_fpregs[15] = r->r15;
    f->rs_uc.uc_mcontext.sc_fpregs[16] = r->r16;
    f->rs_uc.uc_mcontext.sc_fpregs[17] = r->r17;
    f->rs_uc.uc_mcontext.sc_fpregs[18] = r->r18;
    f->rs_uc.uc_mcontext.sc_fpregs[19] = r->r19;
    f->rs_uc.uc_mcontext.sc_fpregs[20] = r->r20;
    f->rs_uc.uc_mcontext.sc_fpregs[21] = r->r21;
    f->rs_uc.uc_mcontext.sc_fpregs[22] = r->r22;
    f->rs_uc.uc_mcontext.sc_fpregs[23] = r->r23;
    f->rs_uc.uc_mcontext.sc_fpregs[24] = r->r24;
    f->rs_uc.uc_mcontext.sc_fpregs[25] = r->r25;
    f->rs_uc.uc_mcontext.sc_fpregs[26] = r->r26;
    f->rs_uc.uc_mcontext.sc_fpregs[27] = r->r27;
    f->rs_uc.uc_mcontext.sc_fpregs[28] = r->r28;
    f->rs_uc.uc_mcontext.sc_fpregs[29] = r->r29;
    f->rs_uc.uc_mcontext.sc_fpregs[30] = r->r30;
    f->rs_uc.uc_mcontext.sc_fpregs[31] = r->r31;

    return 0;
}


int restore_gpregs(struct rt_sigframe *f, UserMipsRegsEntry *r)
{
    f->rs_uc.uc_mcontext.sc_regs[0] = r->r0;
    f->rs_uc.uc_mcontext.sc_regs[1] = r->r1;
    f->rs_uc.uc_mcontext.sc_regs[2] = r->r2;
    f->rs_uc.uc_mcontext.sc_regs[3] = r->r3;
    f->rs_uc.uc_mcontext.sc_regs[4] = r->r4;
    f->rs_uc.uc_mcontext.sc_regs[5] = r->r5;
    f->rs_uc.uc_mcontext.sc_regs[6] = r->r6;
    f->rs_uc.uc_mcontext.sc_regs[7] = r->r7;
    f->rs_uc.uc_mcontext.sc_regs[8] = r->r8;
    f->rs_uc.uc_mcontext.sc_regs[9] = r->r9;
    f->rs_uc.uc_mcontext.sc_regs[10] = r->r10;
    f->rs_uc.uc_mcontext.sc_regs[11] = r->r11;
    f->rs_uc.uc_mcontext.sc_regs[12] = r->r12;
    f->rs_uc.uc_mcontext.sc_regs[13] = r->r13;
    f->rs_uc.uc_mcontext.sc_regs[14] = r->r14;
    f->rs_uc.uc_mcontext.sc_regs[15] = r->r15;
    f->rs_uc.uc_mcontext.sc_regs[16] = r->r16;
    f->rs_uc.uc_mcontext.sc_regs[17] = r->r17;
    f->rs_uc.uc_mcontext.sc_regs[18] = r->r18;
    f->rs_uc.uc_mcontext.sc_regs[19] = r->r19;
    f->rs_uc.uc_mcontext.sc_regs[20] = r->r20;
    f->rs_uc.uc_mcontext.sc_regs[21] = r->r21;
    f->rs_uc.uc_mcontext.sc_regs[22] = r->r22;
    f->rs_uc.uc_mcontext.sc_regs[23] = r->r23;
    f->rs_uc.uc_mcontext.sc_regs[24] = r->r24;
    f->rs_uc.uc_mcontext.sc_regs[25] = r->r25;
    f->rs_uc.uc_mcontext.sc_regs[26] = r->r26;
    f->rs_uc.uc_mcontext.sc_regs[27] = r->r27;
    f->rs_uc.uc_mcontext.sc_regs[28] = r->r28;
    f->rs_uc.uc_mcontext.sc_regs[29] = r->r29;
    f->rs_uc.uc_mcontext.sc_regs[30] = r->r30;
    f->rs_uc.uc_mcontext.sc_regs[31] = r->r31;

    f->rs_uc.uc_mcontext.sc_mdlo = r->lo;
    f->rs_uc.uc_mcontext.sc_mdhi = r->hi;
    f->rs_uc.uc_mcontext.sc_pc = r->cp0_epc;

    return 0;
}

int get_task_futex_robust_list_compat(pid_t pid, ThreadCoreEntry *info)
{
    return 0;
}
