1 /*
2 * Implementation of the protocol buffers encoder.
3 *
4 * Based on code taken from
5 * https://code.google.com/archive/p/lwpb/source/default/source
6 *
7 * The code there is licensed as Apache 2.0. However, NVIDIA has received the
8 * code from the original author under MIT license terms.
9 *
10 *
11 * Copyright 2009 Simon Kallweit
12 * Copyright 2009-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of this software and associated documentation files (the "Software"),
16 * to deal in the Software without restriction, including without limitation
17 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 * and/or sell copies of the Software, and to permit persons to whom the
19 * Software is furnished to do so, subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 * DEALINGS IN THE SOFTWARE.
31 */
32
33 #include "os/os.h"
34 #include "lib/protobuf/prb.h"
35
36 static NV_STATUS prbEncAddField(PRB_ENCODER *encoder,
37 const PRB_FIELD_DESC *field_desc,
38 PRB_VALUE *value);
39 static NV_STATUS prbEndPackedField(PRB_ENCODER *encoder);
40 static NV_STATUS prbStartPackedField(PRB_ENCODER *encoder,
41 const PRB_FIELD_DESC *field_desc);
42
43 #define MSG_RESERVE_BYTES 10
44
45 // Handy macros to check flags
46 #define COUNT_FLAG(encoder) ((encoder->flags & PRB_COUNT_ONLY) != 0)
47 #define FIXED_FLAG(encoder) ((encoder->flags & PRB_FIXED_MODE) != 0)
48
49 /*!
50 * @brief Initializes a memory buffer. Sets the position to the base address.
51 * @param [in] buf Memory buffer
52 * @param [in] data Base address of memory
53 * @param [in] len Length of memory
54 *
55 */
56 static void
prbBufInit(PRB_BUF * buf,void * data,NvU32 len)57 prbBufInit(PRB_BUF *buf, void *data, NvU32 len)
58 {
59 buf->base = data;
60 buf->pos = data;
61 buf->end = &buf->base[len];
62 }
63
64 /*!
65 * @brief frees a buffer
66 * @param [in] buff Memory buffer
67 */
68
69 static void
prbBuffFree(PRB_BUF * buf)70 prbBuffFree(PRB_BUF *buf)
71 {
72 portMemFree(buf->base);
73
74 buf->base = NULL;
75 buf->pos = NULL;
76 buf->end = NULL;
77 }
78
79 /*!
80 * @brief Returns the number of used bytes in the buffer.
81 * @param [in] buf Memory buffer
82 *
83 * @returns the number of used bytes.
84 */
85 static NvU32
prbBufUsed(PRB_BUF * buf)86 prbBufUsed(PRB_BUF *buf)
87 {
88 return (NvU32)(buf->pos - buf->base);
89 }
90
91 /*!
92 * @brief Returns the number of bytes left in the buffer.
93 * @param [in] buf Memory buffer
94 *
95 * @returns the number of bytes left.
96 */
97 static NvU32
prbBufLeft(PRB_BUF * buf)98 prbBufLeft(PRB_BUF *buf)
99 {
100 return (NvU32)(buf->end - buf->pos);
101 }
102
103 // Encoder utilities
104
105 /*!
106 * @brief Encodes a variable integer in base-128 format.
107 * See https://code.google.com/apis/protocolbuffers/docs/encoding.html for more
108 * information.
109 * @param [in] buf Memory buffer
110 * @param [in] varint Value to encode
111 * @param [in] countOnly Set to just count the bytes
112 * @returns NV_STATUS
113 */
114
115 static
116 NV_STATUS
encode_varint(PRB_BUF * buf,NvU64 varint,NvBool countOnly)117 encode_varint(PRB_BUF *buf, NvU64 varint, NvBool countOnly)
118 {
119 do {
120 if (prbBufLeft(buf) < 1)
121 return NV_ERR_BUFFER_TOO_SMALL;
122 if (!countOnly)
123 {
124 if (varint > 127) {
125 *buf->pos = (NvU8)(0x80 | (varint & 0x7F));
126 } else {
127 *buf->pos = (NvU8)(varint & 0x7F);
128 }
129 }
130 varint >>= 7;
131 buf->pos++;
132 } while (varint);
133
134 return NV_OK;
135 }
136
137 /**
138 * Decodes a variable integer in base-128 format.
139 * See https://code.google.com/apis/protocolbuffers/docs/encoding.html for more
140 * information.
141 * @param [in] pBuff Buffer to decode
142 * @param [in] len Length of input buffer
143 * @param [out] pUsed Number of bytes used
144 * @param [out] pData Data value returned
145 * @return Returns NV_STATUS
146 */
147 static NV_STATUS
decode_varint(NvU8 * pBuff,NvU64 len,NvU32 * pUsed,NvU64 * pData)148 decode_varint(NvU8 *pBuff, NvU64 len, NvU32 *pUsed, NvU64 *pData)
149 {
150 NvU32 bitpos;
151
152 if (pBuff == NULL)
153 {
154 return NV_ERR_INVALID_POINTER;
155 }
156
157 *pUsed = 0;
158
159 *pData = 0;
160 for (bitpos = 0; *pBuff & 0x80 && bitpos < 64; bitpos += 7, pBuff++)
161 {
162 *pData |= (NvU64) (*pBuff & 0x7f) << bitpos;
163 (*pUsed)++;
164 if (--len < 1)
165 return NV_ERR_BUFFER_TOO_SMALL;
166 }
167 *pData |= (NvU64)(*pBuff & 0x7f) << bitpos;
168 (*pUsed)++;
169
170 return NV_OK;
171 }
172
173 /*!
174 * @brief Encodes a 32 bit integer.
175 * @param [in] buf Memory buffer
176 * @param [in] value Value to encode
177 * @param [in] countOnly Set to just count the bytes
178 * @returns NV_STATUS
179 */
180 static NV_STATUS
encode_32bit(PRB_BUF * buf,NvU32 value,NvBool countOnly)181 encode_32bit(PRB_BUF *buf, NvU32 value, NvBool countOnly)
182 {
183 if (prbBufLeft(buf) < 4)
184 return NV_ERR_BUFFER_TOO_SMALL;
185
186 if (!countOnly)
187 {
188 buf->pos[0] = (NvU8)((value) & 0xff);
189 buf->pos[1] = (NvU8)((value >> 8) & 0xff);
190 buf->pos[2] = (NvU8)((value >> 16) & 0xff);
191 buf->pos[3] = (NvU8)((value >> 24) & 0xff);
192 }
193 buf->pos += 4;
194
195 return NV_OK;
196 }
197
198 /*!
199 * @brief Encodes a 64 bit integer.
200 * @param [in] buf Memory buffer
201 * @param [in] value Value to encode
202 * @param [in] countOnly Set to just count the bytes
203 * @returns NV_STATUS
204 */
205 static NV_STATUS
encode_64bit(PRB_BUF * buf,NvU64 value,NvBool countOnly)206 encode_64bit(PRB_BUF *buf, NvU64 value, NvBool countOnly)
207 {
208 if (prbBufLeft(buf) < 8)
209 return NV_ERR_BUFFER_TOO_SMALL;
210
211 if (!countOnly)
212 {
213 buf->pos[0] = (NvU8)((value) & 0xff);
214 buf->pos[1] = (NvU8)((value >> 8) & 0xff);
215 buf->pos[2] = (NvU8)((value >> 16) & 0xff);
216 buf->pos[3] = (NvU8)((value >> 24) & 0xff);
217 value >>= 32;
218 buf->pos[4] = (NvU8)((value) & 0xff);
219 buf->pos[5] = (NvU8)((value >> 8) & 0xff);
220 buf->pos[6] = (NvU8)((value >> 16) & 0xff);
221 buf->pos[7] = (NvU8)((value >> 24) & 0xff);
222 }
223 buf->pos += 8;
224
225 return NV_OK;
226 }
227
228 // Encoder
229
230 /*!
231 * @brief Starts the encoder with the first message
232 * This variant allows the caller to pass in a buffer to use.
233 * @param [in] encoder The encoder structure
234 * @param [in] msg_desc The message to encode
235 * @param [in] data The buffer to use
236 * @param [in] len Length of the buffer
237 */
238
239 void
prbEncStart(PRB_ENCODER * encoder,const PRB_MSG_DESC * msg_desc,void * data,NvU32 len,PrbBufferCallback * pBufferCallback)240 prbEncStart
241 (
242 PRB_ENCODER *encoder,
243 const PRB_MSG_DESC *msg_desc,
244 void *data,
245 NvU32 len,
246 PrbBufferCallback *pBufferCallback
247 )
248 {
249 encoder->flags = 0;
250 encoder->depth = 1;
251 prbBufInit(&encoder->stack[0].buf, data, len);
252 encoder->stack[0].field_desc = NULL;
253 encoder->stack[0].msg_desc = msg_desc;
254
255 encoder->pBufferCallback = pBufferCallback;
256 if (pBufferCallback != NULL)
257 {
258 encoder->flags |= PRB_FIXED_MODE;
259 }
260 }
261
262 /*!
263 * @brief Starts the encoder with the first message
264 * Allocates memory to hold the data.
265 * If no memory was available, logging will be disabled
266 * and future calls to the encoding routines with this encoder
267 * will succeed but no data will be logged.
268 * @param [in] encoder The encoder structure
269 * @param [in] msg_desc The message to encode
270 * @param [in] len The caller's estimate of the number of bytes needed
271 * @returns NV_STATUS
272 */
273
274 NV_STATUS
prbEncStartAlloc(PRB_ENCODER * encoder,const PRB_MSG_DESC * msg_desc,NvU32 len,PrbBufferCallback * pBufferCallback)275 prbEncStartAlloc
276 (
277 PRB_ENCODER *encoder,
278 const PRB_MSG_DESC *msg_desc,
279 NvU32 len,
280 PrbBufferCallback *pBufferCallback
281 )
282 {
283 void *data = NULL;
284 NV_STATUS rmstatus = NV_OK;
285
286 data = portMemAllocNonPaged(len);
287 if (data != NULL)
288 {
289 prbEncStart(encoder, msg_desc, data, len, pBufferCallback);
290 encoder->flags |= PRB_BUFFER_ALLOCATED;
291 }
292 else
293 {
294 rmstatus = NV_ERR_NO_MEMORY;
295 NV_PRINTF(LEVEL_ERROR,
296 "Can't allocate memory for protocol buffers.\n");
297 // Disable all encoding
298 encoder->flags = PRB_ENCODE_DISABLED;
299 }
300 return rmstatus;
301 }
302
303 /*!
304 * @brief Starts the encoder with the first message
305 * This variant just counts the length of the message
306 * No data is stored
307 * @param [in] encoder The encoder structure
308 * @param [in] msg_desc The message to encode
309 * @param [in] len Length of the buffer
310 */
311
312 void
prbEncStartCount(PRB_ENCODER * encoder,const PRB_MSG_DESC * msg_desc,NvU32 len)313 prbEncStartCount(PRB_ENCODER *encoder,
314 const PRB_MSG_DESC *msg_desc,
315 NvU32 len)
316 {
317 prbEncStart(encoder, msg_desc, NULL, len, NULL);
318 encoder->flags |= PRB_COUNT_ONLY;
319 }
320
321 /*!
322 * @brief free an allocated buffer and disables encoding.
323 * @param [in] encoder the encoder structure.
324 */
325
326 void
prbFreeAllocatedBuffer(PRB_ENCODER * encoder)327 prbFreeAllocatedBuffer(PRB_ENCODER *encoder)
328 {
329 if (encoder->flags & PRB_BUFFER_ALLOCATED)
330 prbBuffFree(&encoder->stack[0].buf);
331
332 encoder->flags &= ~PRB_BUFFER_ALLOCATED;
333 encoder->flags |= PRB_ENCODE_DISABLED;
334 encoder->depth = 1;
335 }
336
337 /*!
338 * @brief Finish encoding
339 * @param [in] encoder The current encoder structure
340 * @param [out] buff The address of the data buffer.
341 * @returns the number of bytes encoded
342 */
343
344 NvU32
prbEncFinish(PRB_ENCODER * encoder,void ** buff)345 prbEncFinish(PRB_ENCODER *encoder, void **buff)
346 {
347 if (!(encoder->flags & PRB_ENCODE_DISABLED))
348 prbEndPackedField(encoder);
349
350 *buff = encoder->stack[0].buf.base;
351 encoder->flags |= PRB_ENCODE_DISABLED;
352 return prbBufUsed(&encoder->stack[0].buf);
353 }
354
355 /*!
356 * @brief Start a nested message
357 * @param [in] encoder The current encoder
358 * @param [in] field_desc The field where the message starts
359 * @returns NV_STATUS
360 */
361
362 NV_STATUS
prbEncNestedStart(PRB_ENCODER * encoder,const PRB_FIELD_DESC * field_desc)363 prbEncNestedStart(PRB_ENCODER *encoder,
364 const PRB_FIELD_DESC *field_desc)
365 {
366 NV_STATUS status;
367
368 PRB_ENCODER_STACK_FRAME *frame, *new_frame;
369
370 if (encoder->flags & PRB_ENCODE_DISABLED)
371 {
372 return NV_ERR_INVALID_REQUEST;
373 }
374
375 status = prbEndPackedField(encoder);
376 if (status != NV_OK)
377 return status;
378
379 // The field must be a message
380 if (field_desc->opts.typ != PRB_MESSAGE)
381 {
382 DBG_BREAKPOINT();
383 return NV_ERR_INVALID_REQUEST;
384 }
385
386 // Check max depth
387 if (encoder->depth >= PRB_MAX_DEPTH)
388 {
389 DBG_BREAKPOINT();
390 return NV_ERR_INSUFFICIENT_RESOURCES;
391 }
392
393 // Get parent frame
394 frame = &encoder->stack[encoder->depth - 1];
395
396 // Create a new frame
397 encoder->depth++;
398 new_frame = &encoder->stack[encoder->depth - 1];
399 new_frame->field_desc = field_desc;
400 new_frame->msg_desc = field_desc->msg_desc;
401
402 // Reserve a few bytes for the field on the parent frame. This is where
403 // the field key (message) and the message length will be stored, once it
404 // is known.
405 if (prbBufLeft(&frame->buf) < MSG_RESERVE_BYTES)
406 {
407 encoder->depth--;
408 return NV_ERR_BUFFER_TOO_SMALL;
409 }
410
411 prbBufInit(&new_frame->buf, frame->buf.pos + MSG_RESERVE_BYTES,
412 prbBufLeft(&frame->buf) - MSG_RESERVE_BYTES);
413 return NV_OK;
414 }
415
416 /*!
417 * @brief Add bytes to a stubbed message.
418 * @param [in] encoder The current encoder
419 * @param [in] buffer The data to copy
420 * @param [in] len The data length
421 */
422
423 NV_STATUS
prbEncStubbedAddBytes(PRB_ENCODER * encoder,NvU8 * buffer,NvU32 len)424 prbEncStubbedAddBytes(PRB_ENCODER *encoder, NvU8 *buffer, NvU32 len)
425 {
426 PRB_ENCODER_STACK_FRAME *frame;
427 NV_STATUS status = NV_OK;
428
429 frame = &encoder->stack[encoder->depth - 1];
430
431 // Check length
432 if (len <= 0) {
433 return NV_ERR_INVALID_ARGUMENT;
434 }
435
436 // Check if we have enough space
437 if (prbBufLeft(&frame->buf) < len) {
438 return NV_ERR_BUFFER_TOO_SMALL;
439 }
440
441 status = prbEndPackedField(encoder);
442 if (status != NV_OK)
443 return status;
444
445 // Move the (possibly overlapping) memory
446 if (!COUNT_FLAG(encoder))
447 portMemMove(frame->buf.pos, len, buffer, len);
448
449 // Adjust current buffer position
450 frame->buf.pos += len;
451 return NV_OK;
452 }
453
454 /*!
455 * @brief Internal helper routine to keep track of packed fields.
456 * @param [in] encoder The encoder
457 * @param [in] field_desc The field being packed
458 * @returns NV_STATUS
459 */
460
461 static NV_STATUS
prbStartPackedField(PRB_ENCODER * encoder,const PRB_FIELD_DESC * field_desc)462 prbStartPackedField(PRB_ENCODER *encoder,
463 const PRB_FIELD_DESC *field_desc)
464 {
465 PRB_ENCODER_STACK_FRAME *frame, *new_frame;
466
467 // The field must be packed
468 if (!(field_desc->opts.flags & PRB_IS_PACKED))
469 {
470 DBG_BREAKPOINT();
471 return NV_ERR_INVALID_REQUEST;
472 }
473
474 // Check max depth
475 if (encoder->depth >= PRB_MAX_DEPTH)
476 {
477 DBG_BREAKPOINT();
478 return NV_ERR_INSUFFICIENT_RESOURCES;
479 }
480
481 // Get parent frame
482 frame = &encoder->stack[encoder->depth - 1];
483
484 // Create a new frame
485 encoder->depth++;
486 new_frame = &encoder->stack[encoder->depth - 1];
487 new_frame->field_desc = field_desc;
488 new_frame->msg_desc = frame->msg_desc;
489 encoder->flags |= PRB_PACKED_FRAME;
490
491 // Reserve a few bytes for the field on the parent frame. This is where
492 // the field key (message) and the message length will be stored, once it
493 // is known.
494 if (prbBufLeft(&frame->buf) < MSG_RESERVE_BYTES)
495 {
496 encoder->depth--;
497 encoder->flags &= ~PRB_PACKED_FRAME;
498 return NV_ERR_BUFFER_TOO_SMALL;
499 }
500
501 prbBufInit(&new_frame->buf, frame->buf.pos + MSG_RESERVE_BYTES,
502 prbBufLeft(&frame->buf) - MSG_RESERVE_BYTES);
503 return NV_OK;
504 }
505
506 /*!
507 * @brief End a nested message
508 * @param [in] encoder The current encoder
509 * @returns NV_STATUS
510 */
511
512 NV_STATUS
prbEncNestedEnd(PRB_ENCODER * encoder)513 prbEncNestedEnd(PRB_ENCODER *encoder)
514 {
515 PRB_ENCODER_STACK_FRAME *frame;
516 PRB_VALUE value;
517 NV_STATUS status;
518
519 if (encoder->flags & PRB_ENCODE_DISABLED)
520 {
521 return NV_ERR_INVALID_REQUEST;
522 }
523
524 status = prbEndPackedField(encoder);
525 if (status != NV_OK)
526 return status;
527
528 if (encoder->depth <= 1)
529 {
530 DBG_BREAKPOINT();
531 return NV_ERR_INVALID_REQUEST;
532 }
533
534 frame = &encoder->stack[encoder->depth - 1];
535
536 encoder->depth--;
537
538 value.message.data = frame->buf.base;
539 value.message.len = prbBufUsed(&frame->buf);
540
541 return prbEncAddField(encoder, frame->field_desc, &value);
542 }
543
544 /*!
545 * @brief Return size of remaining buffer
546 * @param [in] encoder The encoder to use
547 * @returns bytes left
548 */
549
550 NvU32
prbEncBufLeft(PRB_ENCODER * encoder)551 prbEncBufLeft(PRB_ENCODER *encoder)
552 {
553 PRB_ENCODER_STACK_FRAME *frame;
554
555 if (encoder->depth <= 0)
556 {
557 DBG_BREAKPOINT();
558 return 0;
559 }
560
561 frame = &encoder->stack[encoder->depth - 1];
562
563 return prbBufLeft(&frame->buf);
564 }
565
566 /*!
567 * @brief End a packed field
568 * @param [in] encoder The encoder to use
569 * @returns NV_STATUS
570 */
571
572 static NV_STATUS
prbEndPackedField(PRB_ENCODER * encoder)573 prbEndPackedField(PRB_ENCODER *encoder)
574 {
575 PRB_ENCODER_STACK_FRAME *frame;
576 const PRB_FIELD_DESC *field_desc;
577 NV_STATUS ret;
578 NvU64 key;
579 NvU8 *packed_start;
580 NvU32 packed_len;
581
582 if (encoder->depth < 1)
583 {
584 DBG_BREAKPOINT();
585 return NV_ERR_INVALID_REQUEST;
586 }
587
588 frame = &encoder->stack[encoder->depth - 1];
589 if (encoder->flags & PRB_PACKED_FRAME)
590 {
591 // Clear the flag
592 encoder->flags &= ~PRB_PACKED_FRAME;
593
594 // Pick up field desc, packed start and length
595 packed_start = frame->buf.base;
596 packed_len = prbBufUsed(&frame->buf);
597 field_desc = frame->field_desc;
598
599 if (encoder->depth == 1)
600 {
601 DBG_BREAKPOINT();
602 return NV_ERR_INVALID_REQUEST;
603 }
604
605 // Switch to parent frame
606 encoder->depth--;
607 frame = &encoder->stack[encoder->depth - 1];
608
609 if (packed_len == 0)
610 return(NV_OK);
611
612 key = WT_STRING | (field_desc->number << 3);
613 ret = encode_varint(&frame->buf, key, COUNT_FLAG(encoder));
614 if (ret != NV_OK)
615 return ret;
616
617 ret = encode_varint(&frame->buf, packed_len, COUNT_FLAG(encoder));
618 if (ret != NV_OK)
619 return ret;
620
621 if (prbBufLeft(&frame->buf) < packed_len)
622 return NV_ERR_BUFFER_TOO_SMALL;
623
624 if (!COUNT_FLAG(encoder))
625 portMemMove(frame->buf.pos, packed_len, packed_start, packed_len);
626 frame->buf.pos += packed_len;
627 }
628 return NV_OK;
629 }
630
631 /*!
632 * @brief Add a field to a message
633 * @param [in] encoder The encoder to use
634 * @param [in] field_desc Which field to add
635 * @param [in] value The value to send
636 * @returns NV_STATUS
637 * NV_ERR_INVALID_REQUEST if the field is not found
638 */
639
640 static NV_STATUS
prbEncAddField(PRB_ENCODER * encoder,const PRB_FIELD_DESC * field_desc,PRB_VALUE * value)641 prbEncAddField(PRB_ENCODER *encoder,
642 const PRB_FIELD_DESC *field_desc,
643 PRB_VALUE *value)
644 {
645 NV_STATUS ret;
646 PRB_ENCODER_STACK_FRAME *frame;
647 NvU32 i;
648 NvU64 key;
649 WIRE_TYPE wire_type = WT_32BIT;
650 WIRE_VALUE wire_value = {0};
651
652 if (encoder->flags & PRB_ENCODE_DISABLED)
653 {
654 return NV_ERR_INVALID_REQUEST;
655 }
656
657 if (encoder->depth <= 0)
658 {
659 DBG_BREAKPOINT();
660 return NV_ERR_INVALID_REQUEST;
661 }
662
663 frame = &encoder->stack[encoder->depth - 1];
664
665 // If this field is not stubbed, then...
666 if (!(field_desc->opts.flags & PRB_STUBBED_FIELD)) {
667
668 // Check that field belongs to the current message
669 for (i = 0; i < frame->msg_desc->num_fields; i++)
670 if (field_desc == &frame->msg_desc->fields[i])
671 break;
672 if (i == frame->msg_desc->num_fields)
673 {
674 DBG_BREAKPOINT();
675 return NV_ERR_INVALID_REQUEST;
676 }
677 }
678
679 if (field_desc->opts.flags & PRB_IS_DEPRECATED)
680 {
681 // OK to read deprecated fields, but we should not write them.
682 DBG_BREAKPOINT();
683 }
684
685 if (field_desc->opts.flags & PRB_IS_PACKED)
686 {
687 // Need to start a new packed field?
688 if (frame->field_desc != field_desc)
689 {
690 ret = prbEndPackedField(encoder);
691 if (ret != NV_OK)
692 return ret;
693
694 ret = prbStartPackedField(encoder, field_desc);
695 if (ret != NV_OK)
696 return ret;
697 }
698
699 }
700 else
701 {
702 ret = prbEndPackedField(encoder);
703 if (ret != NV_OK)
704 return ret;
705 }
706
707 // Messing with packed fields may have changed depth
708 frame = &encoder->stack[encoder->depth - 1];
709
710 // Encode wire value
711 switch (field_desc->opts.typ)
712 {
713 case PRB_DOUBLE:
714 wire_type = WT_64BIT;
715 wire_value.int64 = *((NvU64 *) &value->double_);
716 break;
717 case PRB_FLOAT:
718 wire_type = WT_32BIT;
719 wire_value.int32 = *((NvU32 *) &value->float_);
720 break;
721 case PRB_INT32:
722 wire_type = WT_VARINT;
723 wire_value.varint = value->int32;
724 break;
725 case PRB_UINT32:
726 wire_type = WT_VARINT;
727 wire_value.varint = value->uint32;
728 break;
729 case PRB_SINT32:
730 // Zig-zag encoding
731 wire_type = WT_VARINT;
732 wire_value.varint = (NvU32) ((value->int32 << 1) ^ (value->int32 >> 31));
733 break;
734 case PRB_INT64:
735 wire_type = WT_VARINT;
736 wire_value.varint = value->int64;
737 break;
738 case PRB_UINT64:
739 wire_type = WT_VARINT;
740 wire_value.varint = value->uint64;
741 break;
742 case PRB_SINT64:
743 // Zig-zag encoding
744 wire_type = WT_VARINT;
745 wire_value.varint = (NvU64) ((value->int64 << 1) ^ (value->int64 >> 63));
746 break;
747 case PRB_FIXED32:
748 wire_type = WT_32BIT;
749 wire_value.int32 = value->uint32;
750 break;
751 case PRB_FIXED64:
752 wire_type = WT_64BIT;
753 wire_value.int64 = value->uint64;
754 break;
755 case PRB_SFIXED32:
756 wire_type = WT_32BIT;
757 wire_value.int32 = value->int32;
758 break;
759 case PRB_SFIXED64:
760 wire_type = WT_64BIT;
761 wire_value.int64 = value->int64;
762 break;
763 case PRB_BOOL:
764 wire_type = WT_VARINT;
765 wire_value.varint = value->bool_;
766 break;
767 case PRB_ENUM:
768 wire_type = WT_VARINT;
769 wire_value.varint = value->enum_;
770 break;
771 case PRB_STRING:
772 wire_type = WT_STRING;
773 wire_value.string.data = value->string.str;
774 wire_value.string.len = value->string.len;
775 break;
776 case PRB_BYTES:
777 wire_type = WT_STRING;
778 wire_value.string.data = value->bytes.data;
779 wire_value.string.len = value->bytes.len;
780 break;
781 case PRB_MESSAGE:
782 wire_type = WT_STRING;
783 wire_value.string.data = value->message.data;
784 wire_value.string.len = value->message.len;
785 break;
786 }
787
788 if (!(field_desc->opts.flags & PRB_IS_PACKED))
789 {
790 key = wire_type | (field_desc->number << 3);
791 ret = encode_varint(&frame->buf, key, COUNT_FLAG(encoder));
792 if (ret != NV_OK)
793 return ret;
794 }
795
796 switch (wire_type)
797 {
798 case WT_VARINT:
799 ret = encode_varint(&frame->buf, wire_value.varint, COUNT_FLAG(encoder));
800 if (ret != NV_OK)
801 return ret;
802 break;
803 case WT_64BIT:
804 ret = encode_64bit(&frame->buf, wire_value.int64, COUNT_FLAG(encoder));
805 if (ret != NV_OK)
806 return ret;
807 break;
808 case WT_STRING:
809 ret = encode_varint(&frame->buf, wire_value.string.len, COUNT_FLAG(encoder));
810 if (ret != NV_OK)
811 return ret;
812 if (prbBufLeft(&frame->buf) < wire_value.string.len)
813 return NV_ERR_BUFFER_TOO_SMALL;
814 if (!COUNT_FLAG(encoder))
815 {
816 // Use memmove() when writing a message field as the memory areas are
817 // overlapping.
818 if (field_desc->opts.typ == PRB_MESSAGE)
819 {
820 portMemMove(frame->buf.pos, (NvU32)wire_value.string.len,
821 wire_value.string.data, (NvU32)wire_value.string.len);
822 }
823 else
824 {
825 portMemCopy(frame->buf.pos, (NvU32)wire_value.string.len, wire_value.string.data, (NvU32)wire_value.string.len);
826 }
827 }
828 frame->buf.pos += wire_value.string.len;
829 break;
830 case WT_32BIT:
831 ret = encode_32bit(&frame->buf, wire_value.int32, COUNT_FLAG(encoder));
832 if (ret != NV_OK)
833 return ret;
834 break;
835 default:
836 DBG_BREAKPOINT();
837 break;
838 }
839
840 return NV_OK;
841 }
842
843 /*!
844 * @brief Encode a signed 32 bit integer argument
845 * @param [in] encoder The encoder to use
846 * @param [in] field_desc The field descriptor to use
847 * @param [in] int32 The value to encode
848 * @returns NV_STATUS
849 */
850
851 NV_STATUS
prbEncAddInt32(PRB_ENCODER * encoder,const PRB_FIELD_DESC * field_desc,NvS32 int32)852 prbEncAddInt32(PRB_ENCODER *encoder,
853 const PRB_FIELD_DESC *field_desc,
854 NvS32 int32)
855 {
856 PRB_VALUE value;
857
858 value.int32 = int32;
859 return prbEncAddField(encoder, field_desc, &value);
860 }
861
862 /*!
863 * @brief Encode an unsigned 32 bit integer argument
864 * @param [in] encoder The encoder to use
865 * @param [in] field_desc The field descriptor to use
866 * @param [in] uint32 The value to encode
867 * @returns NV_STATUS
868 */
869
870 NV_STATUS
prbEncAddUInt32(PRB_ENCODER * encoder,const PRB_FIELD_DESC * field_desc,NvU32 uint32)871 prbEncAddUInt32(PRB_ENCODER *encoder,
872 const PRB_FIELD_DESC *field_desc,
873 NvU32 uint32)
874 {
875 PRB_VALUE value;
876
877 value.uint32 = uint32;
878 return prbEncAddField(encoder, field_desc, &value);
879 }
880
881 /*!
882 * @brief Encode a 64 bit signed integer
883 * @param [in] encoder The encoder to use
884 * @param [in] field_desc The field descriptor to use
885 * @param [in] int64 The value to encode
886 * @returns NV_STATUS
887 */
888
889 NV_STATUS
prbEncAddInt64(PRB_ENCODER * encoder,const PRB_FIELD_DESC * field_desc,NvS64 int64)890 prbEncAddInt64(PRB_ENCODER *encoder,
891 const PRB_FIELD_DESC *field_desc,
892 NvS64 int64)
893 {
894 PRB_VALUE value;
895
896 value.int64 = int64;
897 return prbEncAddField(encoder, field_desc, &value);
898 }
899
900 /*!
901 * @brief Encode a 64 bit unsigned integer
902 * @param [in] encoder The encoder to use
903 * @param [in] field_desc The field descriptor to use
904 * @param [in] uint64 The value to encode
905 * @returns NV_STATUS
906 */
907
908 NV_STATUS
prbEncAddUInt64(PRB_ENCODER * encoder,const PRB_FIELD_DESC * field_desc,NvU64 uint64)909 prbEncAddUInt64(PRB_ENCODER *encoder,
910 const PRB_FIELD_DESC *field_desc,
911 NvU64 uint64)
912 {
913 PRB_VALUE value;
914
915 value.uint64 = uint64;
916 return prbEncAddField(encoder, field_desc, &value);
917 }
918
919 /*!
920 * @brief Encode a boolean
921 * @param [in] encoder The encoder to use
922 * @param [in] field_desc The field descriptor to use
923 * @param [in] bool_ The value to encode
924 * @returns NV_STATUS
925 */
926
927 NV_STATUS
prbEncAddBool(PRB_ENCODER * encoder,const PRB_FIELD_DESC * field_desc,NvBool bool_)928 prbEncAddBool(PRB_ENCODER *encoder,
929 const PRB_FIELD_DESC *field_desc,
930 NvBool bool_)
931 {
932 PRB_VALUE value;
933
934 value.bool_ = bool_;
935 return prbEncAddField(encoder, field_desc, &value);
936 }
937
938 /*!
939 * @brief Encode an enum
940 * @param [in] encoder The encoder to use
941 * @param [in] field_desc The field descriptor to use
942 * @param [in] enum_ The value to encode
943 * @returns NV_STATUS
944 */
945
946 NV_STATUS
prbEncAddEnum(PRB_ENCODER * encoder,const PRB_FIELD_DESC * field_desc,int enum_)947 prbEncAddEnum(PRB_ENCODER *encoder,
948 const PRB_FIELD_DESC *field_desc,
949 int enum_)
950 {
951 PRB_VALUE value;
952
953 value.enum_ = enum_;
954 return prbEncAddField(encoder, field_desc, &value);
955 }
956
957 /*!
958 * @brief Encode a null terminated string
959 * @param [in] encoder The encoder to use
960 * @param [in] field_desc The field descriptor to use
961 * @param [in] str The value to encode
962 * @returns NV_STATUS
963 */
964
965 NV_STATUS
prbEncAddString(PRB_ENCODER * encoder,const PRB_FIELD_DESC * field_desc,const char * str)966 prbEncAddString(PRB_ENCODER *encoder,
967 const PRB_FIELD_DESC *field_desc,
968 const char *str)
969 {
970 PRB_VALUE value;
971
972 value.string.str = str;
973 value.string.len = (NvU32)portStringLength(str);
974 return prbEncAddField(encoder, field_desc, &value);
975 }
976
977 /*!
978 * @brief Encode a byte array
979 * @param [in] encoder The encoder to use
980 * @param [in] field_desc The field descriptor to use
981 * @param [in] data The value to encode
982 * @param [in] len The length of the byte array
983 * @returns NV_STATUS
984 */
985
986 NV_STATUS
prbEncAddBytes(PRB_ENCODER * encoder,const PRB_FIELD_DESC * field_desc,const NvU8 * data,NvU32 len)987 prbEncAddBytes(PRB_ENCODER *encoder,
988 const PRB_FIELD_DESC *field_desc,
989 const NvU8 *data,
990 NvU32 len)
991 {
992 PRB_VALUE value;
993
994 value.string.str = (const char *) data;
995 value.string.len = len;
996 return prbEncAddField(encoder, field_desc, &value);
997 }
998
999 /*!
1000 * @brief concatenate a message to an encoded message stream
1001 * @param [in] encoder The encoder to use
1002 * @param [in] pMsg The pointer to the message to add to the steam
1003 * @param [in] len Length of the message
1004 * @returns NV_STATUS
1005 */
1006
1007 NV_STATUS
prbEncCatMsg(PRB_ENCODER * encoder,void * pMsg,NvU32 len)1008 prbEncCatMsg(PRB_ENCODER *encoder, void *pMsg, NvU32 len)
1009 {
1010 NV_STATUS status;
1011 NvU8 *pBuff = pMsg;
1012 NvU32 used;
1013 NvU64 msgVarint1;
1014 NvU64 msgVarint2;
1015 WIRE_TYPE msgWireType;
1016 NvU32 msgField;
1017 NvU32 msgLen;
1018 PRB_ENCODER_STACK_FRAME *frame;
1019 const PRB_FIELD_DESC *field_desc;
1020 NvU32 i;
1021
1022 // Get field, wiretype
1023 status = decode_varint(pBuff, len, &used, &msgVarint1);
1024 if (status != NV_OK)
1025 return status;
1026
1027 if (used >= len)
1028 return NV_ERR_BUFFER_TOO_SMALL;
1029
1030 msgWireType = (WIRE_TYPE)msgVarint1 & 0x7;
1031 if (msgWireType != WT_STRING)
1032 return NV_ERR_INVALID_REQUEST;
1033
1034 msgField = (NvU32)msgVarint1 >> 3;
1035
1036 // Find a field descriptor for the new message
1037 frame = &encoder->stack[encoder->depth - 1];
1038 for (i = 0; i < frame->msg_desc->num_fields; i++)
1039 {
1040 if (frame->msg_desc->fields[i].number == msgField)
1041 break;
1042 }
1043
1044 if (i == frame->msg_desc->num_fields)
1045 {
1046 DBG_BREAKPOINT();
1047 return NV_ERR_INVALID_REQUEST;
1048 }
1049 else
1050 {
1051 field_desc = &frame->msg_desc->fields[i];
1052 }
1053
1054 pBuff += used;
1055 len -= used;
1056
1057 // Get length
1058 status = decode_varint(pBuff, len, &used, &msgVarint2);
1059 if (status != NV_OK)
1060 return status;
1061
1062 msgLen = (NvU32)msgVarint2;
1063 if (msgLen > len - used)
1064 return NV_ERR_BUFFER_TOO_SMALL;
1065
1066 return prbEncAddBytes(encoder, field_desc, pBuff + used, msgLen);
1067 }
1068
1069