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

v4l2-h264.c (13726B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * V4L2 H264 helpers.
      4 *
      5 * Copyright (C) 2019 Collabora, Ltd.
      6 *
      7 * Author: Boris Brezillon <boris.brezillon@collabora.com>
      8 */
      9
     10#include <linux/module.h>
     11#include <linux/sort.h>
     12
     13#include <media/v4l2-h264.h>
     14
     15/*
     16 * Size of the tempory buffer allocated when printing reference lists. The
     17 * output will be truncated if the size is too small.
     18 */
     19static const int tmp_str_size = 1024;
     20
     21/**
     22 * v4l2_h264_init_reflist_builder() - Initialize a P/B0/B1 reference list
     23 *				      builder
     24 *
     25 * @b: the builder context to initialize
     26 * @dec_params: decode parameters control
     27 * @sps: SPS control
     28 * @dpb: DPB to use when creating the reference list
     29 */
     30void
     31v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b,
     32		const struct v4l2_ctrl_h264_decode_params *dec_params,
     33		const struct v4l2_ctrl_h264_sps *sps,
     34		const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES])
     35{
     36	int cur_frame_num, max_frame_num;
     37	unsigned int i;
     38
     39	max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
     40	cur_frame_num = dec_params->frame_num;
     41
     42	memset(b, 0, sizeof(*b));
     43	if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) {
     44		b->cur_pic_order_count = min(dec_params->bottom_field_order_cnt,
     45					     dec_params->top_field_order_cnt);
     46		b->cur_pic_fields = V4L2_H264_FRAME_REF;
     47	} else if (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) {
     48		b->cur_pic_order_count = dec_params->bottom_field_order_cnt;
     49		b->cur_pic_fields = V4L2_H264_BOTTOM_FIELD_REF;
     50	} else {
     51		b->cur_pic_order_count = dec_params->top_field_order_cnt;
     52		b->cur_pic_fields = V4L2_H264_TOP_FIELD_REF;
     53	}
     54
     55	for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) {
     56		if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
     57			continue;
     58
     59		if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)
     60			b->refs[i].longterm = true;
     61
     62		/*
     63		 * Handle frame_num wraparound as described in section
     64		 * '8.2.4.1 Decoding process for picture numbers' of the spec.
     65		 * For long term references, frame_num is set to
     66		 * long_term_frame_idx which requires no wrapping.
     67		 */
     68		if (!b->refs[i].longterm && dpb[i].frame_num > cur_frame_num)
     69			b->refs[i].frame_num = (int)dpb[i].frame_num -
     70					       max_frame_num;
     71		else
     72			b->refs[i].frame_num = dpb[i].frame_num;
     73
     74		b->refs[i].top_field_order_cnt = dpb[i].top_field_order_cnt;
     75		b->refs[i].bottom_field_order_cnt = dpb[i].bottom_field_order_cnt;
     76
     77		if (b->cur_pic_fields == V4L2_H264_FRAME_REF) {
     78			u8 fields = V4L2_H264_FRAME_REF;
     79
     80			b->unordered_reflist[b->num_valid].index = i;
     81			b->unordered_reflist[b->num_valid].fields = fields;
     82			b->num_valid++;
     83			continue;
     84		}
     85
     86		if (dpb[i].fields & V4L2_H264_TOP_FIELD_REF) {
     87			u8 fields = V4L2_H264_TOP_FIELD_REF;
     88
     89			b->unordered_reflist[b->num_valid].index = i;
     90			b->unordered_reflist[b->num_valid].fields = fields;
     91			b->num_valid++;
     92		}
     93
     94		if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF) {
     95			u8 fields = V4L2_H264_BOTTOM_FIELD_REF;
     96
     97			b->unordered_reflist[b->num_valid].index = i;
     98			b->unordered_reflist[b->num_valid].fields = fields;
     99			b->num_valid++;
    100		}
    101	}
    102
    103	for (i = b->num_valid; i < ARRAY_SIZE(b->unordered_reflist); i++)
    104		b->unordered_reflist[i].index = i;
    105}
    106EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder);
    107
    108static s32 v4l2_h264_get_poc(const struct v4l2_h264_reflist_builder *b,
    109			     const struct v4l2_h264_reference *ref)
    110{
    111	switch (ref->fields) {
    112	case V4L2_H264_FRAME_REF:
    113		return min(b->refs[ref->index].top_field_order_cnt,
    114				b->refs[ref->index].bottom_field_order_cnt);
    115	case V4L2_H264_TOP_FIELD_REF:
    116		return b->refs[ref->index].top_field_order_cnt;
    117	case V4L2_H264_BOTTOM_FIELD_REF:
    118		return b->refs[ref->index].bottom_field_order_cnt;
    119	}
    120
    121	/* not reached */
    122	return 0;
    123}
    124
    125static int v4l2_h264_p_ref_list_cmp(const void *ptra, const void *ptrb,
    126				    const void *data)
    127{
    128	const struct v4l2_h264_reflist_builder *builder = data;
    129	u8 idxa, idxb;
    130
    131	idxa = ((struct v4l2_h264_reference *)ptra)->index;
    132	idxb = ((struct v4l2_h264_reference *)ptrb)->index;
    133
    134	if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
    135		    idxb >= V4L2_H264_NUM_DPB_ENTRIES))
    136		return 1;
    137
    138	if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
    139		/* Short term pics first. */
    140		if (!builder->refs[idxa].longterm)
    141			return -1;
    142		else
    143			return 1;
    144	}
    145
    146	/*
    147	 * For frames, short term pics are in descending pic num order and long
    148	 * term ones in ascending order. For fields, the same direction is used
    149	 * but with frame_num (wrapped). For frames, the value of pic_num and
    150	 * frame_num are the same (see formula (8-28) and (8-29)). For this
    151	 * reason we can use frame_num only and share this function between
    152	 * frames and fields reflist.
    153	 */
    154	if (!builder->refs[idxa].longterm)
    155		return builder->refs[idxb].frame_num <
    156		       builder->refs[idxa].frame_num ?
    157		       -1 : 1;
    158
    159	return builder->refs[idxa].frame_num < builder->refs[idxb].frame_num ?
    160	       -1 : 1;
    161}
    162
    163static int v4l2_h264_b0_ref_list_cmp(const void *ptra, const void *ptrb,
    164				     const void *data)
    165{
    166	const struct v4l2_h264_reflist_builder *builder = data;
    167	s32 poca, pocb;
    168	u8 idxa, idxb;
    169
    170	idxa = ((struct v4l2_h264_reference *)ptra)->index;
    171	idxb = ((struct v4l2_h264_reference *)ptrb)->index;
    172
    173	if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
    174		    idxb >= V4L2_H264_NUM_DPB_ENTRIES))
    175		return 1;
    176
    177	if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
    178		/* Short term pics first. */
    179		if (!builder->refs[idxa].longterm)
    180			return -1;
    181		else
    182			return 1;
    183	}
    184
    185	/* Long term pics in ascending frame num order. */
    186	if (builder->refs[idxa].longterm)
    187		return builder->refs[idxa].frame_num <
    188		       builder->refs[idxb].frame_num ?
    189		       -1 : 1;
    190
    191	poca = v4l2_h264_get_poc(builder, ptra);
    192	pocb = v4l2_h264_get_poc(builder, ptrb);
    193
    194	/*
    195	 * Short term pics with POC < cur POC first in POC descending order
    196	 * followed by short term pics with POC > cur POC in POC ascending
    197	 * order.
    198	 */
    199	if ((poca < builder->cur_pic_order_count) !=
    200	     (pocb < builder->cur_pic_order_count))
    201		return poca < pocb ? -1 : 1;
    202	else if (poca < builder->cur_pic_order_count)
    203		return pocb < poca ? -1 : 1;
    204
    205	return poca < pocb ? -1 : 1;
    206}
    207
    208static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb,
    209				     const void *data)
    210{
    211	const struct v4l2_h264_reflist_builder *builder = data;
    212	s32 poca, pocb;
    213	u8 idxa, idxb;
    214
    215	idxa = ((struct v4l2_h264_reference *)ptra)->index;
    216	idxb = ((struct v4l2_h264_reference *)ptrb)->index;
    217
    218	if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES ||
    219		    idxb >= V4L2_H264_NUM_DPB_ENTRIES))
    220		return 1;
    221
    222	if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) {
    223		/* Short term pics first. */
    224		if (!builder->refs[idxa].longterm)
    225			return -1;
    226		else
    227			return 1;
    228	}
    229
    230	/* Long term pics in ascending frame num order. */
    231	if (builder->refs[idxa].longterm)
    232		return builder->refs[idxa].frame_num <
    233		       builder->refs[idxb].frame_num ?
    234		       -1 : 1;
    235
    236	poca = v4l2_h264_get_poc(builder, ptra);
    237	pocb = v4l2_h264_get_poc(builder, ptrb);
    238
    239	/*
    240	 * Short term pics with POC > cur POC first in POC ascending order
    241	 * followed by short term pics with POC < cur POC in POC descending
    242	 * order.
    243	 */
    244	if ((poca < builder->cur_pic_order_count) !=
    245	    (pocb < builder->cur_pic_order_count))
    246		return pocb < poca ? -1 : 1;
    247	else if (poca < builder->cur_pic_order_count)
    248		return pocb < poca ? -1 : 1;
    249
    250	return poca < pocb ? -1 : 1;
    251}
    252
    253/*
    254 * The references need to be reordered so that references are alternating
    255 * between top and bottom field references starting with the current picture
    256 * parity. This has to be done for short term and long term references
    257 * separately.
    258 */
    259static void reorder_field_reflist(const struct v4l2_h264_reflist_builder *b,
    260				  struct v4l2_h264_reference *reflist)
    261{
    262	struct v4l2_h264_reference tmplist[V4L2_H264_REF_LIST_LEN];
    263	u8 lt, i = 0, j = 0, k = 0;
    264
    265	memcpy(tmplist, reflist, sizeof(tmplist[0]) * b->num_valid);
    266
    267	for (lt = 0; lt <= 1; lt++) {
    268		do {
    269			for (; i < b->num_valid && b->refs[tmplist[i].index].longterm == lt; i++) {
    270				if (tmplist[i].fields == b->cur_pic_fields) {
    271					reflist[k++] = tmplist[i++];
    272					break;
    273				}
    274			}
    275
    276			for (; j < b->num_valid && b->refs[tmplist[j].index].longterm == lt; j++) {
    277				if (tmplist[j].fields != b->cur_pic_fields) {
    278					reflist[k++] = tmplist[j++];
    279					break;
    280				}
    281			}
    282		} while ((i < b->num_valid && b->refs[tmplist[i].index].longterm == lt) ||
    283			 (j < b->num_valid && b->refs[tmplist[j].index].longterm == lt));
    284	}
    285}
    286
    287static char ref_type_to_char(u8 ref_type)
    288{
    289	switch (ref_type) {
    290	case V4L2_H264_FRAME_REF:
    291		return 'f';
    292	case V4L2_H264_TOP_FIELD_REF:
    293		return 't';
    294	case V4L2_H264_BOTTOM_FIELD_REF:
    295		return 'b';
    296	}
    297
    298	return '?';
    299}
    300
    301static const char *format_ref_list_p(const struct v4l2_h264_reflist_builder *builder,
    302				     struct v4l2_h264_reference *reflist,
    303				     char **out_str)
    304{
    305	int n = 0, i;
    306
    307	*out_str = kmalloc(tmp_str_size, GFP_KERNEL);
    308
    309	n += snprintf(*out_str + n, tmp_str_size - n, "|");
    310
    311	for (i = 0; i < builder->num_valid; i++) {
    312		/* this is pic_num for frame and frame_num (wrapped) for field,
    313		 * but for frame pic_num is equal to frame_num (wrapped).
    314		 */
    315		int frame_num = builder->refs[reflist[i].index].frame_num;
    316		bool longterm = builder->refs[reflist[i].index].longterm;
    317
    318		n += scnprintf(*out_str + n, tmp_str_size - n, "%i%c%c|",
    319			       frame_num, longterm ? 'l' : 's',
    320			       ref_type_to_char(reflist[i].fields));
    321	}
    322
    323	return *out_str;
    324}
    325
    326static void print_ref_list_p(const struct v4l2_h264_reflist_builder *builder,
    327			     struct v4l2_h264_reference *reflist)
    328{
    329	char *buf = NULL;
    330
    331	pr_debug("ref_pic_list_p (cur_poc %u%c) %s\n",
    332		 builder->cur_pic_order_count,
    333		 ref_type_to_char(builder->cur_pic_fields),
    334		 format_ref_list_p(builder, reflist, &buf));
    335
    336	kfree(buf);
    337}
    338
    339static const char *format_ref_list_b(const struct v4l2_h264_reflist_builder *builder,
    340				     struct v4l2_h264_reference *reflist,
    341				     char **out_str)
    342{
    343	int n = 0, i;
    344
    345	*out_str = kmalloc(tmp_str_size, GFP_KERNEL);
    346
    347	n += snprintf(*out_str + n, tmp_str_size - n, "|");
    348
    349	for (i = 0; i < builder->num_valid; i++) {
    350		int frame_num = builder->refs[reflist[i].index].frame_num;
    351		u32 poc = v4l2_h264_get_poc(builder, reflist + i);
    352		bool longterm = builder->refs[reflist[i].index].longterm;
    353
    354		n += scnprintf(*out_str + n, tmp_str_size - n, "%i%c%c|",
    355			       longterm ? frame_num : poc,
    356			       longterm ? 'l' : 's',
    357			       ref_type_to_char(reflist[i].fields));
    358	}
    359
    360	return *out_str;
    361}
    362
    363static void print_ref_list_b(const struct v4l2_h264_reflist_builder *builder,
    364			     struct v4l2_h264_reference *reflist, u8 list_num)
    365{
    366	char *buf = NULL;
    367
    368	pr_debug("ref_pic_list_b%u (cur_poc %u%c) %s",
    369		 list_num, builder->cur_pic_order_count,
    370		 ref_type_to_char(builder->cur_pic_fields),
    371		 format_ref_list_b(builder, reflist, &buf));
    372
    373	kfree(buf);
    374}
    375
    376/**
    377 * v4l2_h264_build_p_ref_list() - Build the P reference list
    378 *
    379 * @builder: reference list builder context
    380 * @reflist: 32 sized array used to store the P reference list. Each entry
    381 *	     is a v4l2_h264_reference structure
    382 *
    383 * This functions builds the P reference lists. This procedure is describe in
    384 * section '8.2.4 Decoding process for reference picture lists construction'
    385 * of the H264 spec. This function can be used by H264 decoder drivers that
    386 * need to pass a P reference list to the hardware.
    387 */
    388void
    389v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder *builder,
    390			   struct v4l2_h264_reference *reflist)
    391{
    392	memcpy(reflist, builder->unordered_reflist,
    393	       sizeof(builder->unordered_reflist[0]) * builder->num_valid);
    394	sort_r(reflist, builder->num_valid, sizeof(*reflist),
    395	       v4l2_h264_p_ref_list_cmp, NULL, builder);
    396
    397	if (builder->cur_pic_fields != V4L2_H264_FRAME_REF)
    398		reorder_field_reflist(builder, reflist);
    399
    400	print_ref_list_p(builder, reflist);
    401}
    402EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list);
    403
    404/**
    405 * v4l2_h264_build_b_ref_lists() - Build the B0/B1 reference lists
    406 *
    407 * @builder: reference list builder context
    408 * @b0_reflist: 32 sized array used to store the B0 reference list. Each entry
    409 *		is a v4l2_h264_reference structure
    410 * @b1_reflist: 32 sized array used to store the B1 reference list. Each entry
    411 *		is a v4l2_h264_reference structure
    412 *
    413 * This functions builds the B0/B1 reference lists. This procedure is described
    414 * in section '8.2.4 Decoding process for reference picture lists construction'
    415 * of the H264 spec. This function can be used by H264 decoder drivers that
    416 * need to pass B0/B1 reference lists to the hardware.
    417 */
    418void
    419v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder,
    420			    struct v4l2_h264_reference *b0_reflist,
    421			    struct v4l2_h264_reference *b1_reflist)
    422{
    423	memcpy(b0_reflist, builder->unordered_reflist,
    424	       sizeof(builder->unordered_reflist[0]) * builder->num_valid);
    425	sort_r(b0_reflist, builder->num_valid, sizeof(*b0_reflist),
    426	       v4l2_h264_b0_ref_list_cmp, NULL, builder);
    427
    428	memcpy(b1_reflist, builder->unordered_reflist,
    429	       sizeof(builder->unordered_reflist[0]) * builder->num_valid);
    430	sort_r(b1_reflist, builder->num_valid, sizeof(*b1_reflist),
    431	       v4l2_h264_b1_ref_list_cmp, NULL, builder);
    432
    433	if (builder->cur_pic_fields != V4L2_H264_FRAME_REF) {
    434		reorder_field_reflist(builder, b0_reflist);
    435		reorder_field_reflist(builder, b1_reflist);
    436	}
    437
    438	if (builder->num_valid > 1 &&
    439	    !memcmp(b1_reflist, b0_reflist, builder->num_valid))
    440		swap(b1_reflist[0], b1_reflist[1]);
    441
    442	print_ref_list_b(builder, b0_reflist, 0);
    443	print_ref_list_b(builder, b1_reflist, 1);
    444}
    445EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists);
    446
    447MODULE_LICENSE("GPL");
    448MODULE_DESCRIPTION("V4L2 H264 Helpers");
    449MODULE_AUTHOR("Boris Brezillon <boris.brezillon@collabora.com>");