/*  *********************************************************************
    *  ASTRIS - Remote JTAG probe
    *
    *  Internal API header			File: astris_internal.h
    *
    *  Astris' private API is defined here
    *
    *********************************************************************
    *
    *  Copyright (C) 2009-2020 Apple Inc. All rights reserved.
    *
    *  This document is the property of Apple Inc.
    *  It is considered confidential and proprietary.
    *
    *  This document may not be reproduced or transmitted in any form,
    *  in whole or in part, without the express written permission of
    *  Apple Inc.
    ********************************************************************* */

#ifndef _ASTRIS_INTERNAL_H
#define _ASTRIS_INTERNAL_H

#include "astris_api.h"

#include "csprotocol_shared.h"
#include "astris_arm.h"

#include <netinet/in.h>
#include <sys/socket.h>

#include <sqlite3.h>

#include "astris_machine.h"
#include "astris_concurrency.h"

// Needed for one function defintion
#include <CoreFoundation/CoreFoundation.h>
#include <os/log.h>

#include "astris_CF.h"

/*  *********************************************************************
    *  Constants
    ********************************************************************* */

/* Make certain that IS_ASTRIS_LITE_API is defined to have some value. */
#ifndef IS_ASTRIS_LITE_API
#define IS_ASTRIS_LITE_API 0
#endif

#define JTAG_MAXCHIPS 16 /* XXX belongs somewhre else */

/*  *********************************************************************
    *  Astris Structures
    ********************************************************************* */

/*
 * Types of data structures:
 *
 * AXconn_t - Astris Connection
 * AXchip_t - Chip along the connected JTAG chain (can be a single SWD entry)
 * AXdp_t   - ARM debug port associated with chip
 * AXap_t   - ARM acccess port connected to debug port
 * AXmemap_t - Mem-AP (subclass of AX_ap_t)
 * AXjtagap_t - JTAG-AP (subclass of AX_ap_t)
 */

/* Flags moved to astris_api.h */

/* AXchip: A single entity along a JTAG chain, or in the case of SWD, the only one */
struct AXchip_s {
    int            identity;       /* Chip's identity, or -1 if not known */
    uint32_t       pid;            /* Chip's PID */
    uint32_t       flags;          /* Flags about this chip */
    AXconn_t      *conn;           /* back pointer to connection */
    AXdp_t        *dp;             /* Debug Port, if applicable */
    jtagchip_t     chip;           /* JTAG information (for JTAG mode) */
    void          *soc;            /* Opaque pointer to SOC object */
    void          *interface_1500; /* Opaque pointer to a JTAG 1500 interface object */
    void          *ide_table;      /* Opaque pointer to the object that contains the explore KIS table */
    AXmemaddr_t    ide_base;       /* Base of IDE table for this chip */
    AXhang_info_t *hang_info;
    void          *tap_mux;        /* TAP-MUX Interface */
};

/* AXmemap: An ARM MEM-AP */
struct AXmemap_s {
    uint32_t dbgbase; /* Debug register (or ROM table) base */
    uint32_t cfgreg;  /* Configuration register */
    uint32_t csw_cached;
};

#define AXJTAGAP_MAXPORTS 8
#define AXJTAGAP_MAXCHIPS JTAG_MAXCHIPS

struct AXjtagap_port_s {
    uint32_t  port;                     /* JTAG-AP port # */
    int       nchips;                   /* # of chips */
    AXchip_t *chips[AXJTAGAP_MAXCHIPS]; /* Chips behind this port */
};

/* AXjtagap: An ARM JTAG-AP */
struct AXjtagap_s {
    AXjtagap_port_t *ports[AXJTAGAP_MAXPORTS]; /* We allocate these as needed */
};

/* AXPortal Struct, this struct is not set so no real documenation. This
is a mockup of what we might need for a portal struct */
struct AXportal_s {
    uint8_t         id;
    uint8_t         ver;
    bool            busy;
    uint32_t        status;        /* Portal Statu */
    AXmemaddr_t     base_addr;
    AXportal_name_t name; /* Portal name, DCM/IDE/JTAG/ */
};

/* AXap: Top-level access port (one per select off the DP) */
#define AXAP_DEBUG_READY    0x80000000  /* set if we're good to issue I/Os to AXI/APB/AHB space */
#define AXAP_TYPE_MEMAP     0x40000000
#define AXAP_TYPE_MEMAP_APB 0x00000001
#define AXAP_TYPE_MEMAP_AHB 0x00000002
#define AXAP_TYPE_MEMAP_AXI 0x00000004
#define AXAP_TYPE_JTAGAP    0x00000010

struct AXap_s {
    uint32_t idr;    /* IDR from AP */
    uint32_t select; /* SELECT field for this AP */
    uint32_t flags;  /* Everyone needs flags */
    AXdp_t  *dp;     /* owning debug port */
    union {
        AXmemap_t  memap;
        AXjtagap_t jtagap;
    } ap;
};

/* AXdp: top-level debug port (one per chip) */
#define AXDP_MAX_AP    16
#define AXDP_TYPE_JTAG 0x00000001
#define AXDP_TYPE_SWD  0x00000002

struct AXdp_s {
    unsigned int flags;            /* Type of Debug Port */
    AXchip_t    *chip;             /* owning chip */
    int          apcnt;            /* # of APs */
    AXap_t       aps[AXDP_MAX_AP]; /* APs attached to this DP */
};


struct AXprobeV2_s {
    AXprobe_t probeV1;
    uint32_t primateLoc;
    uint32_t primateHubLoc;
    uint32_t kisLoc;
    uint32_t kisHubLoc;
};

/*  *********************************************************************
    *  Debug components
    ********************************************************************* */

enum {
    K_DBGCOMP_CPU,
    K_DBGCOMP_META,
    K_DBGCOMP_UNKNOWN,
};

#define MAX_TGT_PATH 64
struct AXtgt_s {
    AXchip_t   *chip;    /* always has a chip (might be same as ap->dp->chip) */
    AXap_t     *ap;      /* only valid if this is behind an AP */
    AXmemaddr_t address; /* AXI address, APB address, or JTAG-AP port */
    int         type;
    void       *data;
    char        path[MAX_TGT_PATH];
    const char *type_hint;
};

// CPU assertion areas (used to uniquely ID specific areas within CPU hierarchy)
#define AXA_AREA_CPU_ARM      (AXA_AREA_CPU | (AXA_AREA_CPU + 1))
#define AXA_AREA_CPU_ARM7     (AXA_AREA_CPU_ARM | (AXA_AREA_CPU + 2))
#define AXA_AREA_CPU_ARM7M    (AXA_AREA_CPU_ARM7 | (AXA_AREA_CPU + 3))
#define AXA_AREA_CPU_ARM32    (AXA_AREA_CPU | (AXA_AREA_CPU + 4))
#define AXA_AREA_CPU_ARM64    (AXA_AREA_CPU | (AXA_AREA_CPU + 5))
#define AXA_AREA_CPU_ARM64CYC (AXA_AREA_ARM64 | (AXA_AREA_CPU + 6))

struct AXcpu_s {
    AXconn_t *info;
    AXtgt_t  *tgt;
    AXap_t   *ap;
    int       status;
    int       index;
    int       group;
    void     *state;
    char     *name;
    char     *subsystem;

    pthread_mutex_t mutex;
};

/*  *********************************************************************
    *  META cpu structure
    ********************************************************************* */

#define AXCONN_MAXMETA 4

struct AXmeta_s {
    const char *name;
    AXchip_t   *chip;
    uint16_t    j_img;
    int         is_mtx;
};

/*  *********************************************************************
    *  CS Protocol Control
    ********************************************************************* */

/* use a portion of the cs_id field to maintain a unique ID per transaction */
#define CS_PROTO_MSK_UNIQUE 0x3F
#define CS_PROTO_MIN_UNIQUE 0x01
#define CS_PROTO_MAX_UNIQUE 0x3F

#define CS_RSP_MAX_DRAIN 1 /* maximum number of packets to be drained */

typedef struct AXstatus_cs_s {
    uint8_t     req_unique;         /* last unique ID sent in a request */
    int         rsp_drain_packets;  /* total number of packets to be drained */
    cscommand_t rsp_drain_cmd;      /* area where command response read to on drain */
    int         rsp_drain_cmd_rcvd; /* bytes of command response already drained */
    uint8_t    *rsp_drain_buf;      /* area where payload buffer read to on drain */
    int         rsp_drain_buf_size; /* total byte size of payload receive buffer */
    int         rsp_drain_buf_rcvd; /* bytes of payload buffer already drained */
} AXstatus_cs_t;

/*  *********************************************************************
    *  Astris Connection
    ********************************************************************* */

#define ASTRIS_STATE_IDLE      0
#define ASTRIS_STATE_CONNECTED 1

#define AXCONN_CONNECT_RETRIES 0

#define AXCONN_MAXCHIPS JTAG_MAXCHIPS

#define AXCONN_MAXTGTS 256
#define AXCONN_MAXCPUS 256

#define AXCONN_MAXAVOID 64

#define AXCONN_MAXREPLY 16384

/* MAX Portals is actually 256 but we are using top bit of select
 to mask the portal id, so we loose half the possible portal ids,
 but 128 should be more than enough.
 */
#define  AXCONN_MAXPORTALS 128

#define AXSPEW(flg, args...) ax_os_log(AXLOG_M_ ## flg, AXL_LVL_LOW, args)

#define AXCONN_DFU_REG_CACHE_SZ 8

typedef struct AXavoid_s {
    int          type;
    unsigned int value;
} AXavoid_t;

struct AXconn_s {
    int state; /* Current state of connection */
#ifdef INCLUDE_KEXT_CONNECT
    io_connect_t kext_connect; /* reference to kext connect object, if available */
#endif /* INCLUDE_KEXT_CONNECT */
    int                     fd;         /* socket to probe, if available */
    struct sockaddr_storage remhost;    /* remote host and port (IPV4 or IPV6) */
    csversion_t             remversion; /* Remote Astris version info */
    char                   *hostname;   /* Probe's resolved hostname
                     * [unique part of probe-specific log fname] */
    char *showname;                     /* Version of hostname used for display */
    char *probe_host;                   /* name of host providing access to probe
                     * NULL = device provided by localhost */
    char *probe_address;                /* resolved address that host name equates to
                     * (if probe_host != NULL); else IP addr from user */
    char *probe_match;                  /* probe name match string */
    int   probe_port;                   /* port number used to access probe device */
    int   probe_interface;              /* interface index (IPV6 link local) */
    char *probe_name;                   /* specific probe name that was selected */
    bool  kick_requested;               /* true when probe server has requested kick */
    char *connect_desc;                 /* results of most recent connect attempt */
    bool  single_port;                  /* true when connected to probe-relay over single_port protocol */

    bool adiv6;                          /* true when the DAP is ADIv6 */

    int      exploreflags; /* Flags to govern exploration */
    uint32_t connectflags;

    int       nchips;                 /* total # of chips */
    AXchip_t *chips[AXCONN_MAXCHIPS]; /* Array of chips */

    int      ntgts;                /* total # of targets */
    AXtgt_t *tgts[AXCONN_MAXTGTS]; /* Array of targets */

    int      ncpus;                /* Total # of CPUs */
    AXcpu_t *cpus[AXCONN_MAXCPUS]; /* Array of CPUs */

    int       navoid;                 /* Total # of avoid rules */
    AXavoid_t avoid[AXCONN_MAXAVOID]; /* avoid rules */

    int         nportals;                   /* Total # of Portals */
    AXportal_t *portals[AXCONN_MAXPORTALS]; /* Array of Portals */

    int  bypass_channel;
    bool no_force_pins;  /* true when user explicitly tells us not to force KIS-STM SWD-Bypass pin cfg */

    /*
     * CS Protocol control
     */

    AXstatus_cs_t cs_status; /* tracking the status of CS protocol communication */
    int           xfer_timeout;

    // Concurrency

    astris_concurrency_t *m_concurrency;

    /*
     * Mutex-related stuff for multi-threading
     */

    pthread_mutex_t     mutex;      /* High-level transaction mutex */
    pthread_mutex_t     cmdmutex;   /* low-level transaction mutex */
    pthread_mutexattr_t mutexattr;
    void               *batch_attitude_owner; /* current owner of the cmdmutex */
    pthread_key_t       batch_attitude_key;   /* thread-specific batch attitude key */
    int                 batch_cmd_count;

    /*
     * GDB server information
     */

    void *gdb_data;

    /*
     * Remote environment variables
     */

    AXenvset_t *envsets[4]; /* environment variable sets */

    /*
     * Target database connection.
     */
    sqlite3 *db;

    /*
     * Reply string for api calls that return cstring values.
     */
    char reply[AXCONN_MAXREPLY];

    /*
     * Logging domain for astris connection context.
     */
    const char *axl;

    /*
     * Manually controlled additional spew logging
     */
    uint64_t manual_spew; /* low-level spew under manual control */

    /*
     * DAP error handling control.
     */
    bool ignore_dapcmd_error;

    /*
     * BoosterManager Util
     */
    void *booster_util;

    void              *preferences;
    void              *bypass_setup;
    AXkisdockchannel_t stm_dockch_info;
    bool               enable_stm_dockch;

    /*
     * DFU operation partially complete - finalization needed
     */
    bool     dfu_in_progress;
    uint64_t dfu_cached_regs[AXCONN_DFU_REG_CACHE_SZ];

    bool crash_on_probetimeout;
};

/*  *********************************************************************
    *  Astris command
    *  This structure is used to pass args to the network transaction
    *  code.
    ********************************************************************* */

typedef struct astris_cmd_s {
    cscommand_t cmd;
    uint8_t    *cmdbuf;
    int         cmdlen;

    cscommand_t resp;
    uint8_t    *respbuf;
    int         resplen;
} astris_cmd_t;

/*  *********************************************************************
    *  Astris Value-String Map
    *  These structures are used to describe a 1-to-1 mapping
    *  between a value and string.
    ********************************************************************* */

typedef struct axstr_map_s {
    int         mapValue;
    const char *mapString;
} axstr_map_t;

typedef struct axstr_text_map_s {
    axstr_map_t map;
    const char *mapText;
    uint64_t    mapIndications;
} axstr_text_map_t;

/*  *********************************************************************
    *  Astris SoC Ids
    *
    *  This enumeration provides symbolic ids for the SoC models known
    *  by Astris.
    *
    *  The ordering of this enumeration implicitly defines the order
    *  in which the match criteria will be tested during
    *  identification.  Given that this is the case, it is probably
    *  best practice to place newest and/or most common SoCs earliest
    *  in the list (TODO: <rdar://problem/15759232>).
    *
    *  Note that each of these enumerated ids should have a
    *  corresponding id->string entry added to 'match_entry_name'
    *  array as well as a match criterion added to the 'match' array,
    *  both of which are defined in '.../api/src/astris_identify.c'.
    */

enum astris_soc_id {
#if !IS_ASTRIS_LITE_API
    Apple_H5P,
    Apple_Bali,
    Apple_Alcatraz,
    Apple_AlcatrazTAP,
    Apple_Fiji,
    Apple_Capri,
    Apple_S3E,
    Apple_S3X,
    Apple_S4E,
    Apple_Seagull,
    Apple_S5E,
    Apple_M7,
    Apple_M8,
    Apple_M8W,
    Apple_M8P,
    Apple_M9,
    Apple_Maui,
    Apple_Elba,
    Apple_Malta,
    Apple_Cayman,
    Apple_Myst,
    Apple_Gibraltar,
    Apple_Skye,
    Apple_Cyprus,
    Apple_Aruba,
    Apple_Tinos,
    Apple_Tesla,
    Samsung_G1,
    Apple_Hearst,
    Apple_Bancroft,
    Apple_Cebu,
    Apple_Sicily,
    Apple_Tonga,
    Apple_Avus,
    Apple_Turks,
    Apple_Golay,
    Apple_Spa,
    Apple_JadeChop,
    Apple_Jade,
    Apple_Jade2C,
    Apple_Cota,
    RaspberryPi_BCM2837,
    Apple_Durant,
    Apple_BennuTC,
    Apple_Bora,
    Apple_DurantTC,
    Apple_Sera,
    Apple_Simetra,
    Apple_Ellis,
    Apple_Lifuka,
    Apple_Monaco,
    Apple_Sochi,
    Apple_Maverick,
    Apple_MaverickCM0p,
    Apple_Bennu,
    Apple_Aintree,
    Apple_Staten,
    Intel_Xgold766,
    Apple_Laguna,
    Apple_Crete,
    Apple_RhodesChop,
    Apple_Rhodes1C,
    Apple_Rhodes2C,
    Apple_Stowe,
    Apple_Vale,
    Apple_Helike,
    Apple_HelikeTC,
    Apple_Arche,
    Apple_Baku,
    Apple_ChanningTC,
    Apple_Firebird,
    Apple_Leda,
    Apple_Carpo,
    Apple_Channing,
    Apple_Ibiza,
    Apple_Mirabeau,
    Apple_Lobos,
    Apple_Palma1C,
    Apple_Palma2C,
    Apple_PalmaCr,
    Apple_Coll,
    Apple_Caicos,
    Apple_Thebe,
    Apple_Estoril,
    Apple_Chapel,
    Apple_Sebring,
    Apple_Donan,
    Apple_Orchestra,
    Apple_Spitfire,
    Apple_Abbey,
    Apple_Club,
    Apple_Tahiti,
    Apple_Brava,
    Apple_BravaChop,
    Apple_Este,
    Apple_Pandia,
    Apple_Ananke,
    Apple_Proxima,
    Apple_Tupai,
    Apple_S6E,
    Apple_Specter,
#endif // !IS_ASTRIS_LITE_API
    Misc_CortexM,
    Misc_CortexM_AHB5,
    MAX_MATCH_ENTRY,
};

#if !IS_ASTRIS_LITE_API
static const uint64_t K_CYPRUS_PID     = 0x0C848B;
static const uint64_t K_ARUBA_PID      = 0x1C848B;
static const uint64_t K_CEBU_PID       = 0x0C848C;
static const uint64_t K_SICILY_PID     = 0x0C8880;
static const uint64_t K_TONGA_PID      = 0x0C8881;
static const uint64_t K_TURKS_PID      = 0x0C8900;
static const uint64_t K_JADECHOP_PID   = 0x0C8B00;
static const uint64_t K_JADE_PID       = 0x0C8B01;
static const uint64_t K_JADE2C_PID     = 0x0C8B02;
static const uint64_t K_DURANT_PID     = 0x0C8A03;
static const uint64_t K_ELLIS_PID      = 0x0C8882;
static const uint64_t K_BENNU_PID      = 0x0C8A05;
static const uint64_t K_STATEN_PID     = 0x0C8883;
static const uint64_t K_CRETE_PID      = 0x0C8884;
static const uint64_t K_COLL_PID       = 0x0C8886;
static const uint64_t K_RHODESCHOP_PID = 0x0C8B03;
static const uint64_t K_RHODES1C_PID   = 0x0C8B04;
static const uint64_t K_RHODES2C_PID   = 0x0C8B05;
static const uint64_t K_LEDA_PID       = 0x0C8A80;
static const uint64_t K_CHANNING_PID   = 0x0C8A07;
static const uint64_t K_IBIZA_PID      = 0x0C8885;
static const uint64_t K_LOBOS_PID      = 0x0C8B06;
static const uint64_t K_CAICOS_PID     = 0x0C8902;
static const uint64_t K_PALMA1C_PID    = 0x0C8B07;
static const uint64_t K_PALMA2C_PID    = 0x0C8B08;
static const uint64_t K_DONAN_PID      = 0x0C8887;
static const uint64_t K_PALMACR_PID    = 0x0C8B10;
static const uint64_t K_TAHITI_PID     = 0x0C8888;
static const uint64_t K_BRAVA_PID      = 0x0C8B12;
static const uint64_t K_BRAVACHOP_PID  = 0x0C8B11;
static const uint64_t K_S6E_PID        = 0x0C8536;
#endif // if !IS_ASTRIS_LITE_API

#define INVALID_TAP_IDCODE ((uint32_t)-1)

/*  *********************************************************************
    *  Internal routines
    ********************************************************************* */

__BEGIN_DECLS

void astris_lock(AXconn_t *info);
void astris_unlock(AXconn_t *info);

int astris_convert_tckrate(const char *raw_tckrate, uint32_t *parsed_tckrate);

int  astris_probenav_list(AXconn_t *info, const char *connectName, AXprobe_t **probeList, int *probeCount);
void astris_probenav_list_free(AXprobe_t *probelist, int probecount);
int  astris_probenav_select(AXconn_t *info, const char *connectName, bool forceKick, bool inhibitAsk, bool descDetails, int *probeDevPort, bool mapConnection);
int  astris_probenav_kick(AXconn_t *info, const char *connectName, bool forceKick, bool inhibitAsk, int probePort);
int  astris_probenav_probed_command(AXconn_t *info, const char *connectName, int argc, char **argv, char **response);
int  astris_setup_connect(AXconn_t *info, const char *hostname, bool *single_port_connection, unsigned int flags);

//new
int astris_probenav_list_connected(AXconn_t *info, const char *connectName, AXprobe_t **probeList, int *probeCountn);

int astris_probenav_listV2(AXconn_t *info, const char *connectName, AXprobeV2_t **probeList, int *probeCount);
int astris_probenav_listV2_connected(AXconn_t *info, const char *connectName, AXprobeV2_t **probeList, int *probeCount);
void astris_probenav_listV2_free(AXprobeV2_t *probelist, int probecount);
int astris_convert_probe_array_v2_to_v1(AXprobeV2_t *probeListV2, int probeCount, AXprobe_t **probeListV1);

#define K_PROBENAME_KIS     "KIS"
#define K_PROBENAME_KIS_STM "KIS-STM"
#define K_DEFAULT_CONNECT   "usb"
#define K_PROBEMAP_ERR_MSG  "Error:ASTRIS_ERR_BADPARAM(-29)"
#define K_STM_CHANNEL_STR   "#ch-"
#define K_PROBENAME_HPM     "Port"
#define K_PROBENAME_KIS_SEP "#KIS"
#define K_PROBENAME_EXTRA_INFO_START  " ("

/*
    Our probenames usually look like this:
    ChimpSWD-305C37: This is a regular primate probe we have had forever.
    ChimpSWD-306B12#KIS: This is KIS connection backed by a primate probe. These probes can both SWD and KIS.
    KIS-0x1100000#KIS: This is a standalone KIS connection, there is no primate or hub involved here. We use locationid for identifier.
    KIS-STM-013187: Ellis and before KIS bypass connection, there is no channel because we can only talk to one TMS.
    KIS-STM-013187#ch-0: Staten and forward where we can have multiple bypass connections and talk to different TMS lines.
                         We have #ch- to able to identify which TMS the connection is for.
    KIS-0x1100000#KIS (back-right): Standalone KIS connection that was created via HPM calls.

    Port-back-right: This is an HPM connection where there is no probe but this is identifier for ACE on the host system we talking to.


    Prefix & Suffix Explanations:

    Overall you will see that Astris uses # as a special character when its part of the probe
    name to separate probename and extra decorator, we use this for KIS and ch to provide a separator.

    We use () to provide extra info that is not part of actual probe name we want to connect to. There
    is a space separator between each new parentheses clauses ex: ChimpSWD-305C37 (info1) (info2)
    The info should always be at the space seperating the probename and the extra info.
    This info is usually displayed as extra help to the user, however our API is not expected
    to take this info as a way to connect to hostname:probe , we only use the hostname and probe
    and not extra info that is in the parentheses. All the extra info should come AFTER the probe name,
    so anything after the first parentheses, should/will be ignored.


    K_PROBENAME_KIS: [Prefix] Is used on standalone KIS connections when there is no backing primate.
    K_PROBENAME_KIS_STM: [Prefix] Is used when specifying a KIS bypass connection.
    K_STM_CHANNEL_STR: [Suffix] Is used right after KIS-STM-Serial[KIS_STM_CHANNEL_STR], with no space to show the the TMS line.
    K_PROBENAME_HPM: [Prefix] Used to tell the HPM probe

*/

int    astris_server_connect(const char *axlkey, const char *host, int port, int interface, struct sockaddr_storage *remhost, int *sockref);
int    astris_server_read(int fd, bool waitselect, unsigned char *buffer, int bytes, int to_secs, const char *axldomain, int *result);
size_t astris_server_send(int fd, unsigned char *buffer, int bytes, int to_secs, const char *axldomain);

void astris_csprotocol_cleanup(AXconn_t *info);

int astris_check_csprotocol_version(AXconn_t *info, unsigned int flags, uint32_t ver, uint32_t rev);

void astris_connect_lock(AXconn_t *info, const char *name, pthread_mutex_t *mutex);
void astris_connect_unlock(AXconn_t *info, const char *name, pthread_mutex_t *mutex);
bool astris_command_lock(AXconn_t *info);
void astris_command_unlock(AXconn_t *info);
int  astris_batch_attitude_attach(AXconn_t *info);
int  astris_batch_attitude_detach(AXconn_t *info);
int  astris_batch_attitude_cop(AXconn_t *info);
int  astris_batch_attitude_lose(AXconn_t *info);
int  astris_batch_attitude_suspend(AXconn_t *info);
int  astris_batch_attitude_resume(AXconn_t *info);
int  astris_batch_attitude_relax(AXconn_t *info);
int  astris_batch_attitude_destroy(AXconn_t *info);
void astris_batch_attitude_exit(void *thread_specific_key);
int  astris_command(AXconn_t *info, astris_cmd_t *acmd);

/*!
 @function astris_internal_disconnect
 @discussion Sends a CS Protocol GEN,DISCONNECT packet
 but does not disconnect from the server if connected to astrisprobed.
 */
int astris_internal_disconnect(AXconn_t *info);

/*!
 @function astris_send_probe_command
 @discussion Send a PROBED packet to the daemon on a already connected AXconn
 other functions like astris_probenav_probed_command , connect and disconnect from the daemon.
 This function just sends the request string and reads back response from the daemon.
 */
int astris_send_probe_command(AXconn_t *conn, const char *request, char **response);

typedef enum {
    kRelayConnectedNoTarget            = 0,
    kRelayConnectedTarget              = 1,
    kRelayConnectedTargetAndSWDEnabled = 2,
    kRelayConnected10PinTarget         = 3,
} AXrelayConnectedStatus_t;

/*!
 @function astris_conn_check_orientation
 @discussion Uses hostid to check if E75 based cables (Kanzi & Koba) are plugged
 in the right direction. This check can only be done on newest port controllers,
 but still provides a warning messages to our users that something is wrong.
 */
int astris_conn_check_orientation(AXconn_t *conn);

/*!
 @function astris_select_probe
 @discussion this function will talk to probe map to get list of probes, then it will ask user to select a probe.
 Once user selects the probe, it will fill up info->probe_name accordingly. This func will only talk to probemap and
 won't open connection to probedev
 */
int astris_select_probe(AXconn_t *info, const char *hostname, unsigned int flags);

/*!
 @function astris_get_servertime
 @discussion Send a PROBED packet to the daemon on a already connected AXconn
 Sends request for Unix time from probed and reads response.
 */
int astris_get_servertime(AXconn_t *info, int64_t *time_in_seconds);

/*!
 @function astris_get_clientIP
 @discussion Send a PROBED packet to the daemon on a already connected AXconn
 Sends request for client IP from probed and reads response.
 */
int astris_get_clientIP(AXconn_t *info, uint32_t *ip_addr);

/*!
 @function astris_write_hang_crumb
 @discussion Write addr hang crumb to SOC pointed to by chip
 */
int astris_write_hang_crumb(AXchip_t *chip, AXmemaddr_t addr);

#define REVISION_NOT_YET_FETCHED 0xFFFF

// Chip/SOC internal API
bool        astris_chip_identify(AXchip_t *chip);
int         astris_chip_identify_and_explore(AXconn_t *conn, AXchip_t *chip);
const char *astris_chip_type(AXchip_t *chip);
const char *astris_chip_gpu_type(AXchip_t *chip);
const char *astris_chip_rev(AXchip_t *chip);
const char *astris_chip_collateral_name(AXchip_t *chip);
bool        astris_chip_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);
AXap_t     *astris_chip_sysbus_ap(AXchip_t *chip);
int         astris_soc_init(AXchip_t *chip);
int         astris_soc_setup(AXchip_t *chip);
void        astris_soc_release(AXchip_t *chip, bool lost_target);
int         astris_soc_check_stop_clock(AXchip_t *chip);
bool        astris_soc_ide_explore_supported(AXchip_t *chip);
int         astris_soc_enable_acg(AXchip_t *chip, bool on);
int         astris_soc_restore_acg(AXchip_t *chip);
int         astris_soc_addr_in_dram(AXchip_t *chip, AXmemaddr_t adrr, bool *is_dram);
int         astris_soc_is_applesoc(AXchip_t *chip, bool *is_applesoc);
int         astris_soc_set_stop_clock(AXchip_t *chip, bool stop_clock_active);

/*!
 @function astris_identify_load_booster
 @discussion This function doesn't explore the chip, it will try to find match for pid.
 If match found, will load corresponding SoC booster and allocates SoC object. User needs
 to call AXjtag_release to reset and dealloc objects
 */
int astris_identify_load_booster(AXchip_t *chip, uint64_t pid);

/*!
 @function  astris_soc_check_debug_root
 @brief     Read from consistent debug root register to verify basic SoC functionality
 @param[in] chip    pointer to SoC object to check
 @result    ASTRIS_ERR_OK if debug root register is accessable
    ASTRIS_ERR_NOTSUPPORTED if the chip is not an AppleSoC
    ASTRIS_ERR_NOMEM if DRAM access fails
    ASTRIS_ERR_NOTPRESENT if the consistent debug register is NULL
    ASTRIS_ERR_TGTSTATE if we could not access PMGR scratch to retrieve the register address - Fabric is likely hung
    ASTRIS_ERR_INVAL function parameter error
*/
int astris_soc_check_debug_root(AXchip_t *chip);

/*!
 @function  astris_soc_check_ap_watchdog
 @brief     Check SMC AP watchdog timer for exipiration
 @param[in] chip  pointer to chip object
 @param[in,out] panic_str pointer to panic string (if found). Caller must free after use
 @param[in] outdir_path path to save the watchdog information (if found)
 @param[in,out] is_panicked True if the watchdog timer has expired
 */
int astris_soc_check_ap_watchdog(AXchip_t *chip, char **panic_str, char *outdir_path, bool *is_panicked);

/*!
 @function  astris_soc_check_smc_slp
 @brief     Check for an SMC low-power panic
 @param[in] chip  pointer to chip object
 @param[in,out] panic_str pointer to panic string (if found). Caller must free after use
 @param[in] outdir_path path to save the watchdog information (if found)
 @param[in,out] is_panicked True if the SMC SLP panic was detected
 */
int astris_soc_check_smc_slp(AXchip_t *chip, char **panic_str, char *outdir_path, bool *is_panicked);

int astris_print_consistent_debug_entries(AXconn_t *conn, AXchip_t *chip);

/*!
 @function astris_conn_has_kis
 @discussion Just based on info from relays of a connection determine
 if kis is supported.
 */
int astris_conn_has_kis(AXconn_t *conn);

/*!
 @function astris_conn_choose_gateway
 @discussion Same as our API AXconn_choose_gateway, however lets you choose
 if you want to jtag_release to be called. This is most of the time what you want, because
 if you switch to KIS from SWD you need portal objects and such, so you need to rexplore. However,
 if say you want to just switch to primate from KIS, to call relay, or some PROBE specific function
 like that, its safe not to jtag_release as long as you call this function again to return
 to the original gateway after
 @param conn Conn struct that could be gotten via AXconn_create
 @param gateway One of the enum to slecect the gateway
 @param jtag_release True if you want jtag_release to be called.
 */
int astris_conn_choose_gateway(AXconn_t *conn, AXGatewayType_t gateway, bool jtag_release);

/*!
 @function astris_conn_switch_gateways
 @discussion Same as AXconn_switch_gateways , but allows you to not release jtag
 objects. Please read astris_conn_choose_gateway documentation on when its okay to
 not release.
 */
int astris_conn_switch_gateways(AXconn_t *conn, bool jtag_release);

/*!
 @function astris_chip_kis_enable
 @discussion Do specific SoC overrides to enable KIS.
 This used to be the old AXchip_kis_enable public api.
 */
int astris_chip_kis_enable(AXchip_t *chip, bool force_wake);

/*!
 @function astris_chip_kis_disable
 @discussion Do specific SoC overrides to disbale KIS.
 This used to be the old AXchip_kis_disable public api.
 */
int astris_chip_kis_disable(AXchip_t *chip);

/*!
 * @function astris_kis_get_bypass_info
 * @abstract This command will get bypass config that corresponds to pid, bid and bypass_device_name
 * @param conn AXconn_t connection created with AXconn_create
 * @param pid PID that will be used to identify SoC
 * @param bid Board id that will be used to identify product
 * @param bypass_device_name KIS Bypass device name to which KIS-STM probename should be returned
 * @param bypass_config  It holds pointer to AXbypass_config_t structure that we fill out
 */
int astris_kis_get_bypass_info(AXconn_t *conn, uint64_t pid, uint32_t bid, char *bypass_device_name, AXbypass_config_t *bypass_config);

#define WD_PANIC_STR_LEN 20
static const char _wd_panic_string[WD_PANIC_STR_LEN] = "AP Watchdog Expired";
#define SLP_SMC_PANIC_STR_LEN 23
static const char _slp_smc_panic_string[SLP_SMC_PANIC_STR_LEN] = "SLP_SMC panic detected";

static const uint32_t K_DEFAULT_SWD_BREAK_SEQ = 0x3CE7;

/*
    This function and the enum above can easily be moved to public API if needed
    or can be rolled into AXchip_getinfo function.
*/
int astris_chip_get_runtimeenv(AXchip_t *chip, AXruntime_env_t *env);

int astris_addtarget(AXconn_t *info, AXtgt_t *tgt);
int astris_addcpu(AXconn_t *info, AXcpu_t *cpu);

int astris_should_avoid(AXconn_t *info, int type, unsigned int arg);

AXap_t *  astris_explore_ap(AXdp_t *dp, int sel);
int       astris_explore_aps(AXchip_t *chip, int flags);
AXtgt_t  *astris_create_ap_slave(AXap_t *ap, const char *name, AXmemaddr_t base, const char *type_hint);
int       astris_update_ap_slave(AXtgt_t *tgt);
AXmeta_t *astris_create_meta(AXconn_t *conn, AXchip_t *chip, const char *name, uint16_t j_img);

#define RTXCID_MAGIC_UUID 0x64697575 // Spells 'uuid' in reverse

// Function applies region0 unmap and aslr offset.
// This translation is specific to Cortex with mxwrap and return ASTRIS_ERR_NOTSUPPORTED on other cpus
int astris_cpu_r0unmap_and_aslr_translate(AXcpu_t *cpu, AXmemaddr_t va, AXmemaddr_t *translated_va);

int   astris_setup_cpu(AXconn_t *info, AXtgt_t *tgt, const char *name, dbgarch_t arch, uint32_t id, uint32_t implementer, uint32_t partnum);
void  astris_cpu_set_info(AXcpu_t *cpu, const char *name, int group);
void  astris_cpu_release(AXcpu_t *cpu, bool lost_target);
bool  astris_cpu_normal_memory(AXcpu_t *cpu, AXmemaddr_t addr, AXmemaddr_t len);
int   astris_cpu_status(AXcpu_t *cpu, AXcpu_status_t *detailed);
int   astris_cpu_lower_el(AXcpu_t *cpu, uint32_t target_el);
int   astris_cpu_raise_el(AXcpu_t *cpu, uint32_t target_el);
int   astris_cpu_print_regs(AXcpu_t *cpu);
int   astris_cpu_get_select(AXcpu_t *ap, uint32_t *select);
char *astris_cpu_get_subsystem(AXcpu_t *cpu);
int   astris_cpu_set_halting(AXcpu_t *cpu, bool enable);
int   astris_cpu_clear_lockacc(AXcpu_t *cpu);
int   astris_cpu_set_lockacc(AXcpu_t *cpu);
int   astris_cpu_reverse(AXcpu_t *cpu, bool reverse);

int astris_cpu_enter_guarded(AXcpu_t *cpu);
int astris_cpu_exit_guarded(AXcpu_t *cpu);

// will return current guarded status
bool astris_cpu_get_current_guarded_status(AXcpu_t *cpu);

/*
 @function  astris_cpu_name_from_index
 @brief     get CPU name from CPU index by going through SOC _cpus list
 @param[in] chip        pointer to SoC object to check
 @param[in] index       cpu index
 @param[in] cpu_name    char** to cpu name
 @result    ASTRIS_ERR_OK if CPU name found
    ASTRIS_ERR_BADPARAM if chip is NULL
    ASTRIS_ERR_NOTSUPPORTED if the chip is not an AppleSoC
    ASTRIS_ERR_INVAL if no CPU found with index
*/
int astris_cpu_name_from_index(AXchip_t *chip, int index, const char **cpu_name);

void astris_dump_bpwp_info(bpwp_info_t *bpwp_info);

AXtgt_t *astris_setup_placeholder(AXap_t *ap, const char *name, AXmemaddr_t address, const char *type_hint);

/* This is to be used to created named registers like:
    static const struct {
        const AXmemaddr_t addr;
        const char *const name;
    } named_regs[] = {
        NAMED_REG_INITIALIZER(SOC_REG_X)
    }

    Where now there is: {SOC_REG_X, "SOC_REG_X"}
    as def.
*/
#define AXNAMED_REG_INITIALIZER(r) {r, #r}

/* ARMDAP internal routines */
void astris_memap_recovery(AXconn_t *info, jtagchip_t *chip, unsigned int select);
int  astris_dpread(AXconn_t *info, jtagchip_t *chip, unsigned int reg, uint32_t *regval, int nwords);
int  astris_dpwrite(AXconn_t *info, jtagchip_t *chip, unsigned int reg, uint32_t *regval, int nwords);
int  astris_dpabort(AXconn_t *info, jtagchip_t *chip);
int  astris_apread(AXconn_t *info, jtagchip_t *chip, unsigned int select, unsigned int reg, uint32_t *regval, int nwords);
int  astris_apwrite(AXconn_t *info, jtagchip_t *chip, unsigned int select, unsigned int reg, uint32_t *regval, int nwords);

int astris_poll_cmdstat(AXdp_t *dp, uint32_t mask, uint32_t match, uint32_t *regval);

#define MEMAP_BUS_FLG_FIFO 0x01
#define MEMAP_BUS_FLG_INCR 0x02

int astris_memap_bus_read(AXconn_t *info, jtagchip_t *chip, unsigned int select, AXmemaddr_t reg, uint8_t *vals, int size, int *count, unsigned flags);
int astris_memap_bus_write(AXconn_t *info, jtagchip_t *chip, unsigned int select, AXmemaddr_t reg, uint8_t *vals, int size, int *count, unsigned flags);

/*
    Please look at ADN: ADN-22-02-Memap_Improve.md for more info.

    TLDR: These functions configure AP and change the CSW value only if cached is not what we want.
    If you want to configure the CSW yourself then use the old functions above. HOWEVER!! Unless,
    its the KIS API AXportal_xyz calls, then you don't have any reason to use the older functions, and should
    instead use these.
*/
int astris_memap_bus_read_with_cfg(AXconn_t *info, jtagchip_t *chip, unsigned int select, AXmemaddr_t addr, uint8_t *vals, int size, int *count, unsigned flags);
int astris_memap_bus_write_with_cfg(AXconn_t *info, jtagchip_t *chip, unsigned int select, AXmemaddr_t addr, uint8_t *vals, int size, int *count, unsigned flags);

int astris_memap_readvals(AXap_t *ap, AXmemaddr_t busaddr, uint8_t *vals, int size, uint32_t *count, bool fifo);
int astris_memap_writevals(AXap_t *ap, AXmemaddr_t busaddr, uint8_t *vals, int size, uint32_t *count, bool fifo);
int astris_memap_readmemblock(AXap_t *ap, AXmemaddr_t address, uint32_t *length, uint8_t *buffer);
int astris_memap_readmemblock_fast(AXap_t *ap, AXmemaddr_t address, uint32_t *length,uint8_t *buffer);
int astris_memap_writememblock(AXap_t *ap, AXmemaddr_t address, uint32_t *length, uint8_t *buffer);
int astris_memap_read32(AXap_t *ap, AXregaddr_t regaddr, uint32_t *regval);
int astris_memap_write32(AXap_t *ap, AXregaddr_t regaddr, uint32_t regval);
int astris_memap_read64(AXap_t *ap, AXregaddr_t regaddr, uint64_t *regval);
int astris_memap_write64(AXap_t *ap, AXregaddr_t regaddr, uint64_t regval);
int astris_memap_debug_readbuf(AXtgt_t *tgt, AXregaddr_t regaddr, uint32_t *regval, int *nwords);
int astris_memap_debug_writebuf(AXtgt_t *tgt, AXregaddr_t regaddr, uint32_t *regval, int *nwords);
int astris_memap_debug_read(AXtgt_t *tgt, AXregaddr_t regaddr, uint32_t *regval);
int astris_memap_debug_write(AXtgt_t *tgt, AXregaddr_t regaddr, uint32_t regval);
int astris_memap_read_aligning(AXap_t *ap, AXmemaddr_t pa, uint32_t width, uint32_t *length, uint8_t *buffer);

int  astris_jtagap_explore_port(AXap_t *ap, AXjtagap_port_t *jport, jtagchip_t *topo);
int  astris_jtagap_kis_explore_helper(AXap_t *jtag_ap);
void astris_setup_aps_jtag(AXconn_t *conn, AXchip_t *chip);

/*
@function astris_tapmux_pulse_all
@abstract Calls Reset All -> Deselect All -> Reset All
*/
int astris_tapmux_pulse_all(AXchip_t *tap_chip);

/*
@function astris_tapmux_pulse_and_select
@abstract Pulses the chosen eTap and then selects it.
Reset & Select eTap -> Reset eTap -> Clear All -> Reset eTap -> Reset & Select eTap
*/
int astris_tapmux_pulse_and_select(AXchip_t *tap_chip, uint8_t tap_id);

/*
@function astris_tapmux_ir_scan
@abstract Assumes that the ONE eTap is already selected. This function
adds enough bits to bypass the main TAP. Aka it add 1's equal to irlen of main tap.
We currently dont support multiple eTAPs being selected.
*/
int astris_tapmux_ir_scan(AXchip_t *tap_chip, uint8_t tap_id, int cnt, uint8_t *bits);

/*
@function astris_tapmux_reset_all_and_select
@abstract Sets ALL the reset bits for the TAPMUX and sets the select bit for given
eTap. No pulsing is done.
*/
int astris_tapmux_reset_all_and_select(AXchip_t *tap_chip, uint8_t tap_id);

int astris_memap_lmflash(AXconn_t *info, jtagchip_t *chip, unsigned int select, uint32_t flashbase, uint32_t flashcmd, uint32_t offset, uint32_t *data, int nwords);

int astris_corefile_open(const char *filename, void **corekey);
int astris_corefile_readmem(void *corekey, AXmemaddr_t va, void *buf, int bufsize);
int astris_corefile_readreg(void *corekey, int cpu, AXregid_t regid, AXregval_t *regval);
int astris_corefile_close(void *corekey);
int astris_corefile_stitch(const char *component_dir, const char *core_filename, cpu_subtype_t cpusubtype, uint num_cpu);

int astris_logfile_open(const char *filename, void **logkey);
int astris_logfile_readmem(void *logkey, AXmemaddr_t va, void *buf, int bufsize);
int astris_logfile_readreg(void *logkey, int cpu, AXregid_t regid, AXregval_t *regval);
int astris_logfile_close(void *logkey);

char *astris_axlog_date_time(void);
char *astris_axlog_get_base_dir_name(void);

/* CMD Snapshot */
/*!
 @function AXlog_cmd_snapshot_start
 @discussion Start's tracking astris log messages and putting copies into seperate
 queue. It also clears previous messages if another snapshot was taken earlier.
 The purpose of these functions is to collect astris log messages for certain
 period of time like a run of multiple API functions and then get the log.
 */
int AXlog_cmd_snapshot_start(void);

/*!
 @function AXlog_cmd_snapshot_stop
 @discussion Stops a tracking astris log messages, after previous call to start.
 This function will not clear the current queue.
 */
int AXlog_cmd_snapshot_stop(void);

/*!
 @function AXlog_cmd_snapshot_dump
 @discussion After calling to AXlog_cmd_snapshot_stop, this command can be used
 to dump the messages out to stdout.
 */
int AXlog_cmd_snapshot_dump(void);

/*!
 @function AXlog_cmd_snapshot_save
 @discussion After calling to AXlog_cmd_snapshot_stop, this command can be used
 to save the messages to a given file.
 */
int AXlog_cmd_snapshot_save(const char *filename);

/*!
 @function AXlog_cmd_snapshot_clear
 @discussion Explicitly clears the queue, you don't need to use this if you
 are just going to call AXlog_cmd_snapshot_start. However, this function could
 be used to explicitly free memory that the queue is taking part of.
 */
int AXlog_cmd_snapshot_clear(void);

int astris_write_binary_data(AXconn_t *info, const char *buffer, size_t length, const char *output_dir_path, const char *name_prefix, const char *name_ext);

uint32_t astris_get_dft_tap_idcode(uint32_t soc_id);

// Internal Booster API
int astris_booster_cleanup(AXconn_t *conn);
int astris_remove_loaded_cpu_boosters(AXconn_t *conn);
int astris_remove_loaded_soc_boosters(AXconn_t *conn);
int astris_boosters_init_with_paths(AXconn_t *conn, char *boosterpack_paths[], int len);
int cfarray_copy_to_carray(CFArrayRef cf_array, char ***cstr_array, int *list_length);

#define K_CFCONVERT_UINT64_ERROR 0xFFFFFFFFFFFFFFFF

/*
    Takes the paths of where boosters are from old_conn booster manager. Then calls
    init of booster with the new conn and paths from the old conn. Thus initializing
    the same booster system with the same batch of boosters that old conn looked at
    during its init.
*/
int astris_copy_util_init(AXconn_t *new_conn, AXconn_t *old_conn);

// ROM table routines
int astris_romtable_cid(uint64_t *cid, AXconn_t *conn, AXdp_t *dp, AXap_t *ap);
int astris_romtable_pid(uint64_t *pid, AXconn_t *conn, AXdp_t *dp, AXap_t *ap);
int astris_romtable_dump(AXconn_t *conn, AXdp_t *dp, AXap_t *ap, int verbose, int explain);

// Bit manipulation routines
void     astris_swap(uint8_t *data, int num_bytes);
void     astris_bitreverse(uint8_t *data, int num_bytes);   // Reverse all bits in byte string, effectively changing byte order
void     astris_bytereverse(uint8_t *data, int num_bytes);  // Reverse bits in each byte, effectively keeping byte order the same
uint32_t astris_log2(uint32_t num_bits);

/* Internal Portal/KIS API */
int     astris_addportal(AXconn_t *conn, AXportal_t *portal);
void    astris_cleanup_portals(AXconn_t *conn);
void    astris_create_basic_portals(AXconn_t *conn);
int     astris_kis_enable_soc_access(AXconn_t *conn);
int     astris_kis_init_dp(AXchip_t *chip);
uint8_t astris_encode_portal_id_to_select(uint8_t portal_id);
uint8_t astris_decode_portal_id_from_select(uint8_t select);
AXmemaddr_t astris_get_portal_offset(uint8_t portal_id);

int astris_kis_get_translator_ver(AXconn_t *conn, uint32_t *ver);
bool astris_kis_check_translator_ver(AXconn_t *conn, uint32_t min_ver);

// It enables KIS-STM dynamic bypass channel selection. It works only from Staten
// It sends csprotocol packet to insert bypass channel to KIS-STM header
int astris_set_bypass_channel_kis(AXconn_t *conn, uint32_t bypass_channel);

// Send SSTAT value after authentication to daemon to correct max number of stm probes
int astris_set_max_stm_probes(AXconn_t *conn, uint32_t max_stm);

// This will configure KIS to have acccess to Bypass SWD and sets up the PS, TCK and TMS pins
// If force_setup is true, will skip hygiene checks like whether probe is KIS-STM
int astris_soc_setup_bypass_kis(AXchip_t *chip, uint32_t bypass_sel, bool force_setup);

bool astris_chip_identify_kis(AXchip_t *chip, AXmemaddr_t ide_base);
bool astris_identify_chip_using_pid(AXchip_t *chip, uint64_t pid);
int  astris_setup_kis_swd(AXconn_t *conn);
int  astris_cleanup_kis_swd(AXconn_t *conn);
int  astris_stm_explore_ide_get_pid(AXconn_t *conn, uint32_t *pid, uint32_t *bid);
int  astris_stm_identify_setup_booster(AXconn_t *conn, AXchip_t *chip);
int  astris_get_stm_dockch_info(AXconn_t *conn, AXchip_t *chip);
int  astris_ide_explore(AXchip_t *chip, AXmemaddr_t ide_base);
int  astris_ide_get_pid(AXchip_t *chip, uint64_t *pid);
int  astris_ide_get_deid(AXchip_t *chip, uint64_t *deid);
int  astris_ide_get_revision(AXchip_t *chip, uint32_t *rev);
int  astris_ide_get_boardid(AXchip_t *chip, uint32_t *boardid);
int  astris_ide_get_dbgwrap_base(AXchip_t *chip, AXmemaddr_t *dbgwrap_base);
int  astris_ide_get_soc_stop_clock(AXchip_t *chip);
int  astris_ide_explore_release(AXchip_t *chip);
int  astris_ide_get_pid_for_component_at_address(AXchip_t *chip, AXmemaddr_t base, uint32_t *id);
int  astris_ide_get_cpuid_for_component_at_address(AXchip_t *chip, AXmemaddr_t base, uint32_t *id);
int  astris_ide_get_cid1_for_component_at_address(AXchip_t *chip, AXmemaddr_t base, uint32_t *id);
int  astris_ide_get_full_pid_for_component_at_address(AXchip_t *chip, AXmemaddr_t base, uint64_t *pid);
int  astris_ide_dump_all_core_info(AXchip_t *chip);
int  astris_create_cpus_from_ide(AXchip_t *chip);
int  astris_ide_get_da_address(AXchip_t *chip, AXmemaddr_t *da_base);
int  astris_ide_set_cpuid_for_component_at_address(AXchip_t *chip, AXmemaddr_t base, uint32_t midr);
int  astris_ide_replace_or_create_entry_for_component_at_address(AXchip_t *chip, AXmemaddr_t base, uint32_t subsystem_id, uint32_t feature_id, uint32_t component_id, uint32_t location_id,
                                                                 uint64_t PID, uint32_t CID, uint32_t midr, uint32_t type);

int astris_ide_get_cpm_coresight(AXchip_t *chip, AXmemaddr_t cpu_addr, AXmemaddr_t *cpm_addr);

/*!
 @function  astris_dump_kis_component
 @brief     Pretty print to stdout, the component in IDE
 @param[in] comp    This is a pointer to KisDebugComponent_t.
*/
void astris_dump_kis_component(void *comp);

/*!
 @function  astris_ide_compare_with_booster
 @brief     1. Walks IDE and checks the CPU addresses there against, the ones
                in the currently loaded SoC booster plist.
            2. Walks the currently loaded SoC booster plist and checks the
                IDE that these addresses are there.
            Prints out differences to stderr.
 @param[in] chip    AXchip_t pointer representing the loaded SoC.
 @result   ASTRIS_ERR_OK If everything matchs
           ASTRIS_ERR_FAILURE If some components are missing
*/
int astris_ide_compare_with_booster(AXchip_t *chip);

int             astris_ide_get_da_address_per_die(AXchip_t *chip, AXmemaddr_t *da_base, int die);
AXportal_name_t astris_portal_id_to_name(uint8_t portal_id);
const char     *astris_get_str_from_portal_id(uint8_t portal_id);
int             astris_ide_explore_only(AXchip_t *chip, AXmemaddr_t ide_base);
bool            astris_authdebug_timeout_supported(AXchip_t *chip);
bool            astris_probeauth_supported(AXchip_t *chip);
bool            astris_dftauth_supported(AXchip_t *chip);
uint32_t        astris_ide_get_cip_gen_number(AXchip_t *chip);
int             astris_ide_get_parsed_cip_gen_number(AXchip_t *chip, uint8_t *major, uint8_t *minor);

/* Please note some SoCs dont follow this conversion but most H chips do

    For most of our H,G,M chips we used to have 0x200000000 map to 0x0 and 0xC0000000
    so to go from sys to dbg, we would need to subtrack 0x200000000 , and then set
    bits 30 and 31 (even though 31 is ignored on newer designs)

    On J* chip we have different mapping and matters on which config you are talking to
    it might have even a much more different mapping.

    So to handle all these cases, what we are doing is just taking bits [29:0] of
    sys address and then setting bits 30 and 31. On newer designs bits 31 is ignored
    for most things. However, please read above the history and why we are doing this
    this is not a simple mask there is reasoning for it described in the JTAG Gateway specs.

    "In J*, MEMAP1 will have access to these the windows:
    - 0x0280000000 to 0x02BFFF0000 from master-die’s dbgWrap.
    - 0x2280000000 to 0x22BFFF0000 from slave-die’s dbgWrap.

    0x0292300000 -> 0x52300000 or 0xD2300000 since bit 31 is ignored.

    <rdar://problem/46863324>"


    If this fails, we would need to pipe through some kinda command through the
    chip struct but that comes with its own issues where we might need to know the
    offset/conversion before we know the chip.
*/
inline AXmemaddr_t astris_convert_sys_to_dbg(AXmemaddr_t sys_addr)
{
    return (sys_addr & _MM64_MAKEMASK(30, 0)) + 0xC0000000;
}

#define ASTRIS_DBGAP_SEL 1
#define ASTRIS_SYSAP_SEL 4

/* Astris Prefs */
/*
    I kinda wish we can put this and the ASTRIS_PREFS_URL define in astris_api.h
    so its public, but since I am not sure yet how this is all going to be used its not there
    but for future maybe we move there. -- Anatoly

*/
#define ASTRIS_PREFS_TATSU_KEY              CFSTR("TatsuServer")
#define ASTRIS_PREFS_AUTH_DEBUG_USE_SSO_KEY CFSTR("AuthDebugUseSSO")
#define ASTRIS_PREFS_DEFAULT_PRIMATE_KEY    CFSTR("DefaultConnectAddress")
#define ASTRIS_PREFS_LLDB_PACKET_TIMEOUT    CFSTR("LldbPacketTimeout")

int       astris_preferences_init(AXconn_t *conn, const char *prefs_path);
int       astris_preferences_cleanup(AXconn_t *conn);
CFTypeRef astris_preferences_copy(AXconn_t *conn, CFStringRef key);
int       astris_preferences_cpu_monitor_list(AXconn_t *conn, AXchip_t *chip, char ***cpus_to_monitor, int *monitor_length);
int       astris_preferences_subsystem_monitor_list(AXconn_t *conn, char ***subsystem_list, int *length);
int       astris_chip_get_cpus_for_subsystem(AXconn_t *conn, const char *subsystem, char ***cpus, int *length);

/* 1500 Chain */
void astris_1500_interface_release(AXchip_t *chip);

/* Debug Auth */
#if !IS_ASTRIS_LITE_API
bool  astris_debug_auth_is_authenticated(AXchip_t *chip);
int   astris_debug_auth_authenticate(AXchip_t *chip);
int   astris_debug_auth_clear_auth(AXchip_t *chip);
int   astris_debug_auth_enable_test(AXchip_t *chip);
int   astris_debug_auth_enable_timer_ovr(AXchip_t *chip, uint32_t local_load_val);
int   astris_debug_auth_get_timer_count(AXchip_t *chip, uint32_t *count);
int   astris_debug_auth_get_probe_timer_count(AXchip_t *chip, uint32_t *count);
int   astris_debug_auth_get_dft_timer_count(AXchip_t *chip, uint32_t *count);
void *astris_soc_get_debug_auth(AXchip_t *chip);
void *astris_soc_get_auth_eam(AXchip_t *chip);
bool  astris_debug_auth_is_probe_authenticated(AXchip_t *chip);
int   astris_debug_auth_authenticate_probe(AXchip_t *chip);
int   astris_debug_auth_clear_probe_auth(AXchip_t *chip);
bool  astris_debug_auth_is_dft_authenticated(AXchip_t *chip);
int   astris_debug_auth_authenticate_dft(AXchip_t *chip);
int   astris_debug_auth_clear_dft_auth(AXchip_t *chip);

#endif // if !IS_ASTRIS_LITE_API

////////////////////////////////////////////////////////////////////////////////
#pragma mark os_log

/*!
 @defined ASTRIS_OS_LOG_SUBSYSTEM oslog subsystem identifier for astris
 */
#define ASTRIS_OS_LOG_SUBSYSTEM "com.apple.astris"

/*!
 @function astris_os_log_init
 @discussion Initializes the oslog and source structures
 @result astris error code
 */
int astris_os_log_init(void);

/*!
 @function astris_os_log_teardown
 @discussion Cleans up the oslog and source structures
 @result astris error code
 */
int astris_os_log_teardown(void);

/*!
 @function astris_os_log_obj_get
 @discussion Gets the log object mapping to the current log source for the
 thread. Shall only be called after a call to astris_os_log_init.
 @result oslog object to use
 */
os_log_t astris_os_log_obj_get(void);

/*!
 @function astris_os_log_src_push
 @discussion Push a source onto the source stack
 @param src Source to push
 @returns Log source token
 */
astris_os_log_src_token_t astris_os_log_src_push(astris_os_log_src_t src);

/*!
 @function astris_os_log_src_pop
 @discussion Pop and return the current source from the source stack. This will
 return ASTRIS_OS_LOG_SRC_DEFAULT if the stack is empty.
 @param tok Log source token obtained from a call to astris_os_log_src_push
 @result The current source
 */
astris_os_log_src_t astris_os_log_src_pop(astris_os_log_src_token_t *tok);

/*!
 @function astris_os_log_src_retain
 @discussion Push a source onto the source stack if and only if a source isn't
 already set.
 @param src Source to push
 @result log source token
 */
astris_os_log_src_token_t astris_os_log_src_retain(astris_os_log_src_t src);

/*!
 @function astris_os_log_src_release
 @discussion Pop and return the current source from the stack if and only if a
 source has been set through a call to astris_os_log_src_retain.
 @param tok Log source token obtained from a call to astris_os_log_src_push_retain
 @result the current source
 */
astris_os_log_src_t astris_os_log_src_release(astris_os_log_src_token_t *tok);

/*!
 @function astris_os_log_src_peek
 @discussion Get the current souce without removing it from the source stack.
 This will return ASTRIS_OS_LOG_SRC_DEFAULT if the stack is empty.
 @result the current source
 */
astris_os_log_src_t astris_os_log_src_peek(void);

const char *astris_os_log_src_to_str(astris_os_log_src_t src);

/*!
 @function astris_os_log_src_unwind
 @discussion Unwind the stack, i.e. remove all sources. This is intended to be
 used as a chicken bit for when things go badly...
 */
void astris_os_log_src_unwind(void);

//                      AXexc_set_to_log()
//  Description:
//      Set if exception output to go to log.
//  Inputs:
//      to_log
void AXexc_set_to_log(bool to_log);

//                      AXexc_set_to_stdout()
//  Description:
//      Set if exception output to go to stdout.
//  Inputs:
//      to_stdout
void AXexc_set_to_stdout(bool to_stdout);

typedef int (*astris_tcl_interp_print)(const char *channel, char *str, bool add_newline);
/*
    @function astris_set_tcl_logger
    @discussion This function sets alternative print function that is used
    when Astris library is running under TCL interp. The function should
    take a string that is the std channel to log to "stdout" or "stderr", the
    string the log and if a newline should be added to the string if it doesnt
    exist in the end of the string.

    The return value of the function pointer given should be ASTRIS_ERR_OK, if
    the print to stdout happened and anything else if it failed. It if failed
    the logging system will fallback on using regular C runtime stdour,stderr
*/
void astris_set_tcl_logger(astris_tcl_interp_print tcl_logger);

int   astris_soc_cpu_in_complex(AXchip_t *chip, AXcpu_t *cpu);
char *astris_soc_complex_name_contains_cpu(AXchip_t *chip, AXcpu_t *cpu);
int   astris_soc_cpu_complex_halt_only(AXchip_t *chip, const char *complex_name, bool force_halt);
int   astris_soc_cpu_in_acc_complex(AXchip_t *chip, AXcpu_t *cpu, bool *in_acc);

/*!
 @function astris_set_exception
 @discussion Turns off global exceptions, since they are not thread safe. This
 can be used in work around scenarios until: <rdar://problem/35575845> is fixed
 @param val , false to turn exceptions off, and true to turn them back on
 */
void astris_set_exception(bool val);

/*!
 @function astris_cleanup_exception
 @discussion Cleans up the current global exception. This only clears up the internals
 of the exception root. The root itself will be deleted with rest of globals
 on exit.
 */
void astris_cleanup_exception(void);

void  astris_set_exception_root(void *root);
void *astris_get_exception_root();

void astris_exc_bread_init(void);
void astris_exc_bread_enable(void);
void astris_exc_bread_disable(void);
void astris_exc_bread_dump(void);
void astris_exc_bread_reset(void);
int  astris_exc_bread_test(void);

void astris_exc_bread_copy(char **desc);

void astris_log_guard_enable(void);
void astris_log_guard_disable(void);

void astris_hang_info_cleanup(AXchip_t *chip);
int  astris_hang_info_get(AXchip_t *chip, AXhang_info_t **info);
int  astris_hang_info_print(AXchip_t *chip, uint64_t log_category);

/*!
 @function astris_get_macho_list
 @discussion Read debug_header_t struct at offset from VBAR and return
 image[] containing list of virtual addresses for XNU/SPTM/TXM binaries.
 CPU should be halted before calling.
 debug_header_t is defined in Kernel.framework/sptm/debug_header.h,
 which we have copied to external/
 @param cpu CPU selected for debug (cpu selected for coredump)
 @param images Pointer to array to write virtual addresses to.
 Caller is responsible for freeing allocated memory.
 @param count Size of array returned
 */
int astris_get_macho_list(AXcpu_t* cpu, uint64_t** images, int* count);

void astris_jebdump_request(AXconn_t *conn, AXmemaddr_t address, const char *domain, const char *filename, const char *function, int line, const char *fmt, ...);

#define AXJEBDUMP_REQUIRED(conn, address, domain, fmt, ...)      \
    do {astris_jebdump_request(conn, address, domain,            \
                               __FILE__, __FUNCTION__, __LINE__, \
                               fmt "\n",                         \
                               ## __VA_ARGS__);                  \
    } while (0)

#if TARGET_OS_OSX
#if !IS_ASTRIS_LITE_API

#define AXRELAY_HPM_KART_EN_STATUS  "kartEn"
#define AXRELAY_HPM_KART_STATUS_LOWER "kartStatus"
#define AXRELAY_HPM_KART_STATUS_HIGH "kartStatusHigh"
#define AXRELAY_HPM_KART_DEVICE "kartDevice"
#define AXRELAY_HPM_DEBUG_CAPS  "debugCaps"

#define AXRELAY_HPM_RESET_PORT "resetPort"
#define AXRELAY_HPM_RESET_EXT "resetExt"
#define AXRELAY_HPM_KART "kart"
#define AXRELAY_HPM_DFU "dfu"
#define AXRELAY_HPM_KIS "kis"
#define AXRELAY_HPM_DISCONNECT "disconnect"


typedef enum {
    kHpmResetExternalTarget,
    kHpmResetPort,
} AXhpmreset_t;

typedef enum {
    kKartEnabled,
    kDebugCaps,
    kKartStatus,
    kKartDevice,
} AXhpmStatus_t;

int astris_hpm_kart(AXconn_t *conn, uint32_t val);
int astris_hpm_reset(AXconn_t *conn, AXhpmreset_t reset_type);
int astris_hpm_dfu(AXconn_t *conn);
int astris_hpm_kis(AXconn_t *conn);
int astris_hpm_disconnect(AXconn_t *conn, uint16_t sec);
int astris_hpm_status(AXconn_t *conn, AXhpmStatus_t status_type, uint64_t *status);
int astris_hpm_status_decode(AXconn_t *conn, AXhpmStatus_t status_type, uint64_t status, char **desc);
const char * astris_hpm_status_type_str(AXhpmStatus_t status_type);

#endif  // !IS_ASTRIS_LITE_API
#endif  // TARGET_OS_OSX

__END_DECLS

/*  *********************************************************************
    *  Inline functions
    ********************************************************************* */

static inline void astris_setupcmd(astris_cmd_t *cmd, uint16_t type)
{
    cmd->cmd.cs_type   = type;
    cmd->cmd.cs_length = 0;
    cmd->cmd.cs_chip   = 0;
    cmd->cmd.cs_id     = 0;
    cmd->cmd.cs_flags  = 0;
    cmd->cmdbuf        = NULL;
    cmd->cmdlen        = 0;
    cmd->respbuf       = NULL;
    cmd->resplen       = 0;
}

////////////////////////////////////////////////////////////////////////////////
#pragma mark Memory Management Macros

/* Call free() and set the freed pointer value to NULL. */
#define FREE(x)   \
    do {          \
        free(x);  \
        x = NULL; \
    } while (0)

/* If provided pointer exists (is not NULL) then call FREE()
 * to free and set the freed pointer value to NULL. */
#define FREE_EXISTS(x)   \
    do {                 \
        if (x != NULL) { \
            FREE(x);     \
        }                \
    } while (0)

#define CFRELEASE(x) do { \
        if (x != NULL) {  \
            CFRelease(x); \
            (x) = NULL;   \
        }                 \
} while (0)

#define DELETE(x) do { \
        delete x;      \
        (x) = NULL;    \
} while (0)

#define DELETE_EXISTS(x) \
    do {                 \
        if (x) {         \
            delete x;    \
            (x) = NULL;  \
        }                \
    } while (0)

#endif // ifndef _ASTRIS_INTERNAL_H
