/*
 * zgetdump - Tool for copying and converting System z dumps
 *
 * Secure execution/PV guest dump definitions.
 *
 * Copyright IBM Corp. 2022
 *
 * s390-tools is free software; you can redistribute it and/or modify
 * it under the terms of the MIT license. See LICENSE for details.
 */

#ifndef PV_DEFS_H
#define PV_DEFS_H

#include <stdint.h>

#include "lib/zt_common.h"

/* Special ELF section names used for Protected Virtualization Dumps */
#define PV_ELF_SECTION_NAME_COMPL  "pv_compl"
#define PV_ELF_SECTION_NAME_TWEAKS "pv_mem_meta"

/* Maximum size (in bytes) of completion section data */
#define PV_MAX_COMPL_DATA_SIZE ROUNDUP(sizeof(pv_dump_completion_data_v1_t), PAGE_SIZE)
/* Maximum size (in bytes) of section header string table */
#define PV_MAX_SHSTRTAB_SIZE                                                                       \
	ROUNDUP(sizeof(PV_ELF_SECTION_NAME_COMPL) + sizeof(PV_ELF_SECTION_NAME_TWEAKS) +           \
			sizeof(".shstrtab"),                                                       \
		PAGE_SIZE)
/* Maximum size of NT_S390_PV_CPU_DATA */
#define PV_MAX_NT_S390_PV_CPU_DATA_SIZE ROUNDUP(sizeof(pv_cpu_dump_v1_t), PAGE_SIZE)

#define PV_COMPL_DATA_VERSION_1	  ((uint32_t)1)
#define PV_SEC_CPU_DATA_VERSION_1 ((uint32_t)1)

/**
 * pv_tweak_nonce_t:
 *
 * Struct representing a tweak nonce.
 */
typedef struct {
	uint8_t value[16];
} pv_tweak_nonce_t __big_endian;

/**
 * pv_dump_completion_aad_v1_t:
 *
 * Struct representing the authenticated part of a PV dump completion v1
 */
typedef struct {
	uint32_t version;  /* 0000 */
	uint32_t len;	   /* 0004 */
	uint64_t res_0x8;  /* 0008 */
	uint8_t seed[64];  /* 0016 */
	uint8_t iv[12];	   /* 0080 */
	uint32_t res_0x92; /* 0092 */
} pv_dump_completion_aad_v1_t __big_endian;
STATIC_ASSERT(sizeof(pv_dump_completion_aad_v1_t) == 96)

/**
 * pv_dump_completion_confidential_area_v1_t:
 *
 * Struct representing the encrypted part of a PV dump completion v1
 */
typedef struct {
	pv_tweak_nonce_t nonce; /* 0096 */
	union {
		uint8_t key[64]; /* 0112 */
		struct {
			uint8_t key1[32]; /* 0112 */
			uint8_t key2[32]; /* 0144 */
		};
	};
	uint8_t res_0x176[96]; /* 0176 */
} pv_dump_completion_confidential_area_v1_t __big_endian;
STATIC_ASSERT(sizeof(pv_dump_completion_confidential_area_v1_t) == 176)

/**
 * pv_dump_completion_data_v1_t
 *
 * Struct to interpret the data returned by the `Complete Configuration Dump` UVC.
 */
typedef struct {
	pv_dump_completion_aad_v1_t aad;			     /* 0000 */
	pv_dump_completion_confidential_area_v1_t confidential_area; /* 0096 */
	uint8_t tag[16];					     /* 0272 */
								     /* 0288 */
} pv_dump_completion_data_v1_t __big_endian;
STATIC_ASSERT(sizeof(pv_dump_completion_data_v1_t) == 288)

/* Container data structures used to implement polymorphic behavior */
#define PV_STRUCT_NAME(_struct, _version) _struct##_v##_version##_t
#define PV_GET_STRUCT_DATA(_struct, _version, _container)                                          \
	_container->version != _version ?                                                          \
		NULL :                                                                             \
		&(((PV_STRUCT_NAME(_struct, _version) *)_container)->data)

#define PV_GET_DUMP_DATA_V1(_container) PV_GET_STRUCT_DATA(pv_dump_completion, 1, _container)

typedef struct {
	unsigned int version;
} pv_dump_completion_t;

typedef struct {
	pv_dump_completion_t super;
	pv_dump_completion_data_v1_t data;
} PV_STRUCT_NAME(pv_dump_completion, 1);

/**
 * pv_cpu_vector_register_t:
 *
 * Struct representing the PV CPU vector register
 */
typedef struct {
	uint64_t low;
	uint64_t high;
} pv_cpu_vector_register_t __big_endian;
STATIC_ASSERT(sizeof(pv_cpu_vector_register_t) == 16)

/**
 * pv_cpu_dump_aad_v1_t:
 *
 * Struct representing the authenticated part of a PV cpu dump v1
 */
typedef struct {
	uint32_t version;     /*  0000 */
	uint32_t len;	      /*  0004 */
	uint8_t iv[12];	      /*  0008 */
	uint8_t res_0x20[12]; /*  0020 */
} pv_cpu_dump_aad_v1_t __big_endian;
STATIC_ASSERT(sizeof(pv_cpu_dump_aad_v1_t) == 32)

/**
 * pv_cpu_dump_confidential_area_v1_t:
 *
 * Struct to interpret the Secure CPU Dump Area UVC.
 */
typedef struct {
	uint8_t gprs[128];    /* 0032 */
	uint8_t psw[16];      /* 0160 */
	uint8_t res_0x176[8]; /* 0176 */
	uint32_t prefix;      /* 0184 */
	uint32_t fpc;	      /* 0188 */
	uint8_t res_0x192[4]; /* 0192 */
	uint32_t todpreg;     /* 0196 */
	uint64_t timer;	      /* 0200 */
	uint64_t todcmp;      /* 0208 */
	uint8_t res_0x216[8]; /* 0216 */
	uint8_t acrs[64];     /* 0224 */
	uint8_t ctrs[128];    /* 0288 */
	struct {
		pv_cpu_vector_register_t vector_register_low[16];
		uint8_t vector_register_high[256];
	};			/* 0416 */
	uint8_t res_0x928[512]; /* 0928 */
	uint8_t zeros_2[8];	/* 1440 */
	uint64_t gsd;		/* 1448 */
	uint64_t gssm;		/* 1456 */
	uint64_t gs_epl_a;	/* 1464 */
	uint8_t res_0x1472[64]; /* 1472 */
	union {
		struct {
			uint16_t has_osii : 1;
			uint16_t reserved : 15;
		};
		uint16_t dump_flags; /* 1536 */
	};
	uint8_t res_0x1538[6]; /* 1538 */
	uint8_t res_0x1544[8]; /* 1544 */
} pv_cpu_dump_confidential_area_v1_t __big_endian;
STATIC_ASSERT(sizeof(pv_cpu_dump_confidential_area_v1_t) == 1520)

/**
 * pv_cpu_dump_v1_t:
 *
 * Struct representing a PV CPU dump v1 returned by the `Dump CPU state` UVC.
 */
typedef struct {
	pv_cpu_dump_aad_v1_t aad;			      /* 0000 */
	pv_cpu_dump_confidential_area_v1_t confidential_area; /* 0032 */
	uint8_t tag[16];				      /* 1552 */
} pv_cpu_dump_v1_t __big_endian;
STATIC_ASSERT(sizeof(pv_cpu_dump_v1_t) == 1568)

/* PV special tweak component indicator */
#define PV_SPECIAL_INDICATOR 0xFFFFFFFFUL

/**
 * pv_special_tweak_component_layout_t:
 *
 * Struct representing the layout of a special tweak component.
 */
typedef struct {
	uint32_t indicator;
	uint8_t reserved[10];
	uint8_t flag_reserved1;
	uint8_t flag_reserved2 : 5;
	uint8_t is_mapped_page : 1;
	uint8_t is_shared_page : 1;
	uint8_t is_zero_page   : 1;
} pv_special_tweak_component_layout_t __big_endian;
STATIC_ASSERT(sizeof(pv_special_tweak_component_layout_t) == 16)

/**
 * pv_tweak_component_t:
 *
 * Struct representing a tweak component returned by `Dump Configuration Storage State` UVC.
 */
typedef union {
	uint8_t value[16];
	pv_special_tweak_component_layout_t special;
} pv_tweak_component_t __big_endian;
STATIC_ASSERT(sizeof(pv_tweak_component_t) == 16)

/**
 * pv_tweak_t:
 *
 * Struct representing one tweak value.
 */
typedef struct {
	uint8_t value[16];
} pv_tweak_t;
STATIC_ASSERT(sizeof(pv_tweak_t) == 16)

STATIC_ASSERT(sizeof_field(pv_tweak_t, value) == sizeof_field(pv_tweak_component_t, value))
STATIC_ASSERT(sizeof_field(pv_tweak_t, value) == sizeof_field(pv_tweak_nonce_t, value))

#endif /* PV_DEFS_H */
