21
21
#include < errno.h>
22
22
#include < sys/types.h>
23
23
24
+ /* Define this to 1 to enable support for the 'isLarge' variable flag
25
+ * that instructs the encoder to send large data buffers by a direct
26
+ * write through the pipe (i.e. without copying it into a temporary
27
+ * buffer. This has definite performance benefits when using a QEMU Pipe.
28
+ *
29
+ * Set to 0 otherwise.
30
+ */
31
+ #define WITH_LARGE_SUPPORT 1
32
+
24
33
EntryPoint * ApiGen::findEntryByName (const std::string & name)
25
34
{
26
35
EntryPoint * entry = NULL ;
@@ -338,6 +347,99 @@ int ApiGen::genEncoderHeader(const std::string &filename)
338
347
return 0 ;
339
348
}
340
349
350
+ // Format the byte length expression for a given variable into a user-provided buffer
351
+ // If the variable type is not a pointer, this is simply its size as a decimal constant
352
+ // If the variable is a pointer, this will be an expression provided by the .attrib file
353
+ // through the 'len' attribute.
354
+ //
355
+ // Returns 1 if the variable is a pointer, 0 otherwise
356
+ //
357
+ static int getVarEncodingSizeExpression (Var& var, EntryPoint* e, char * buff, size_t bufflen)
358
+ {
359
+ int ret = 0 ;
360
+ if (!var.isPointer ()) {
361
+ snprintf (buff, bufflen, " %u" , (unsigned int ) var.type ()->bytes ());
362
+ } else {
363
+ ret = 1 ;
364
+ const char * lenExpr = var.lenExpression ().c_str ();
365
+ const char * varname = var.name ().c_str ();
366
+ if (e != NULL && lenExpr[0 ] == ' \0 ' ) {
367
+ fprintf (stderr, " %s: data len is undefined for '%s'\n " ,
368
+ e->name ().c_str (), varname);
369
+ }
370
+ if (var.nullAllowed ()) {
371
+ snprintf (buff, bufflen, " ((%s != NULL) ? %s : 0)" , varname, lenExpr);
372
+ } else {
373
+ snprintf (buff, bufflen, " %s" , lenExpr);
374
+ }
375
+ }
376
+ return ret;
377
+ }
378
+
379
+ static int writeVarEncodingSize (Var& var, FILE* fp)
380
+ {
381
+ int ret = 0 ;
382
+ if (!var.isPointer ()) {
383
+ fprintf (fp, " %u" , (unsigned int ) var.type ()->bytes ());
384
+ } else {
385
+ ret = 1 ;
386
+ fprintf (fp, " __size_%s" , var.name ().c_str ());
387
+ }
388
+ return ret;
389
+ }
390
+
391
+
392
+
393
+ static void writeVarEncodingExpression (Var& var, FILE* fp)
394
+ {
395
+ const char * varname = var.name ().c_str ();
396
+
397
+ if (var.isPointer ()) {
398
+ // encode a pointer header
399
+ fprintf (fp, " \t *(unsigned int *)(ptr) = __size_%s; ptr += 4;\n " , varname);
400
+
401
+ Var::PointerDir dir = var.pointerDir ();
402
+ if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) {
403
+ if (var.nullAllowed ()) {
404
+ fprintf (fp, " \t if (%s != NULL) " , varname);
405
+ } else {
406
+ fprintf (fp, " \t " );
407
+ }
408
+
409
+ if (var.packExpression ().size () != 0 ) {
410
+ fprintf (fp, " %s;" , var.packExpression ().c_str ());
411
+ } else {
412
+ fprintf (fp, " memcpy(ptr, %s, __size_%s);" ,
413
+ varname, varname);
414
+ }
415
+
416
+ fprintf (fp, " ptr += __size_%s;\n " , varname);
417
+ }
418
+ } else {
419
+ // encode a non pointer variable
420
+ if (!var.isVoid ()) {
421
+ fprintf (fp, " \t *(%s *) (ptr) = %s; ptr += %u;\n " ,
422
+ var.type ()->name ().c_str (), varname,
423
+ (uint) var.type ()->bytes ());
424
+ }
425
+ }
426
+ }
427
+
428
+ #if WITH_LARGE_SUPPORT
429
+ static void writeVarLargeEncodingExpression (Var& var, FILE* fp)
430
+ {
431
+ const char * varname = var.name ().c_str ();
432
+
433
+ fprintf (fp, " \t stream->writeFully(&__size_%s,4);\n " , varname);
434
+ if (var.nullAllowed ()) {
435
+ fprintf (fp, " \t if (%s != NULL) " , varname);
436
+ } else {
437
+ fprintf (fp, " \t " );
438
+ }
439
+ fprintf (fp, " stream->writeFully(%s, __size_%s);\n " , varname, varname);
440
+ }
441
+ #endif /* WITH_LARGE_SUPPORT */
442
+
341
443
int ApiGen::genEncoderImpl (const std::string &filename)
342
444
{
343
445
FILE *fp = fopen (filename.c_str (), " wt" );
@@ -368,109 +470,163 @@ int ApiGen::genEncoderImpl(const std::string &filename)
368
470
fprintf (fp, " {\n " );
369
471
370
472
// fprintf(fp, "\n\tDBG(\">>>> %s\\n\");\n", e->name().c_str());
371
- fprintf (fp, " \n\t %s *ctx = (%s *)self;\n\n " ,
473
+ fprintf (fp, " \n\t %s *ctx = (%s *)self;\n " ,
372
474
classname.c_str (),
373
475
classname.c_str ());
476
+ fprintf (fp, " \t IOStream *stream = ctx->m_stream;\n\n " );
477
+ VarsArray & evars = e->vars ();
478
+ size_t maxvars = evars.size ();
479
+ size_t j;
374
480
375
- // size calculation ;
376
- fprintf (fp, " \t size_t packetSize = " );
481
+ char buff[256 ];
377
482
378
- VarsArray & evars = e->vars ();
379
- size_t nvars = evars.size ();
380
- size_t npointers = 0 ;
381
- for (size_t j = 0 ; j < nvars; j++) {
382
- fprintf (fp, " %s " , j == 0 ? " " : " +" );
383
- if (evars[j].isPointer ()) {
384
- npointers++;
483
+ // Define the __size_XXX variables that contain the size of data
484
+ // associated with pointers.
485
+ for (j = 0 ; j < maxvars; j++) {
486
+ Var& var = evars[j];
385
487
386
- if (evars[j].lenExpression () == " " ) {
387
- fprintf (stderr, " %s: data len is undefined for '%s'\n " ,
388
- e->name ().c_str (), evars[j].name ().c_str ());
389
- }
488
+ if (!var.isPointer ())
489
+ continue ;
490
+
491
+ const char * varname = var.name ().c_str ();
492
+ fprintf (fp, " \t const unsigned int __size_%s = " , varname);
493
+
494
+ getVarEncodingSizeExpression (var, e, buff, sizeof (buff));
495
+ fprintf (fp, " %s;\n " , buff);
496
+ }
497
+
498
+ #if WITH_LARGE_SUPPORT
499
+ // We need to take care of 'isLarge' variable in a special way
500
+ // Anything before an isLarge variable can be packed into a single
501
+ // buffer, which is then commited. Each isLarge variable is a pointer
502
+ // to data that can be written to directly through the pipe, which
503
+ // will be instant when using a QEMU pipe
504
+
505
+ size_t nvars = 0 ;
506
+ size_t npointers = 0 ;
507
+
508
+ // First, compute the total size, 8 bytes for the opcode + payload size
509
+ fprintf (fp, " \t unsigned char *ptr;\n " );
510
+ fprintf (fp, " \t const size_t packetSize = 8" );
511
+
512
+ for (j = 0 ; j < maxvars; j++) {
513
+ fprintf (fp, " + " );
514
+ npointers += writeVarEncodingSize (evars[j], fp);
515
+ }
516
+ if (npointers > 0 ) {
517
+ fprintf (fp, " + %u*4" , npointers);
518
+ }
519
+ fprintf (fp, " ;\n " );
520
+
521
+ // We need to divide the packet into fragments. Each fragment contains
522
+ // either copied arguments to a temporary buffer, or direct writes for
523
+ // large variables.
524
+ //
525
+ // The first fragment must also contain the opcode+payload_size
526
+ //
527
+ nvars = 0 ;
528
+ while (nvars < maxvars || maxvars == 0 ) {
529
+
530
+ // Skip over non-large fields
531
+ for (j = nvars; j < maxvars; j++) {
532
+ if (evars[j].isLarge ())
533
+ break ;
534
+ }
535
+
536
+ // Write a fragment if needed.
537
+ if (nvars == 0 || j > nvars) {
538
+ const char * plus = " " ;
539
+
540
+ if (nvars == 0 && j == maxvars) {
541
+ // Simple shortcut for the common case where we don't have large variables;
542
+ fprintf (fp, " \t ptr = stream->alloc(packetSize);\n " );
390
543
391
- if (evars[j].nullAllowed ()) {
392
- fprintf (fp, " (%s != NULL ? %s : 0)" ,
393
- evars[j].name ().c_str (),
394
- evars[j].lenExpression ().c_str ());
395
544
} else {
396
- if (evars[j].pointerDir () == Var::POINTER_IN ||
397
- evars[j].pointerDir () == Var::POINTER_INOUT) {
398
- fprintf (fp, " %s" , evars[j].lenExpression ().c_str ());
399
- } else {
400
- fprintf (fp, " 0" );
545
+ // allocate buffer from the stream until the first large variable
546
+ fprintf (fp, " \t ptr = stream->alloc(" );
547
+ plus = " " ;
548
+
549
+ if (nvars == 0 ) {
550
+ fprintf (fp," 8" ); plus = " + " ;
551
+ }
552
+ if (j > nvars) {
553
+ npointers = 0 ;
554
+ for (j = nvars; j < maxvars && !evars[j].isLarge (); j++) {
555
+ fprintf (fp, " %s" , plus); plus = " + " ;
556
+ npointers += writeVarEncodingSize (evars[j], fp);
557
+ }
558
+ if (npointers > 0 ) {
559
+ fprintf (fp, " %s%u*4" , plus, npointers); plus = " + " ;
560
+ }
401
561
}
562
+ fprintf (fp," );\n " );
563
+ }
564
+
565
+ // encode packet header if needed.
566
+ if (nvars == 0 ) {
567
+ fprintf (fp, " \t *(unsigned int *)(ptr) = OP_%s; ptr += 4;\n " , e->name ().c_str ());
568
+ fprintf (fp, " \t *(unsigned int *)(ptr) = (unsigned int) packetSize; ptr += 4;\n " );
569
+ }
570
+
571
+ if (maxvars == 0 )
572
+ break ;
573
+
574
+ // encode non-large fields in this fragment
575
+ for (j = nvars; j < maxvars && !evars[j].isLarge (); j++) {
576
+ writeVarEncodingExpression (evars[j],fp);
577
+ }
578
+
579
+ // Ensure the fragment is commited if it is followed by a large variable
580
+ if (j < maxvars) {
581
+ fprintf (fp, " \t stream->flush();\n " );
402
582
}
403
- } else {
404
- fprintf (fp, " %u" , (unsigned int ) evars[j].type ()->bytes ());
405
583
}
584
+
585
+ // If we have one or more large variables, write them directly.
586
+ // As size + data
587
+ for ( ; j < maxvars && evars[j].isLarge (); j++) {
588
+ writeVarLargeEncodingExpression (evars[j], fp);
589
+ }
590
+
591
+ nvars = j;
406
592
}
407
- fprintf (fp, " %s 8 + %u * 4;\n " , nvars != 0 ? " +" : " " , (unsigned int ) npointers);
593
+
594
+ #else /* !WITH_LARGE_SUPPORT */
595
+ size_t nvars = evars.size ();
596
+ size_t npointers = 0 ;
597
+ fprintf (fp, " \t const size_t packetSize = 8" );
598
+ for (size_t j = 0 ; j < nvars; j++) {
599
+ npointers += getVarEncodingSizeExpression (evars[j],e,buff,sizeof (buff));
600
+ fprintf (fp, " + %s" , buff);
601
+ }
602
+ fprintf (fp, " + %u * 4;\n " , (unsigned int ) npointers);
408
603
409
604
// allocate buffer from the stream;
410
- fprintf (fp, " \t unsigned char *ptr = ctx->m_stream ->alloc(packetSize);\n\n " );
605
+ fprintf (fp, " \t unsigned char *ptr = stream ->alloc(packetSize);\n\n " );
411
606
412
607
// encode into the stream;
413
608
fprintf (fp, " \t *(unsigned int *)(ptr) = OP_%s; ptr += 4;\n " , e->name ().c_str ());
414
609
fprintf (fp, " \t *(unsigned int *)(ptr) = (unsigned int) packetSize; ptr += 4;\n\n " );
415
610
416
611
// out variables
417
612
for (size_t j = 0 ; j < nvars; j++) {
418
- if (evars[j].isPointer ()) {
419
- // encode a pointer header
420
- if (evars[j].nullAllowed ()) {
421
- fprintf (fp, " \t *(unsigned int *)(ptr) = (%s != NULL) ? %s : 0; ptr += 4; \n " ,
422
- evars[j].name ().c_str (), evars[j].lenExpression ().c_str ());
423
- } else {
424
- fprintf (fp, " \t *(unsigned int *)(ptr) = %s; ptr += 4; \n " ,
425
- evars[j].lenExpression ().c_str ());
426
- }
427
-
428
- Var::PointerDir dir = evars[j].pointerDir ();
429
- if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) {
430
- if (evars[j].nullAllowed ()) {
431
- fprintf (fp, " \t if (%s != NULL) " , evars[j].name ().c_str ());
432
- } else {
433
- fprintf (fp, " \t " );
434
- }
435
-
436
- if (evars[j].packExpression ().size () != 0 ) {
437
- fprintf (fp, " %s;" , evars[j].packExpression ().c_str ());
438
- } else {
439
- fprintf (fp, " memcpy(ptr, %s, %s);" ,
440
- evars[j].name ().c_str (),
441
- evars[j].lenExpression ().c_str ());
442
- }
443
-
444
- if (evars[j].nullAllowed ()) {
445
- fprintf (fp, " ptr += %s == NULL ? 0 : %s; \n " , evars[j].name ().c_str (), evars[j].lenExpression ().c_str ());
446
- } else {
447
- fprintf (fp, " ptr += %s;\n " , evars[j].lenExpression ().c_str ());
448
- }
449
- }
450
- } else {
451
- // encode a non pointer variable
452
- if (!evars[j].isVoid ()) {
453
- fprintf (fp, " \t *(%s *) (ptr) = %s; ptr += %u;\n " ,
454
- evars[j].type ()->name ().c_str (), evars[j].name ().c_str (),
455
- (uint) evars[j].type ()->bytes ());
456
- }
457
- }
613
+ writeVarEncodingExpression (evars[j], fp);
458
614
}
615
+ #endif /* !WITH_LARGE_SUPPORT */
616
+
459
617
// in variables;
460
618
for (size_t j = 0 ; j < nvars; j++) {
461
619
if (evars[j].isPointer ()) {
462
620
Var::PointerDir dir = evars[j].pointerDir ();
463
621
if (dir == Var::POINTER_INOUT || dir == Var::POINTER_OUT) {
622
+ const char * varname = evars[j].name ().c_str ();
464
623
if (evars[j].nullAllowed ()) {
465
- fprintf (fp, " \t if (%s != NULL) ctx->m_stream->readback(%s, %s);\n " ,
466
- evars[j].name ().c_str (),
467
- evars[j].name ().c_str (),
468
- evars[j].lenExpression ().c_str ());
624
+ fprintf (fp, " \t if (%s != NULL) " ,varname);
469
625
} else {
470
- fprintf (fp, " \t ctx->m_stream->readback(%s, %s);\n " ,
471
- evars[j].name ().c_str (),
472
- evars[j].lenExpression ().c_str ());
626
+ fprintf (fp, " \t " );
473
627
}
628
+ fprintf (fp, " stream->readback(%s, __size_%s);\n " ,
629
+ varname, varname);
474
630
}
475
631
}
476
632
}
@@ -482,7 +638,7 @@ int ApiGen::genEncoderImpl(const std::string &filename)
482
638
fprintf (fp, " \t return NULL;\n " );
483
639
} else if (e->retval ().type ()->name () != " void" ) {
484
640
fprintf (fp, " \n\t %s retval;\n " , e->retval ().type ()->name ().c_str ());
485
- fprintf (fp, " \t ctx->m_stream ->readback(&retval, %u);\n " ,(uint) e->retval ().type ()->bytes ());
641
+ fprintf (fp, " \t stream ->readback(&retval, %u);\n " ,(uint) e->retval ().type ()->bytes ());
486
642
fprintf (fp, " \t return retval;\n " );
487
643
}
488
644
fprintf (fp, " }\n\n " );
0 commit comments