@@ -293,14 +293,26 @@ static void load_dtb(char **ram_loc, vm_attr_t *attr)
293
293
{
294
294
#include "minimal_dtb.h"
295
295
char * bootargs = attr -> data .system .bootargs ;
296
- char * vblk = attr -> data .system .vblk_device ;
296
+ char * * vblk = attr -> data .system .vblk_device ;
297
297
char * blob = * ram_loc ;
298
298
char * buf ;
299
299
size_t len ;
300
300
int node , err ;
301
301
int totalsize ;
302
302
303
- memcpy (blob , minimal , sizeof (minimal ));
303
+ #define DTB_EXPAND_SIZE 1024 /* or more if needed */
304
+
305
+ /* Allocate enough memory for DTB + extra room */
306
+ int minimal_len = ARRAY_SIZE (minimal );
307
+ void * dtb_buf = calloc (minimal_len + DTB_EXPAND_SIZE , sizeof (uint8_t ));
308
+ assert (dtb_buf );
309
+
310
+ /* Expand it to a usable DTB blob */
311
+ err = fdt_open_into (minimal , dtb_buf , minimal_len + DTB_EXPAND_SIZE );
312
+ if (err < 0 ) {
313
+ rv_log_error ("fdt_open_into fails\n" );
314
+ exit (EXIT_FAILURE );
315
+ }
304
316
305
317
if (bootargs ) {
306
318
node = fdt_path_offset (blob , "/chosen" );
@@ -320,18 +332,71 @@ static void load_dtb(char **ram_loc, vm_attr_t *attr)
320
332
assert (!err );
321
333
}
322
334
323
- /* remove the vblk node from soc if it is not specified */
324
- if (!vblk ) {
325
- int subnode ;
326
- node = fdt_path_offset (blob , "/soc@F0000000" );
335
+ if (vblk ) {
336
+ int node = fdt_path_offset (dtb_buf , "/soc@F0000000" );
327
337
assert (node >= 0 );
328
338
329
- subnode = fdt_subnode_offset (blob , node , "virtio@4200000" );
330
- assert (subnode >= 0 );
339
+ uint32_t base_addr = 0x4000000 ;
340
+ uint32_t addr_offset = 0x100000 ;
341
+ uint32_t size = 0x200 ;
342
+
343
+ uint32_t next_addr = base_addr ;
344
+ uint32_t next_irq = 1 ;
345
+
346
+ /* scan existing nodes to get next addr and irq */
347
+ int subnode ;
348
+ fdt_for_each_subnode (subnode , dtb_buf , node )
349
+ {
350
+ const char * name = fdt_get_name (dtb_buf , subnode , NULL );
351
+ assert (name );
352
+
353
+ uint32_t addr = strtoul (name + 7 , NULL , 16 );
354
+ if (addr == next_addr )
355
+ next_addr = addr + addr_offset ;
356
+
357
+ const fdt32_t * irq_prop =
358
+ fdt_getprop (dtb_buf , subnode , "interrupts" , NULL );
359
+ if (irq_prop ) {
360
+ uint32_t irq = fdt32_to_cpu (* irq_prop );
361
+ if (irq == next_irq )
362
+ next_irq = irq + 1 ;
363
+ }
364
+ }
365
+ /* set IRQ for virtio block, see devices/virtio.h */
366
+ attr -> vblk_irq_base = next_irq ;
367
+
368
+ /* adding new virtio block nodes */
369
+ for (int i = 0 ; i < attr -> vblk_cnt ; i ++ ) {
370
+ uint32_t new_addr = next_addr + i * addr_offset ;
371
+ uint32_t new_irq = next_irq + i ;
372
+
373
+ char node_name [32 ];
374
+ snprintf (node_name , sizeof (node_name ), "virtio@%x" , new_addr );
375
+
376
+ int subnode = fdt_add_subnode (dtb_buf , node , node_name );
377
+ if (subnode == - FDT_ERR_NOSPACE ) {
378
+ rv_log_warn ("add subnode no space!\n" );
379
+ }
380
+ assert (subnode >= 0 );
331
381
332
- assert (fdt_del_node (blob , subnode ) == 0 );
382
+ /* compatible = "virtio,mmio" */
383
+ assert (fdt_setprop_string (dtb_buf , subnode , "compatible" ,
384
+ "virtio,mmio" ) == 0 );
385
+
386
+ /* reg = <new_addr size> */
387
+ uint32_t reg [2 ] = {cpu_to_fdt32 (new_addr ), cpu_to_fdt32 (size )};
388
+ assert (fdt_setprop (dtb_buf , subnode , "reg" , reg , sizeof (reg )) == 0 );
389
+
390
+ /* interrupts = <new_irq> */
391
+ uint32_t irq = cpu_to_fdt32 (new_irq );
392
+ assert (fdt_setprop (dtb_buf , subnode , "interrupts" , & irq ,
393
+ sizeof (irq )) == 0 );
394
+ }
333
395
}
334
396
397
+ memcpy (blob , dtb_buf , minimal_len + DTB_EXPAND_SIZE );
398
+ free (dtb_buf );
399
+
335
400
totalsize = fdt_totalsize (blob );
336
401
* ram_loc += totalsize ;
337
402
return ;
@@ -406,28 +471,36 @@ static void rv_fsync_device()
406
471
*
407
472
* vblk is optional, so it could be NULL
408
473
*/
409
- if (attr -> vblk ) {
410
- if (attr -> vblk -> disk_fd >= 3 ) {
411
- if (attr -> vblk -> device_features & VIRTIO_BLK_F_RO ) /* readonly */
412
- goto end ;
413
-
414
- if (pwrite (attr -> vblk -> disk_fd , attr -> vblk -> disk ,
415
- attr -> vblk -> disk_size , 0 ) == -1 ) {
416
- rv_log_error ("pwrite block device failed: %s" , strerror (errno ));
417
- return ;
474
+ if (attr -> vblk_cnt ) {
475
+ for (int i = 0 ; i < attr -> vblk_cnt ; i ++ ) {
476
+ virtio_blk_state_t * vblk = attr -> vblk [i ];
477
+ if (vblk -> disk_fd >= 3 ) {
478
+ if (vblk -> device_features & VIRTIO_BLK_F_RO ) /* readonly */
479
+ goto end ;
480
+
481
+ if (pwrite (vblk -> disk_fd , vblk -> disk , vblk -> disk_size , 0 ) ==
482
+ -1 ) {
483
+ rv_log_error ("pwrite block device failed: %s" ,
484
+ strerror (errno ));
485
+ return ;
486
+ }
487
+
488
+ if (fsync (vblk -> disk_fd ) == -1 ) {
489
+ rv_log_error ("fsync block device failed: %s" ,
490
+ strerror (errno ));
491
+ return ;
492
+ }
493
+ rv_log_info ("Sync block device OK" );
494
+
495
+ end :
496
+ close (vblk -> disk_fd );
418
497
}
419
498
420
- if (fsync (attr -> vblk -> disk_fd ) == -1 ) {
421
- rv_log_error ("fsync block device failed: %s" , strerror (errno ));
422
- return ;
423
- }
424
- rv_log_info ("Sync block device OK" );
425
-
426
- end :
427
- close (attr -> vblk -> disk_fd );
499
+ vblk_delete (vblk );
428
500
}
429
501
430
- vblk_delete (attr -> vblk );
502
+ free (attr -> vblk );
503
+ free (attr -> disk );
431
504
}
432
505
}
433
506
#endif /* RV32_HAS(SYSTEM) && !RV32_HAS(ELF_LOADER) */
@@ -548,6 +621,9 @@ riscv_t *rv_create(riscv_user_t rv_attr)
548
621
* *----------------*----------------*-------*
549
622
*/
550
623
624
+ /* load_dtb needs the count to add the virtio block subnode dynamically */
625
+ attr -> vblk_cnt = attr -> data .system .vblk_device_cnt ;
626
+
551
627
char * ram_loc = (char * ) attr -> mem -> mem_base ;
552
628
map_file (& ram_loc , attr -> data .system .kernel );
553
629
rv_log_info ("Kernel loaded" );
@@ -590,36 +666,47 @@ riscv_t *rv_create(riscv_user_t rv_attr)
590
666
attr -> uart -> out_fd = attr -> fd_stdout ;
591
667
592
668
/* setup virtio-blk */
593
- attr -> vblk = NULL ;
594
- if (attr -> data .system .vblk_device ) {
669
+ attr -> vblk_mmio_base_hi = 0x41 ;
670
+ attr -> vblk_mmio_max_hi = attr -> vblk_mmio_base_hi + attr -> vblk_cnt ;
671
+
672
+ attr -> vblk = malloc (sizeof (virtio_blk_state_t * ) * attr -> vblk_cnt );
673
+ assert (attr -> vblk );
674
+ attr -> disk = malloc (sizeof (uint32_t * ) * attr -> vblk_cnt );
675
+ assert (attr -> disk );
676
+
677
+ if (attr -> vblk_cnt ) {
678
+ for (int i = 0 ; i < attr -> vblk_cnt ; i ++ ) {
595
679
/* Currently, only used for block image path and permission */
596
680
#define MAX_OPTS 2
597
- char * vblk_opts [MAX_OPTS ] = {NULL };
598
- int vblk_opt_idx = 0 ;
599
- char * opt = strtok (attr -> data .system .vblk_device , "," );
600
- while (opt ) {
601
- if (vblk_opt_idx == MAX_OPTS ) {
602
- rv_log_error ("Too many arguments for vblk" );
603
- break ;
681
+ char * vblk_device_str = attr -> data .system .vblk_device [i ];
682
+ char * vblk_opts [MAX_OPTS ] = {NULL };
683
+ int vblk_opt_idx = 0 ;
684
+ char * opt = strtok (vblk_device_str , "," );
685
+ while (opt ) {
686
+ if (vblk_opt_idx == MAX_OPTS ) {
687
+ rv_log_error ("Too many arguments for vblk" );
688
+ break ;
689
+ }
690
+ vblk_opts [vblk_opt_idx ++ ] = opt ;
691
+ opt = strtok (NULL , "," );
604
692
}
605
- vblk_opts [vblk_opt_idx ++ ] = opt ;
606
- opt = strtok (NULL , "," );
607
- }
608
- char * vblk_device = vblk_opts [0 ];
609
- char * vblk_readonly = vblk_opts [1 ];
610
-
611
- bool readonly = false;
612
- if (vblk_readonly ) {
613
- if (strcmp (vblk_readonly , "readonly" ) != 0 ) {
614
- rv_log_error ("Unknown vblk option: %s" , vblk_readonly );
615
- exit (EXIT_FAILURE );
693
+ char * vblk_device = vblk_opts [0 ];
694
+ char * vblk_readonly = vblk_opts [1 ];
695
+
696
+ bool readonly = false;
697
+ if (vblk_readonly ) {
698
+ if (strcmp (vblk_readonly , "readonly" ) != 0 ) {
699
+ rv_log_error ("Unknown vblk option: %s" , vblk_readonly );
700
+ exit (EXIT_FAILURE );
701
+ }
702
+ readonly = true;
616
703
}
617
- readonly = true;
618
- }
619
704
620
- attr -> vblk = vblk_new ();
621
- attr -> vblk -> ram = (uint32_t * ) attr -> mem -> mem_base ;
622
- attr -> disk = virtio_blk_init (attr -> vblk , vblk_device , readonly );
705
+ attr -> vblk [i ] = vblk_new ();
706
+ attr -> vblk [i ]-> ram = (uint32_t * ) attr -> mem -> mem_base ;
707
+ attr -> disk [i ] =
708
+ virtio_blk_init (attr -> vblk [i ], vblk_device , readonly );
709
+ }
623
710
}
624
711
625
712
capture_keyboard_input ();
0 commit comments