cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ccs-data.c (23521B)


      1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
      2/*
      3 * CCS static data binary parser library
      4 *
      5 * Copyright 2019--2020 Intel Corporation
      6 */
      7
      8#include <linux/device.h>
      9#include <linux/errno.h>
     10#include <linux/limits.h>
     11#include <linux/mm.h>
     12#include <linux/slab.h>
     13
     14#include "ccs-data-defs.h"
     15
     16struct bin_container {
     17	void *base;
     18	void *now;
     19	void *end;
     20	size_t size;
     21};
     22
     23static void *bin_alloc(struct bin_container *bin, size_t len)
     24{
     25	void *ptr;
     26
     27	len = ALIGN(len, 8);
     28
     29	if (bin->end - bin->now < len)
     30		return NULL;
     31
     32	ptr = bin->now;
     33	bin->now += len;
     34
     35	return ptr;
     36}
     37
     38static void bin_reserve(struct bin_container *bin, size_t len)
     39{
     40	bin->size += ALIGN(len, 8);
     41}
     42
     43static int bin_backing_alloc(struct bin_container *bin)
     44{
     45	bin->base = bin->now = kvzalloc(bin->size, GFP_KERNEL);
     46	if (!bin->base)
     47		return -ENOMEM;
     48
     49	bin->end = bin->base + bin->size;
     50
     51	return 0;
     52}
     53
     54#define is_contained(var, endp)				\
     55	(sizeof(*var) <= (endp) - (void *)(var))
     56#define has_headroom(ptr, headroom, endp)	\
     57	((headroom) <= (endp) - (void *)(ptr))
     58#define is_contained_with_headroom(var, headroom, endp)		\
     59	(sizeof(*var) + (headroom) <= (endp) - (void *)(var))
     60
     61static int
     62ccs_data_parse_length_specifier(const struct __ccs_data_length_specifier *__len,
     63				size_t *__hlen, size_t *__plen,
     64				const void *endp)
     65{
     66	size_t hlen, plen;
     67
     68	if (!is_contained(__len, endp))
     69		return -ENODATA;
     70
     71	switch (__len->length >> CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) {
     72	case CCS_DATA_LENGTH_SPECIFIER_1:
     73		hlen = sizeof(*__len);
     74		plen = __len->length &
     75			((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1);
     76		break;
     77	case CCS_DATA_LENGTH_SPECIFIER_2: {
     78		struct __ccs_data_length_specifier2 *__len2 = (void *)__len;
     79
     80		if (!is_contained(__len2, endp))
     81			return -ENODATA;
     82
     83		hlen = sizeof(*__len2);
     84		plen = ((size_t)
     85			(__len2->length[0] &
     86			 ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1))
     87			<< 8) + __len2->length[1];
     88		break;
     89	}
     90	case CCS_DATA_LENGTH_SPECIFIER_3: {
     91		struct __ccs_data_length_specifier3 *__len3 = (void *)__len;
     92
     93		if (!is_contained(__len3, endp))
     94			return -ENODATA;
     95
     96		hlen = sizeof(*__len3);
     97		plen = ((size_t)
     98			(__len3->length[0] &
     99			 ((1 << CCS_DATA_LENGTH_SPECIFIER_SIZE_SHIFT) - 1))
    100			<< 16) + (__len3->length[0] << 8) + __len3->length[1];
    101		break;
    102	}
    103	default:
    104		return -EINVAL;
    105	}
    106
    107	if (!has_headroom(__len, hlen + plen, endp))
    108		return -ENODATA;
    109
    110	*__hlen = hlen;
    111	*__plen = plen;
    112
    113	return 0;
    114}
    115
    116static u8
    117ccs_data_parse_format_version(const struct __ccs_data_block *block)
    118{
    119	return block->id >> CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT;
    120}
    121
    122static u8 ccs_data_parse_block_id(const struct __ccs_data_block *block,
    123				       bool is_first)
    124{
    125	if (!is_first)
    126		return block->id;
    127
    128	return block->id & ((1 << CCS_DATA_BLOCK_HEADER_ID_VERSION_SHIFT) - 1);
    129}
    130
    131static int ccs_data_parse_version(struct bin_container *bin,
    132				  struct ccs_data_container *ccsdata,
    133				  const void *payload, const void *endp)
    134{
    135	const struct __ccs_data_block_version *v = payload;
    136	struct ccs_data_block_version *vv;
    137
    138	if (v + 1 != endp)
    139		return -ENODATA;
    140
    141	if (!bin->base) {
    142		bin_reserve(bin, sizeof(*ccsdata->version));
    143		return 0;
    144	}
    145
    146	ccsdata->version = bin_alloc(bin, sizeof(*ccsdata->version));
    147	if (!ccsdata->version)
    148		return -ENOMEM;
    149
    150	vv = ccsdata->version;
    151	vv->version_major = ((u16)v->static_data_version_major[0] << 8) +
    152		v->static_data_version_major[1];
    153	vv->version_minor = ((u16)v->static_data_version_minor[0] << 8) +
    154		v->static_data_version_minor[1];
    155	vv->date_year =  ((u16)v->year[0] << 8) + v->year[1];
    156	vv->date_month = v->month;
    157	vv->date_day = v->day;
    158
    159	return 0;
    160}
    161
    162static void print_ccs_data_version(struct device *dev,
    163				   struct ccs_data_block_version *v)
    164{
    165	dev_dbg(dev,
    166		"static data version %4.4x.%4.4x, date %4.4u-%2.2u-%2.2u\n",
    167		v->version_major, v->version_minor,
    168		v->date_year, v->date_month, v->date_day);
    169}
    170
    171static int ccs_data_block_parse_header(const struct __ccs_data_block *block,
    172				       bool is_first, unsigned int *__block_id,
    173				       const void **payload,
    174				       const struct __ccs_data_block **next_block,
    175				       const void *endp, struct device *dev,
    176				       bool verbose)
    177{
    178	size_t plen, hlen;
    179	u8 block_id;
    180	int rval;
    181
    182	if (!is_contained(block, endp))
    183		return -ENODATA;
    184
    185	rval = ccs_data_parse_length_specifier(&block->length, &hlen, &plen,
    186					       endp);
    187	if (rval < 0)
    188		return rval;
    189
    190	block_id = ccs_data_parse_block_id(block, is_first);
    191
    192	if (verbose)
    193		dev_dbg(dev,
    194			"Block ID 0x%2.2x, header length %zu, payload length %zu\n",
    195			block_id, hlen, plen);
    196
    197	if (!has_headroom(&block->length, hlen + plen, endp))
    198		return -ENODATA;
    199
    200	if (__block_id)
    201		*__block_id = block_id;
    202
    203	if (payload)
    204		*payload = (void *)&block->length + hlen;
    205
    206	if (next_block)
    207		*next_block = (void *)&block->length + hlen + plen;
    208
    209	return 0;
    210}
    211
    212static int ccs_data_parse_regs(struct bin_container *bin,
    213			       struct ccs_reg **__regs,
    214			       size_t *__num_regs, const void *payload,
    215			       const void *endp, struct device *dev)
    216{
    217	struct ccs_reg *regs_base = NULL, *regs = NULL;
    218	size_t num_regs = 0;
    219	u16 addr = 0;
    220
    221	if (bin->base && __regs) {
    222		regs = regs_base = bin_alloc(bin, sizeof(*regs) * *__num_regs);
    223		if (!regs)
    224			return -ENOMEM;
    225	}
    226
    227	while (payload < endp && num_regs < INT_MAX) {
    228		const struct __ccs_data_block_regs *r = payload;
    229		size_t len;
    230		const void *data;
    231
    232		if (!is_contained(r, endp))
    233			return -ENODATA;
    234
    235		switch (r->reg_len >> CCS_DATA_BLOCK_REGS_SEL_SHIFT) {
    236		case CCS_DATA_BLOCK_REGS_SEL_REGS:
    237			addr += r->reg_len & CCS_DATA_BLOCK_REGS_ADDR_MASK;
    238			len = ((r->reg_len & CCS_DATA_BLOCK_REGS_LEN_MASK)
    239			       >> CCS_DATA_BLOCK_REGS_LEN_SHIFT) + 1;
    240
    241			if (!is_contained_with_headroom(r, len, endp))
    242				return -ENODATA;
    243
    244			data = r + 1;
    245			break;
    246		case CCS_DATA_BLOCK_REGS_SEL_REGS2: {
    247			const struct __ccs_data_block_regs2 *r2 = payload;
    248
    249			if (!is_contained(r2, endp))
    250				return -ENODATA;
    251
    252			addr += ((u16)(r2->reg_len &
    253				       CCS_DATA_BLOCK_REGS_2_ADDR_MASK) << 8)
    254				+ r2->addr;
    255			len = ((r2->reg_len & CCS_DATA_BLOCK_REGS_2_LEN_MASK)
    256			       >> CCS_DATA_BLOCK_REGS_2_LEN_SHIFT) + 1;
    257
    258			if (!is_contained_with_headroom(r2, len, endp))
    259				return -ENODATA;
    260
    261			data = r2 + 1;
    262			break;
    263		}
    264		case CCS_DATA_BLOCK_REGS_SEL_REGS3: {
    265			const struct __ccs_data_block_regs3 *r3 = payload;
    266
    267			if (!is_contained(r3, endp))
    268				return -ENODATA;
    269
    270			addr = ((u16)r3->addr[0] << 8) + r3->addr[1];
    271			len = (r3->reg_len & CCS_DATA_BLOCK_REGS_3_LEN_MASK) + 1;
    272
    273			if (!is_contained_with_headroom(r3, len, endp))
    274				return -ENODATA;
    275
    276			data = r3 + 1;
    277			break;
    278		}
    279		default:
    280			return -EINVAL;
    281		}
    282
    283		num_regs++;
    284
    285		if (!bin->base) {
    286			bin_reserve(bin, len);
    287		} else if (__regs) {
    288			if (!regs)
    289				return -EIO;
    290
    291			regs->addr = addr;
    292			regs->len = len;
    293			regs->value = bin_alloc(bin, len);
    294			if (!regs->value)
    295				return -ENOMEM;
    296
    297			memcpy(regs->value, data, len);
    298			regs++;
    299		}
    300
    301		addr += len;
    302		payload = data + len;
    303	}
    304
    305	if (!bin->base)
    306		bin_reserve(bin, sizeof(*regs) * num_regs);
    307
    308	if (__num_regs)
    309		*__num_regs = num_regs;
    310
    311	if (bin->base && __regs) {
    312		if (!regs_base)
    313			return -EIO;
    314
    315		*__regs = regs_base;
    316	}
    317
    318	return 0;
    319}
    320
    321static int ccs_data_parse_reg_rules(struct bin_container *bin,
    322				    struct ccs_reg **__regs,
    323				    size_t *__num_regs,
    324				    const void *payload,
    325				    const void *endp, struct device *dev)
    326{
    327	int rval;
    328
    329	if (!bin->base)
    330		return ccs_data_parse_regs(bin, NULL, NULL, payload, endp, dev);
    331
    332	rval = ccs_data_parse_regs(bin, NULL, __num_regs, payload, endp, dev);
    333	if (rval)
    334		return rval;
    335
    336	return ccs_data_parse_regs(bin, __regs, __num_regs, payload, endp,
    337				   dev);
    338}
    339
    340static void assign_ffd_entry(struct ccs_frame_format_desc *desc,
    341			     const struct __ccs_data_block_ffd_entry *ent)
    342{
    343	desc->pixelcode = ent->pixelcode;
    344	desc->value = ((u16)ent->value[0] << 8) + ent->value[1];
    345}
    346
    347static int ccs_data_parse_ffd(struct bin_container *bin,
    348			      struct ccs_frame_format_descs **ffd,
    349			      const void *payload,
    350			      const void *endp, struct device *dev)
    351{
    352	const struct __ccs_data_block_ffd *__ffd = payload;
    353	const struct __ccs_data_block_ffd_entry *__entry;
    354	unsigned int i;
    355
    356	if (!is_contained(__ffd, endp))
    357		return -ENODATA;
    358
    359	if ((void *)__ffd + sizeof(*__ffd) +
    360	    ((u32)__ffd->num_column_descs +
    361	     (u32)__ffd->num_row_descs) *
    362	    sizeof(struct __ccs_data_block_ffd_entry) != endp)
    363		return -ENODATA;
    364
    365	if (!bin->base) {
    366		bin_reserve(bin, sizeof(**ffd));
    367		bin_reserve(bin, __ffd->num_column_descs *
    368			    sizeof(struct ccs_frame_format_desc));
    369		bin_reserve(bin, __ffd->num_row_descs *
    370			    sizeof(struct ccs_frame_format_desc));
    371
    372		return 0;
    373	}
    374
    375	*ffd = bin_alloc(bin, sizeof(**ffd));
    376	if (!*ffd)
    377		return -ENOMEM;
    378
    379	(*ffd)->num_column_descs = __ffd->num_column_descs;
    380	(*ffd)->num_row_descs = __ffd->num_row_descs;
    381	__entry = (void *)(__ffd + 1);
    382
    383	(*ffd)->column_descs = bin_alloc(bin, __ffd->num_column_descs *
    384					 sizeof(*(*ffd)->column_descs));
    385	if (!(*ffd)->column_descs)
    386		return -ENOMEM;
    387
    388	for (i = 0; i < __ffd->num_column_descs; i++, __entry++)
    389		assign_ffd_entry(&(*ffd)->column_descs[i], __entry);
    390
    391	(*ffd)->row_descs = bin_alloc(bin, __ffd->num_row_descs *
    392				      sizeof(*(*ffd)->row_descs));
    393	if (!(*ffd)->row_descs)
    394		return -ENOMEM;
    395
    396	for (i = 0; i < __ffd->num_row_descs; i++, __entry++)
    397		assign_ffd_entry(&(*ffd)->row_descs[i], __entry);
    398
    399	if (__entry != endp)
    400		return -EPROTO;
    401
    402	return 0;
    403}
    404
    405static int ccs_data_parse_pdaf_readout(struct bin_container *bin,
    406				       struct ccs_pdaf_readout **pdaf_readout,
    407				       const void *payload,
    408				       const void *endp, struct device *dev)
    409{
    410	const struct __ccs_data_block_pdaf_readout *__pdaf = payload;
    411
    412	if (!is_contained(__pdaf, endp))
    413		return -ENODATA;
    414
    415	if (!bin->base) {
    416		bin_reserve(bin, sizeof(**pdaf_readout));
    417	} else {
    418		*pdaf_readout = bin_alloc(bin, sizeof(**pdaf_readout));
    419		if (!*pdaf_readout)
    420			return -ENOMEM;
    421
    422		(*pdaf_readout)->pdaf_readout_info_order =
    423			__pdaf->pdaf_readout_info_order;
    424	}
    425
    426	return ccs_data_parse_ffd(bin, !bin->base ? NULL : &(*pdaf_readout)->ffd,
    427				  __pdaf + 1, endp, dev);
    428}
    429
    430static int ccs_data_parse_rules(struct bin_container *bin,
    431				struct ccs_rule **__rules,
    432				size_t *__num_rules, const void *payload,
    433				const void *endp, struct device *dev)
    434{
    435	struct ccs_rule *rules_base = NULL, *rules = NULL, *next_rule = NULL;
    436	size_t num_rules = 0;
    437	const void *__next_rule = payload;
    438	int rval;
    439
    440	if (bin->base) {
    441		rules_base = next_rule =
    442			bin_alloc(bin, sizeof(*rules) * *__num_rules);
    443		if (!rules_base)
    444			return -ENOMEM;
    445	}
    446
    447	while (__next_rule < endp) {
    448		size_t rule_hlen, rule_plen, rule_plen2;
    449		const u8 *__rule_type;
    450		const void *rule_payload;
    451
    452		/* Size of a single rule */
    453		rval = ccs_data_parse_length_specifier(__next_rule, &rule_hlen,
    454						       &rule_plen, endp);
    455
    456		if (rval < 0)
    457			return rval;
    458
    459		__rule_type = __next_rule + rule_hlen;
    460
    461		if (!is_contained(__rule_type, endp))
    462			return -ENODATA;
    463
    464		rule_payload = __rule_type + 1;
    465		rule_plen2 = rule_plen - sizeof(*__rule_type);
    466
    467		switch (*__rule_type) {
    468		case CCS_DATA_BLOCK_RULE_ID_IF: {
    469			const struct __ccs_data_block_rule_if *__if_rules =
    470				rule_payload;
    471			const size_t __num_if_rules =
    472				rule_plen2 / sizeof(*__if_rules);
    473			struct ccs_if_rule *if_rule;
    474
    475			if (!has_headroom(__if_rules,
    476					  sizeof(*__if_rules) * __num_if_rules,
    477					  rule_payload + rule_plen2))
    478				return -ENODATA;
    479
    480			/* Also check there is no extra data */
    481			if (__if_rules + __num_if_rules !=
    482			    rule_payload + rule_plen2)
    483				return -EINVAL;
    484
    485			if (!bin->base) {
    486				bin_reserve(bin,
    487					    sizeof(*if_rule) *
    488					    __num_if_rules);
    489				num_rules++;
    490			} else {
    491				unsigned int i;
    492
    493				if (!next_rule)
    494					return -EIO;
    495
    496				rules = next_rule;
    497				next_rule++;
    498
    499				if_rule = bin_alloc(bin,
    500						    sizeof(*if_rule) *
    501						    __num_if_rules);
    502				if (!if_rule)
    503					return -ENOMEM;
    504
    505				for (i = 0; i < __num_if_rules; i++) {
    506					if_rule[i].addr =
    507						((u16)__if_rules[i].addr[0]
    508						 << 8) +
    509						__if_rules[i].addr[1];
    510					if_rule[i].value = __if_rules[i].value;
    511					if_rule[i].mask = __if_rules[i].mask;
    512				}
    513
    514				rules->if_rules = if_rule;
    515				rules->num_if_rules = __num_if_rules;
    516			}
    517			break;
    518		}
    519		case CCS_DATA_BLOCK_RULE_ID_READ_ONLY_REGS:
    520			rval = ccs_data_parse_reg_rules(bin, &rules->read_only_regs,
    521							&rules->num_read_only_regs,
    522							rule_payload,
    523							rule_payload + rule_plen2,
    524							dev);
    525			if (rval)
    526				return rval;
    527			break;
    528		case CCS_DATA_BLOCK_RULE_ID_FFD:
    529			rval = ccs_data_parse_ffd(bin, &rules->frame_format,
    530						  rule_payload,
    531						  rule_payload + rule_plen2,
    532						  dev);
    533			if (rval)
    534				return rval;
    535			break;
    536		case CCS_DATA_BLOCK_RULE_ID_MSR:
    537			rval = ccs_data_parse_reg_rules(bin,
    538							&rules->manufacturer_regs,
    539							&rules->num_manufacturer_regs,
    540							rule_payload,
    541							rule_payload + rule_plen2,
    542							dev);
    543			if (rval)
    544				return rval;
    545			break;
    546		case CCS_DATA_BLOCK_RULE_ID_PDAF_READOUT:
    547			rval = ccs_data_parse_pdaf_readout(bin,
    548							   &rules->pdaf_readout,
    549							   rule_payload,
    550							   rule_payload + rule_plen2,
    551							   dev);
    552			if (rval)
    553				return rval;
    554			break;
    555		default:
    556			dev_dbg(dev,
    557				"Don't know how to handle rule type %u!\n",
    558				*__rule_type);
    559			return -EINVAL;
    560		}
    561		__next_rule = __next_rule + rule_hlen + rule_plen;
    562	}
    563
    564	if (!bin->base) {
    565		bin_reserve(bin, sizeof(*rules) * num_rules);
    566		*__num_rules = num_rules;
    567	} else {
    568		if (!rules_base)
    569			return -EIO;
    570
    571		*__rules = rules_base;
    572	}
    573
    574	return 0;
    575}
    576
    577static int ccs_data_parse_pdaf(struct bin_container *bin, struct ccs_pdaf_pix_loc **pdaf,
    578			       const void *payload, const void *endp,
    579			       struct device *dev)
    580{
    581	const struct __ccs_data_block_pdaf_pix_loc *__pdaf = payload;
    582	const struct __ccs_data_block_pdaf_pix_loc_block_desc_group *__bdesc_group;
    583	const struct __ccs_data_block_pdaf_pix_loc_pixel_desc *__pixel_desc;
    584	unsigned int i;
    585	u16 num_block_desc_groups;
    586	u8 max_block_type_id = 0;
    587	const u8 *__num_pixel_descs;
    588
    589	if (!is_contained(__pdaf, endp))
    590		return -ENODATA;
    591
    592	if (bin->base) {
    593		*pdaf = bin_alloc(bin, sizeof(**pdaf));
    594		if (!*pdaf)
    595			return -ENOMEM;
    596	} else {
    597		bin_reserve(bin, sizeof(**pdaf));
    598	}
    599
    600	num_block_desc_groups =
    601		((u16)__pdaf->num_block_desc_groups[0] << 8) +
    602		__pdaf->num_block_desc_groups[1];
    603
    604	if (bin->base) {
    605		(*pdaf)->main_offset_x =
    606			((u16)__pdaf->main_offset_x[0] << 8) +
    607			__pdaf->main_offset_x[1];
    608		(*pdaf)->main_offset_y =
    609			((u16)__pdaf->main_offset_y[0] << 8) +
    610			__pdaf->main_offset_y[1];
    611		(*pdaf)->global_pdaf_type = __pdaf->global_pdaf_type;
    612		(*pdaf)->block_width = __pdaf->block_width;
    613		(*pdaf)->block_height = __pdaf->block_height;
    614		(*pdaf)->num_block_desc_groups = num_block_desc_groups;
    615	}
    616
    617	__bdesc_group = (const void *)(__pdaf + 1);
    618
    619	if (bin->base) {
    620		(*pdaf)->block_desc_groups =
    621			bin_alloc(bin,
    622				  sizeof(struct ccs_pdaf_pix_loc_block_desc_group) *
    623				  num_block_desc_groups);
    624		if (!(*pdaf)->block_desc_groups)
    625			return -ENOMEM;
    626	} else {
    627		bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc_group) *
    628			    num_block_desc_groups);
    629	}
    630
    631	for (i = 0; i < num_block_desc_groups; i++) {
    632		const struct __ccs_data_block_pdaf_pix_loc_block_desc *__bdesc;
    633		u16 num_block_descs;
    634		unsigned int j;
    635
    636		if (!is_contained(__bdesc_group, endp))
    637			return -ENODATA;
    638
    639		num_block_descs =
    640			((u16)__bdesc_group->num_block_descs[0] << 8) +
    641			__bdesc_group->num_block_descs[1];
    642
    643		if (bin->base) {
    644			(*pdaf)->block_desc_groups[i].repeat_y =
    645				__bdesc_group->repeat_y;
    646			(*pdaf)->block_desc_groups[i].num_block_descs =
    647				num_block_descs;
    648		}
    649
    650		__bdesc = (const void *)(__bdesc_group + 1);
    651
    652		if (bin->base) {
    653			(*pdaf)->block_desc_groups[i].block_descs =
    654				bin_alloc(bin,
    655					  sizeof(struct ccs_pdaf_pix_loc_block_desc) *
    656					  num_block_descs);
    657			if (!(*pdaf)->block_desc_groups[i].block_descs)
    658				return -ENOMEM;
    659		} else {
    660			bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_block_desc) *
    661				    num_block_descs);
    662		}
    663
    664		for (j = 0; j < num_block_descs; j++, __bdesc++) {
    665			struct ccs_pdaf_pix_loc_block_desc *bdesc;
    666
    667			if (!is_contained(__bdesc, endp))
    668				return -ENODATA;
    669
    670			if (max_block_type_id <= __bdesc->block_type_id)
    671				max_block_type_id = __bdesc->block_type_id + 1;
    672
    673			if (!bin->base)
    674				continue;
    675
    676			bdesc = &(*pdaf)->block_desc_groups[i].block_descs[j];
    677
    678			bdesc->repeat_x = ((u16)__bdesc->repeat_x[0] << 8)
    679				+ __bdesc->repeat_x[1];
    680
    681			if (__bdesc->block_type_id >= num_block_descs)
    682				return -EINVAL;
    683
    684			bdesc->block_type_id = __bdesc->block_type_id;
    685		}
    686
    687		__bdesc_group = (const void *)__bdesc;
    688	}
    689
    690	__num_pixel_descs = (const void *)__bdesc_group;
    691
    692	if (bin->base) {
    693		(*pdaf)->pixel_desc_groups =
    694			bin_alloc(bin,
    695				  sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) *
    696				  max_block_type_id);
    697		if (!(*pdaf)->pixel_desc_groups)
    698			return -ENOMEM;
    699		(*pdaf)->num_pixel_desc_grups = max_block_type_id;
    700	} else {
    701		bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc_group) *
    702			    max_block_type_id);
    703	}
    704
    705	for (i = 0; i < max_block_type_id; i++) {
    706		struct ccs_pdaf_pix_loc_pixel_desc_group *pdgroup = NULL;
    707		unsigned int j;
    708
    709		if (!is_contained(__num_pixel_descs, endp))
    710			return -ENODATA;
    711
    712		if (bin->base) {
    713			pdgroup = &(*pdaf)->pixel_desc_groups[i];
    714			pdgroup->descs =
    715				bin_alloc(bin,
    716					  sizeof(struct ccs_pdaf_pix_loc_pixel_desc) *
    717					  *__num_pixel_descs);
    718			if (!pdgroup->descs)
    719				return -ENOMEM;
    720			pdgroup->num_descs = *__num_pixel_descs;
    721		} else {
    722			bin_reserve(bin, sizeof(struct ccs_pdaf_pix_loc_pixel_desc) *
    723				    *__num_pixel_descs);
    724		}
    725
    726		__pixel_desc = (const void *)(__num_pixel_descs + 1);
    727
    728		for (j = 0; j < *__num_pixel_descs; j++, __pixel_desc++) {
    729			struct ccs_pdaf_pix_loc_pixel_desc *pdesc;
    730
    731			if (!is_contained(__pixel_desc, endp))
    732				return -ENODATA;
    733
    734			if (!bin->base)
    735				continue;
    736
    737			if (!pdgroup)
    738				return -EIO;
    739
    740			pdesc = &pdgroup->descs[j];
    741			pdesc->pixel_type = __pixel_desc->pixel_type;
    742			pdesc->small_offset_x = __pixel_desc->small_offset_x;
    743			pdesc->small_offset_y = __pixel_desc->small_offset_y;
    744		}
    745
    746		__num_pixel_descs = (const void *)(__pixel_desc + 1);
    747	}
    748
    749	return 0;
    750}
    751
    752static int ccs_data_parse_license(struct bin_container *bin,
    753				  char **__license,
    754				  size_t *__license_length,
    755				  const void *payload, const void *endp)
    756{
    757	size_t size = endp - payload;
    758	char *license;
    759
    760	if (!bin->base) {
    761		bin_reserve(bin, size);
    762		return 0;
    763	}
    764
    765	license = bin_alloc(bin, size);
    766	if (!license)
    767		return -ENOMEM;
    768
    769	memcpy(license, payload, size);
    770
    771	*__license = license;
    772	*__license_length = size;
    773
    774	return 0;
    775}
    776
    777static int ccs_data_parse_end(bool *end, const void *payload, const void *endp,
    778			      struct device *dev)
    779{
    780	const struct __ccs_data_block_end *__end = payload;
    781
    782	if (__end + 1 != endp) {
    783		dev_dbg(dev, "Invalid end block length %u\n",
    784			(unsigned int)(endp - payload));
    785		return -ENODATA;
    786	}
    787
    788	*end = true;
    789
    790	return 0;
    791}
    792
    793static int __ccs_data_parse(struct bin_container *bin,
    794			    struct ccs_data_container *ccsdata,
    795			    const void *data, size_t len, struct device *dev,
    796			    bool verbose)
    797{
    798	const struct __ccs_data_block *block = data;
    799	const struct __ccs_data_block *endp = data + len;
    800	unsigned int version;
    801	bool is_first = true;
    802	int rval;
    803
    804	version = ccs_data_parse_format_version(block);
    805	if (version != CCS_STATIC_DATA_VERSION) {
    806		dev_dbg(dev, "Don't know how to handle version %u\n", version);
    807		return -EINVAL;
    808	}
    809
    810	if (verbose)
    811		dev_dbg(dev, "Parsing CCS static data version %u\n", version);
    812
    813	if (!bin->base)
    814		*ccsdata = (struct ccs_data_container){ 0 };
    815
    816	while (block < endp) {
    817		const struct __ccs_data_block *next_block;
    818		unsigned int block_id;
    819		const void *payload;
    820
    821		rval = ccs_data_block_parse_header(block, is_first, &block_id,
    822						   &payload, &next_block, endp,
    823						   dev,
    824						   bin->base ? false : verbose);
    825
    826		if (rval < 0)
    827			return rval;
    828
    829		switch (block_id) {
    830		case CCS_DATA_BLOCK_ID_DUMMY:
    831			break;
    832		case CCS_DATA_BLOCK_ID_DATA_VERSION:
    833			rval = ccs_data_parse_version(bin, ccsdata, payload,
    834						      next_block);
    835			if (rval < 0)
    836				return rval;
    837			break;
    838		case CCS_DATA_BLOCK_ID_SENSOR_READ_ONLY_REGS:
    839			rval = ccs_data_parse_regs(
    840				bin, &ccsdata->sensor_read_only_regs,
    841				&ccsdata->num_sensor_read_only_regs, payload,
    842				next_block, dev);
    843			if (rval < 0)
    844				return rval;
    845			break;
    846		case CCS_DATA_BLOCK_ID_SENSOR_MANUFACTURER_REGS:
    847			rval = ccs_data_parse_regs(
    848				bin, &ccsdata->sensor_manufacturer_regs,
    849				&ccsdata->num_sensor_manufacturer_regs, payload,
    850				next_block, dev);
    851			if (rval < 0)
    852				return rval;
    853			break;
    854		case CCS_DATA_BLOCK_ID_MODULE_READ_ONLY_REGS:
    855			rval = ccs_data_parse_regs(
    856				bin, &ccsdata->module_read_only_regs,
    857				&ccsdata->num_module_read_only_regs, payload,
    858				next_block, dev);
    859			if (rval < 0)
    860				return rval;
    861			break;
    862		case CCS_DATA_BLOCK_ID_MODULE_MANUFACTURER_REGS:
    863			rval = ccs_data_parse_regs(
    864				bin, &ccsdata->module_manufacturer_regs,
    865				&ccsdata->num_module_manufacturer_regs, payload,
    866				next_block, dev);
    867			if (rval < 0)
    868				return rval;
    869			break;
    870		case CCS_DATA_BLOCK_ID_SENSOR_PDAF_PIXEL_LOCATION:
    871			rval = ccs_data_parse_pdaf(bin, &ccsdata->sensor_pdaf,
    872						   payload, next_block, dev);
    873			if (rval < 0)
    874				return rval;
    875			break;
    876		case CCS_DATA_BLOCK_ID_MODULE_PDAF_PIXEL_LOCATION:
    877			rval = ccs_data_parse_pdaf(bin, &ccsdata->module_pdaf,
    878						   payload, next_block, dev);
    879			if (rval < 0)
    880				return rval;
    881			break;
    882		case CCS_DATA_BLOCK_ID_SENSOR_RULE_BASED_BLOCK:
    883			rval = ccs_data_parse_rules(
    884				bin, &ccsdata->sensor_rules,
    885				&ccsdata->num_sensor_rules, payload, next_block,
    886				dev);
    887			if (rval < 0)
    888				return rval;
    889			break;
    890		case CCS_DATA_BLOCK_ID_MODULE_RULE_BASED_BLOCK:
    891			rval = ccs_data_parse_rules(
    892				bin, &ccsdata->module_rules,
    893				&ccsdata->num_module_rules, payload, next_block,
    894				dev);
    895			if (rval < 0)
    896				return rval;
    897			break;
    898		case CCS_DATA_BLOCK_ID_LICENSE:
    899			rval = ccs_data_parse_license(bin, &ccsdata->license,
    900						      &ccsdata->license_length,
    901						      payload, next_block);
    902			if (rval < 0)
    903				return rval;
    904			break;
    905		case CCS_DATA_BLOCK_ID_END:
    906			rval = ccs_data_parse_end(&ccsdata->end, payload,
    907						  next_block, dev);
    908			if (rval < 0)
    909				return rval;
    910			break;
    911		default:
    912			dev_dbg(dev, "WARNING: not handling block ID 0x%2.2x\n",
    913				block_id);
    914		}
    915
    916		block = next_block;
    917		is_first = false;
    918	}
    919
    920	return 0;
    921}
    922
    923/**
    924 * ccs_data_parse - Parse a CCS static data file into a usable in-memory
    925 *		    data structure
    926 * @ccsdata:	CCS static data in-memory data structure
    927 * @data:	CCS static data binary
    928 * @len:	Length of @data
    929 * @dev:	Device the data is related to (used for printing debug messages)
    930 * @verbose:	Whether to be verbose or not
    931 */
    932int ccs_data_parse(struct ccs_data_container *ccsdata, const void *data,
    933		   size_t len, struct device *dev, bool verbose)
    934{
    935	struct bin_container bin = { 0 };
    936	int rval;
    937
    938	rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, verbose);
    939	if (rval)
    940		return rval;
    941
    942	rval = bin_backing_alloc(&bin);
    943	if (rval)
    944		return rval;
    945
    946	rval = __ccs_data_parse(&bin, ccsdata, data, len, dev, false);
    947	if (rval)
    948		goto out_free;
    949
    950	if (verbose && ccsdata->version)
    951		print_ccs_data_version(dev, ccsdata->version);
    952
    953	if (bin.now != bin.end) {
    954		rval = -EPROTO;
    955		dev_dbg(dev, "parsing mismatch; base %p; now %p; end %p\n",
    956			bin.base, bin.now, bin.end);
    957		goto out_free;
    958	}
    959
    960	ccsdata->backing = bin.base;
    961
    962	return 0;
    963
    964out_free:
    965	kvfree(bin.base);
    966
    967	return rval;
    968}