#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
#   mk_spl_img.py --- Make spl images
#
#   Copyright (C) 2022, Zhaohui Shi, all rights reserved.
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
import os
import sys
from struct import Struct, unpack, pack
import struct

CORE_CONTEXT_MAIGC=0xdeadffde00000000

## /*******************************************************************************
##  * Constants that allow assembler code to access members of and the 'gp_regs'
##  * structure at their correct offsets.
##  ******************************************************************************/
CTX_GPREGS_OFFSET	= (0x0)
CTX_GPREG_X0		= (0x0)
CTX_GPREG_X1		= (0x8)
CTX_GPREG_X2		= (0x10)
CTX_GPREG_X3		= (0x18)
CTX_GPREG_X4		= (0x20)
CTX_GPREG_X5		= (0x28)
CTX_GPREG_X6		= (0x30)
CTX_GPREG_X7		= (0x38)
CTX_GPREG_X8		= (0x40)
CTX_GPREG_X9		= (0x48)
CTX_GPREG_X10		= (0x50)
CTX_GPREG_X11		= (0x58)
CTX_GPREG_X12		= (0x60)
CTX_GPREG_X13		= (0x68)
CTX_GPREG_X14		= (0x70)
CTX_GPREG_X15		= (0x78)
CTX_GPREG_X16		= (0x80)
CTX_GPREG_X17		= (0x88)
CTX_GPREG_X18		= (0x90)
CTX_GPREG_X19		= (0x98)
CTX_GPREG_X20		= (0xa0)
CTX_GPREG_X21		= (0xa8)
CTX_GPREG_X22		= (0xb0)
CTX_GPREG_X23		= (0xb8)
CTX_GPREG_X24		= (0xc0)
CTX_GPREG_X25		= (0xc8)
CTX_GPREG_X26		= (0xd0)
CTX_GPREG_X27		= (0xd8)
CTX_GPREG_X28		= (0xe0)
CTX_GPREG_X29		= (0xe8)
CTX_GPREG_LR		= (0xf0)
CTX_GPREG_SP_EL0	= (0xf8)
CTX_GPREGS_END		= (0x100)

## /*******************************************************************************
##  * Constants that allow assembler code to access members of and the 'el3_state'
##  * structure at their correct offsets. Note that some of the registers are only
##  * 32-bits wide but are stored as 64-bit values for convenience
##  ******************************************************************************/
CTX_EL3STATE_OFFSET	= (CTX_GPREGS_OFFSET + CTX_GPREGS_END)
CTX_SCR_EL3		= (0x0)
CTX_ESR_EL3		= (0x8)
CTX_RUNTIME_SP		= (0x10)
CTX_SPSR_EL3		= (0x18)
CTX_ELR_EL3		= (0x20)
CTX_PMCR_EL0		= (0x28)
CTX_EL3STATE_END	= (0x30)

## /*******************************************************************************
##  * Constants that allow assembler code to access members of and the
##  * 'el1_sys_regs' structure at their correct offsets. Note that some of the
##  * registers are only 32-bits wide but are stored as 64-bit values for
##  * convenience
##  ******************************************************************************/
CTX_SYSREGS_OFFSET	= (CTX_EL3STATE_OFFSET + CTX_EL3STATE_END)
CTX_SPSR_EL1		= (0x0)
CTX_ELR_EL1		= (0x8)
CTX_SCTLR_EL1		= (0x10)
CTX_ACTLR_EL1		= (0x18)
CTX_CPACR_EL1		= (0x20)
CTX_CSSELR_EL1		= (0x28)
CTX_SP_EL1		= (0x30)
CTX_ESR_EL1		= (0x38)
CTX_TTBR0_EL1		= (0x40)
CTX_TTBR1_EL1		= (0x48)
CTX_MAIR_EL1		= (0x50)
CTX_AMAIR_EL1		= (0x58)
CTX_TCR_EL1		= (0x60)
CTX_TPIDR_EL1		= (0x68)
CTX_TPIDR_EL0		= (0x70)
CTX_TPIDRRO_EL0		= (0x78)
CTX_PAR_EL1		= (0x80)
CTX_FAR_EL1		= (0x88)
CTX_AFSR0_EL1		= (0x90)
CTX_AFSR1_EL1		= (0x98)
CTX_CONTEXTIDR_EL1	= (0xa0)
CTX_VBAR_EL1		= (0xa8)

reg_name_array = [
	[ "X0" ,            CTX_GPREGS_OFFSET + CTX_GPREG_X0		],
	[ "X1" ,            CTX_GPREGS_OFFSET + CTX_GPREG_X1		],
	[ "X2" ,            CTX_GPREGS_OFFSET + CTX_GPREG_X2		],
	[ "X3" ,            CTX_GPREGS_OFFSET + CTX_GPREG_X3		],
	[ "X4" ,            CTX_GPREGS_OFFSET + CTX_GPREG_X4		],
	[ "X5" ,            CTX_GPREGS_OFFSET + CTX_GPREG_X5		],
	[ "X6" ,            CTX_GPREGS_OFFSET + CTX_GPREG_X6		],
	[ "X7" ,            CTX_GPREGS_OFFSET + CTX_GPREG_X7		],
	[ "X8" ,            CTX_GPREGS_OFFSET + CTX_GPREG_X8		],
	[ "X9" ,            CTX_GPREGS_OFFSET + CTX_GPREG_X9		],
	[ "X10",            CTX_GPREGS_OFFSET + CTX_GPREG_X10		],
	[ "X11",            CTX_GPREGS_OFFSET + CTX_GPREG_X11		],
	[ "X12",            CTX_GPREGS_OFFSET + CTX_GPREG_X12		],
	[ "X13",            CTX_GPREGS_OFFSET + CTX_GPREG_X13		],
	[ "X14",            CTX_GPREGS_OFFSET + CTX_GPREG_X14		],
	[ "X15",            CTX_GPREGS_OFFSET + CTX_GPREG_X15		],
	[ "X16",            CTX_GPREGS_OFFSET + CTX_GPREG_X16		],
	[ "X17",            CTX_GPREGS_OFFSET + CTX_GPREG_X17		],
	[ "X18",            CTX_GPREGS_OFFSET + CTX_GPREG_X18		],
	[ "X19",            CTX_GPREGS_OFFSET + CTX_GPREG_X19		],
	[ "X20",            CTX_GPREGS_OFFSET + CTX_GPREG_X20		],
	[ "X21",            CTX_GPREGS_OFFSET + CTX_GPREG_X21		],
	[ "X22",            CTX_GPREGS_OFFSET + CTX_GPREG_X22		],
	[ "X23",            CTX_GPREGS_OFFSET + CTX_GPREG_X23		],
	[ "X24",            CTX_GPREGS_OFFSET + CTX_GPREG_X24		],
	[ "X25",            CTX_GPREGS_OFFSET + CTX_GPREG_X25		],
	[ "X26",            CTX_GPREGS_OFFSET + CTX_GPREG_X26		],
	[ "X27",            CTX_GPREGS_OFFSET + CTX_GPREG_X27		],
	[ "X28",            CTX_GPREGS_OFFSET + CTX_GPREG_X28		],
	[ "X29",            CTX_GPREGS_OFFSET + CTX_GPREG_X29		],
	[ "X30",            CTX_GPREGS_OFFSET + CTX_GPREG_LR		],
	[ "X31",            CTX_GPREGS_OFFSET + CTX_GPREG_SP_EL0	],
	[ "SCR_EL3",        CTX_EL3STATE_OFFSET + CTX_SCR_EL3		],
	[ "ESR_EL3",        CTX_EL3STATE_OFFSET + CTX_ESR_EL3 		],
	[ "RUNTIME_SP",     CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP 	],
	[ "SPSR_EL3",       CTX_EL3STATE_OFFSET + CTX_SPSR_EL3 		],
	[ "ELR_EL3",        CTX_EL3STATE_OFFSET + CTX_ELR_EL3 		],
	[ "PWRC_EL0",       CTX_EL3STATE_OFFSET + CTX_PMCR_EL0 		],
	[ "SPSR_EL1",       CTX_SYSREGS_OFFSET + CTX_SPSR_EL1		],
	[ "ELR_EL1",        CTX_SYSREGS_OFFSET + CTX_ELR_EL1		],
	[ "SCTLR_EL1",      CTX_SYSREGS_OFFSET + CTX_SCTLR_EL1		],
	[ "ACTLR_EL1",      CTX_SYSREGS_OFFSET + CTX_ACTLR_EL1		],
	[ "CPACR_EL1",      CTX_SYSREGS_OFFSET + CTX_CPACR_EL1		],
	[ "CSSELR_EL1",     CTX_SYSREGS_OFFSET + CTX_CSSELR_EL1		],
	[ "SP_EL1",         CTX_SYSREGS_OFFSET + CTX_SP_EL1		],
	[ "ESR_EL1",        CTX_SYSREGS_OFFSET + CTX_ESR_EL1		],
	[ "TTBR0_EL1",      CTX_SYSREGS_OFFSET + CTX_TTBR0_EL1		],
	[ "TTBR1_EL1",      CTX_SYSREGS_OFFSET + CTX_TTBR1_EL1		],
	[ "MAIR_EL1",       CTX_SYSREGS_OFFSET + CTX_MAIR_EL1		],
	[ "AMAIR_EL1",      CTX_SYSREGS_OFFSET + CTX_AMAIR_EL1		],
	[ "TCR_EL1",        CTX_SYSREGS_OFFSET + CTX_TCR_EL1		],
	[ "TPIDR_EL1",      CTX_SYSREGS_OFFSET + CTX_TPIDR_EL1		],
	[ "TPIDR_EL0",      CTX_SYSREGS_OFFSET + CTX_TPIDR_EL0		],
	[ "TPIDRRO_EL0",    CTX_SYSREGS_OFFSET + CTX_TPIDRRO_EL0	],
	[ "PAR_EL1",        CTX_SYSREGS_OFFSET + CTX_PAR_EL1		],
	[ "FAR_EL1",        CTX_SYSREGS_OFFSET + CTX_FAR_EL1		],
	[ "AFSR0_EL1",      CTX_SYSREGS_OFFSET + CTX_AFSR0_EL1		],
	[ "AFSR1_EL1",      CTX_SYSREGS_OFFSET + CTX_AFSR1_EL1		],
	[ "CONTEXTIDR_EL1", CTX_SYSREGS_OFFSET + CTX_CONTEXTIDR_EL1	],
	[ "VBAR_EL1",       CTX_SYSREGS_OFFSET + CTX_VBAR_EL1		],
]

if __name__ == '__main__':
    import argparse
    parser = argparse.ArgumentParser(description='ramdump image parse')
    parser.add_argument('-r', '--raw_name',
                    action='store_true')
    parser.add_argument('in_filename', help="input filename")
    parser.add_argument('ctx_address', help="Context address", nargs='?',
                        default=0x00000000, type=lambda x: int(x,16))

    args = parser.parse_args()
    with open(args.in_filename, "rb") as f:
        if args.ctx_address == 0:
            for i in range(0, 0x100000):
                blob = f.read(8)
                magic = unpack('<Q', blob)
                if magic[0] == CORE_CONTEXT_MAIGC:
                    f.seek(-8, 1)
                    break;
            pass
        else:
            f.seek(args.ctx_address, 0)
            pass

        for cpu in range(0, 8):
            blob = f.read(75 * 8)
            ctx = unpack(
                '<' + ('Q' * 75), blob)
            if CORE_CONTEXT_MAIGC == ctx[0]:
                print("cpu=%d" % (cpu))
                if (args.raw_name):
                    for regi in reg_name_array:
                        ctx_idx = 2 + (regi[1] >> 3)
                        if (ctx_idx <= 75):
                            print("%15s = 0x%016x" % (regi[0], ctx[ctx_idx]))
                    continue
                for j in range(0, 31):
                    print("x%d=0x%016x" % (j, ctx[j + 2]))
                    pass
                #print("sp=0x%016x" % (ctx[31+ 2]))
                print("sp=0x%016x" % (ctx[74]))
                print("pc=0x%016x" % (ctx[36 + 2]))
                print("pstate=0x%016x" % (ctx[35 + 2]))