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