48
48
#include <unistd.h>
49
49
#include <libxml/parser.h>
50
50
#include <libxml/tree.h>
51
+ #include <sparse/sparse.h>
51
52
#include "qdl.h"
52
53
#include "ufs.h"
53
54
55
+ #define SPARSE_BUFFER_SIZE 8
56
+
54
57
static void xml_setpropf (xmlNode * node , const char * attr , const char * fmt , ...)
55
58
{
56
59
xmlChar buf [128 ];
@@ -288,14 +291,47 @@ static int firehose_configure(struct qdl_device *qdl, bool skip_storage_init, co
288
291
#define MIN (x , y ) ((x) < (y) ? (x) : (y))
289
292
#define ROUND_UP (x , a ) (((x) + (a) - 1) & ~((a) - 1))
290
293
294
+ static int firehose_program_init (struct qdl_device * qdl , unsigned int sector_size ,
295
+ unsigned int num_sectors , unsigned int partition_number ,
296
+ const char * start_sector , const char * filename ) {
297
+ xmlNode * root ;
298
+ xmlNode * node ;
299
+ xmlDoc * doc ;
300
+ int ret ;
301
+
302
+ doc = xmlNewDoc ((xmlChar * )"1.0" );
303
+ root = xmlNewNode (NULL , (xmlChar * )"data" );
304
+ xmlDocSetRootElement (doc , root );
305
+
306
+ node = xmlNewChild (root , NULL , (xmlChar * )"program" , NULL );
307
+ xml_setpropf (node , "SECTOR_SIZE_IN_BYTES" , "%d" , sector_size );
308
+ xml_setpropf (node , "num_partition_sectors" , "%d" , num_sectors );
309
+ xml_setpropf (node , "physical_partition_number" , "%d" , partition_number );
310
+ xml_setpropf (node , "start_sector" , "%s" , start_sector );
311
+ if (filename )
312
+ xml_setpropf (node , "filename" , "%s" , filename );
313
+
314
+ ret = firehose_write (qdl , doc );
315
+ if (ret < 0 ) {
316
+ fprintf (stderr , "[PROGRAM] failed to write program command\n" );
317
+ goto out ;
318
+ }
319
+
320
+ ret = firehose_read (qdl , -1 , firehose_nop_parser );
321
+ if (ret ) {
322
+ fprintf (stderr , "[PROGRAM] failed to setup programming\n" );
323
+ goto out ;
324
+ }
325
+ out :
326
+ xmlFreeDoc (doc );
327
+ return ret ;
328
+ }
329
+
291
330
static int firehose_program (struct qdl_device * qdl , struct program * program , int fd )
292
331
{
293
332
unsigned num_sectors ;
294
333
struct stat sb ;
295
334
size_t chunk_size ;
296
- xmlNode * root ;
297
- xmlNode * node ;
298
- xmlDoc * doc ;
299
335
void * buf ;
300
336
time_t t0 ;
301
337
time_t t ;
@@ -322,27 +358,10 @@ static int firehose_program(struct qdl_device *qdl, struct program *program, int
322
358
if (!buf )
323
359
err (1 , "failed to allocate sector buffer" );
324
360
325
- doc = xmlNewDoc ((xmlChar * )"1.0" );
326
- root = xmlNewNode (NULL , (xmlChar * )"data" );
327
- xmlDocSetRootElement (doc , root );
328
-
329
- node = xmlNewChild (root , NULL , (xmlChar * )"program" , NULL );
330
- xml_setpropf (node , "SECTOR_SIZE_IN_BYTES" , "%d" , program -> sector_size );
331
- xml_setpropf (node , "num_partition_sectors" , "%d" , num_sectors );
332
- xml_setpropf (node , "physical_partition_number" , "%d" , program -> partition );
333
- xml_setpropf (node , "start_sector" , "%s" , program -> start_sector );
334
- if (program -> filename )
335
- xml_setpropf (node , "filename" , "%s" , program -> filename );
336
-
337
- ret = firehose_write (qdl , doc );
338
- if (ret < 0 ) {
339
- fprintf (stderr , "[PROGRAM] failed to write program command\n" );
340
- goto out ;
341
- }
361
+ ret = firehose_program_init (qdl , program -> sector_size , num_sectors , program -> partition ,
362
+ program -> start_sector , program -> filename );
342
363
343
- ret = firehose_read (qdl , -1 , firehose_nop_parser );
344
364
if (ret ) {
345
- fprintf (stderr , "[PROGRAM] failed to setup programming\n" );
346
365
goto out ;
347
366
}
348
367
@@ -386,10 +405,178 @@ static int firehose_program(struct qdl_device *qdl, struct program *program, int
386
405
}
387
406
388
407
out :
389
- xmlFreeDoc ( doc );
408
+ free ( buf );
390
409
return ret ;
391
410
}
392
411
412
+ struct Data {
413
+ struct program * program ;
414
+ long unsigned int offset ;
415
+ struct qdl_device * qdl ;
416
+ void * data_blob ;
417
+ int data_blob_size ;
418
+ int data_blob_count ;
419
+ };
420
+
421
+ int firehose_program_sparse_do_flash (struct qdl_device * qdl , struct program * program , const void * data , long unsigned int num_sectors , long unsigned int start_sector_offset ) {
422
+ int ret ;
423
+ int chunk_size ;
424
+ int n ;
425
+ int left ;
426
+ int offset ;
427
+ long long start_sector ;
428
+ // 2^64 requires 20 chars at max (+ an additional one for '\0')
429
+ char start_sector_str [21 ];
430
+
431
+ // Calculate new start sector
432
+ start_sector = atoll (program -> start_sector );
433
+ start_sector += start_sector_offset ;
434
+ snprintf (start_sector_str , sizeof (start_sector_str ), "%lld" , start_sector );
435
+
436
+ ret = firehose_program_init (qdl , program -> sector_size , num_sectors , program -> partition ,
437
+ start_sector_str , program -> filename );
438
+ if (ret ) {
439
+ return ret ;
440
+ }
441
+
442
+ // Send given data to the target
443
+ left = num_sectors ;
444
+ offset = 0 ;
445
+ while (left > 0 ) {
446
+ chunk_size = MIN (max_payload_size / program -> sector_size , left );
447
+
448
+ n = qdl_write (qdl , data + offset , chunk_size * program -> sector_size , true);
449
+ if (n < 0 )
450
+ err (1 , "failed to write" );
451
+
452
+ if (n != chunk_size * program -> sector_size )
453
+ err (1 , "failed to write full sector" );
454
+
455
+ left -= chunk_size ;
456
+ offset += n ;
457
+ }
458
+
459
+ ret = firehose_read (qdl , -1 , firehose_nop_parser );
460
+ if (ret ) {
461
+ fprintf (stderr , "[PROGRAM] failed\n" );
462
+ }
463
+ return ret ;
464
+ }
465
+
466
+ int firehose_program_sparse_callback (void * priv , const void * data , long unsigned int len ) {
467
+ int ret = 0 ;
468
+ long unsigned int already_flashed = 0 ;
469
+ struct Data * d = priv ;
470
+ unsigned num_sectors = 0 ;
471
+
472
+ if (data == NULL ) {
473
+ // Reached "Don't care" part --> Flash what is currently buffered
474
+ if (d -> data_blob ) {
475
+ num_sectors = (d -> data_blob_count + d -> program -> sector_size - 1 ) / d -> program -> sector_size ;
476
+
477
+ memset (d -> data_blob + d -> data_blob_count , 0 , d -> data_blob_size - d -> data_blob_count );
478
+
479
+ ret = firehose_program_sparse_do_flash (d -> qdl , d -> program , d -> data_blob , num_sectors , d -> offset );
480
+ if (ret ) {
481
+ goto out ;
482
+ }
483
+
484
+ d -> data_blob_count = 0 ;
485
+ }
486
+
487
+ d -> offset += num_sectors ;
488
+ d -> offset += (len + d -> program -> sector_size - 1 ) / d -> program -> sector_size ;
489
+ goto out ;
490
+ }
491
+ else if ((d -> data_blob_size - d -> data_blob_count ) < len ) {
492
+ // Reach part that contains data --> fill up buffer and flash if neccessary
493
+ // Fill up current buffer and flash it
494
+ already_flashed = d -> data_blob_size - d -> data_blob_count ;
495
+ memcpy (d -> data_blob + d -> data_blob_count , data , already_flashed );
496
+ d -> data_blob_count += already_flashed ;
497
+ ret = firehose_program_sparse_callback (priv , NULL , 0 );
498
+
499
+ // Flash the rest of the given data
500
+ if ((len - already_flashed ) > d -> data_blob_size ) {
501
+ num_sectors = ((len - already_flashed ) / d -> program -> sector_size );
502
+
503
+ ret = firehose_program_sparse_do_flash (d -> qdl , d -> program , data + already_flashed , num_sectors , d -> offset );
504
+ if (ret ) {
505
+ goto out ;
506
+ }
507
+ already_flashed += num_sectors * d -> program -> sector_size ;
508
+ d -> data_blob_count = 0 ;
509
+ d -> offset += num_sectors ;
510
+ }
511
+ }
512
+
513
+ memcpy (d -> data_blob + d -> data_blob_count , data + already_flashed , len - already_flashed );
514
+ d -> data_blob_count += len - already_flashed ;
515
+
516
+ out :
517
+ return ret ;
518
+ }
519
+
520
+ static int firehose_program_sparse (struct qdl_device * qdl , struct program * program , struct sparse_file * sparse )
521
+ {
522
+ unsigned num_sectors ;
523
+ time_t t0 ;
524
+ time_t t ;
525
+ int ret ;
526
+ struct Data d ;
527
+
528
+ num_sectors = program -> num_sectors ;
529
+ t0 = time (NULL );
530
+
531
+ memset (& d , 0 , sizeof (struct Data ));
532
+ d .qdl = qdl ;
533
+ d .program = program ;
534
+ d .data_blob_size = SPARSE_BUFFER_SIZE * max_payload_size ;
535
+ d .data_blob = malloc (d .data_blob_size );
536
+ if (!d .data_blob ) {
537
+ return -1 ;
538
+ }
539
+
540
+ // Process the sparse file
541
+ ret = sparse_file_callback (sparse , false, false, firehose_program_sparse_callback , & d );
542
+ if (!ret ) {
543
+ // Call once more (pretending a "Don't care" block) to flash current buffer
544
+ ret = firehose_program_sparse_callback (& d , NULL , 0 );
545
+ }
546
+ free (d .data_blob );
547
+
548
+ t = time (NULL ) - t0 ;
549
+ if (t ) {
550
+ fprintf (stderr ,
551
+ "[PROGRAM] flashed \"%s\" successfully at %ldkB/s\n" ,
552
+ program -> label ,
553
+ program -> sector_size * num_sectors / t / 1024 );
554
+ } else {
555
+ fprintf (stderr , "[PROGRAM] flashed \"%s\" successfully\n" ,
556
+ program -> label );
557
+ }
558
+
559
+ return ret ;
560
+ }
561
+
562
+ static int firehose_program_maybe_sparse (struct qdl_device * qdl , struct program * program , int fd )
563
+ {
564
+ int ret ;
565
+ struct sparse_file * sparse ;
566
+
567
+ if (!program -> sparse ) {
568
+ return firehose_program (qdl , program , fd );
569
+ } else {
570
+ sparse = sparse_file_import (fd , false, false);
571
+ if (!sparse ) {
572
+ return -1 ;
573
+ }
574
+ ret = firehose_program_sparse (qdl , program , sparse );
575
+ sparse_file_destroy (sparse );
576
+ return ret ;
577
+ }
578
+ }
579
+
393
580
static int firehose_apply_patch (struct qdl_device * qdl , struct patch * patch )
394
581
{
395
582
xmlNode * root ;
@@ -597,7 +784,7 @@ int firehose_run(struct qdl_device *qdl, const char *incdir, const char *storage
597
784
if (ret )
598
785
return ret ;
599
786
600
- ret = program_execute (qdl , firehose_program , incdir );
787
+ ret = program_execute (qdl , firehose_program_maybe_sparse , incdir );
601
788
if (ret )
602
789
return ret ;
603
790
0 commit comments