9
9
#include <sys/stat.h>
10
10
#include <unistd.h>
11
11
12
+ #include "common.h"
12
13
#include "device.h"
13
14
#include "riscv.h"
14
15
#include "riscv_private.h"
15
16
#include "virtio.h"
16
17
17
18
#define DISK_BLK_SIZE 512
18
19
20
+ #define VBLK_DEV_CNT_MAX 1
21
+
19
22
#define VBLK_FEATURES_0 0
20
23
#define VBLK_FEATURES_1 1 /* VIRTIO_F_VERSION_1 */
21
24
#define VBLK_QUEUE_NUM_MAX 1024
22
25
#define VBLK_QUEUE (vblk->queues[vblk->QueueSel])
23
26
27
+ #define PRIV (x ) ((struct virtio_blk_config *) x->priv)
28
+
29
+ struct virtio_blk_config {
30
+ uint64_t capacity ;
31
+ uint32_t size_max ;
32
+ uint32_t seg_max ;
33
+
34
+ struct virtio_blk_geometry {
35
+ uint16_t cylinders ;
36
+ uint8_t heads ;
37
+ uint8_t sectors ;
38
+ } geometry ;
39
+
40
+ uint32_t blk_size ;
41
+
42
+ struct virtio_blk_topology {
43
+ uint8_t physical_block_exp ;
44
+ uint8_t alignment_offset ;
45
+ uint16_t min_io_size ;
46
+ uint32_t opt_io_size ;
47
+ } topology ;
48
+
49
+ uint8_t writeback ;
50
+ uint8_t unused0 [3 ];
51
+ uint32_t max_discard_sectors ;
52
+ uint32_t max_discard_seg ;
53
+ uint32_t discard_sector_alignment ;
54
+ uint32_t max_write_zeroes_sectors ;
55
+ uint32_t max_write_zeroes_seg ;
56
+ uint8_t write_zeroes_may_unmap ;
57
+ uint8_t unused1 [3 ];
58
+ } __attribute__((packed ));
59
+
24
60
struct vblk_req_header {
25
61
uint32_t type ;
26
62
uint32_t reserved ;
27
63
uint64_t sector ;
28
64
uint8_t status ;
29
65
} __attribute__((packed ));
30
66
67
+ struct virtio_blk_config vblk_configs [VBLK_DEV_CNT_MAX ];
68
+ int vblk_dev_cnt = 0 ;
69
+
31
70
static void virtio_blk_set_fail (virtio_blk_state_t * vblk )
32
71
{
33
72
vblk -> Status |= VIRTIO_STATUS__DEVICE_NEEDS_RESET ;
@@ -52,11 +91,13 @@ static void virtio_blk_update_status(virtio_blk_state_t *vblk, uint32_t status)
52
91
/* Reset */
53
92
uint32_t * ram = vblk -> ram ;
54
93
uint32_t * disk = vblk -> disk ;
55
- uint32_t capacity = vblk -> capacity ;
94
+ void * priv = vblk -> priv ;
95
+ uint32_t capacity = PRIV (vblk )-> capacity ;
56
96
memset (vblk , 0 , sizeof (* vblk ));
57
97
vblk -> ram = ram ;
58
98
vblk -> disk = disk ;
59
- vblk -> capacity = capacity ;
99
+ vblk -> priv = priv ;
100
+ PRIV (vblk )-> capacity = capacity ;
60
101
}
61
102
62
103
static void virtio_blk_write_handler (virtio_blk_state_t * vblk ,
@@ -128,7 +169,7 @@ static int virtio_blk_desc_handler(virtio_blk_state_t *vblk,
128
169
uint8_t * status = (uint8_t * ) ((uintptr_t ) vblk -> ram + vq_desc [2 ].addr );
129
170
130
171
/* Check sector index is valid */
131
- if (sector > (vblk -> capacity - 1 )) {
172
+ if (sector > (PRIV ( vblk ) -> capacity - 1 )) {
132
173
* status = VIRTIO_BLK_S_IOERR ;
133
174
return -1 ;
134
175
}
@@ -219,125 +260,129 @@ static bool virtio_blk_reg_read(virtio_blk_state_t *vblk,
219
260
uint32_t addr ,
220
261
uint32_t * value )
221
262
{
222
- /* TODO: replace the register address with enum.
223
- * For the address after the configuration space, it should be
224
- * handled by structure pointer depend on the device.
225
- */
263
+ #define _ (reg ) VIRTIO_##reg
226
264
switch (addr ) {
227
- case 0 : /* MagicValue (R) */
265
+ case _ ( MagicValue ):
228
266
* value = 0x74726976 ;
229
267
return true;
230
- case 1 : /* Version (R) */
268
+ case _ ( Version ):
231
269
* value = 2 ;
232
270
return true;
233
- case 2 : /* DeviceID (R) */
271
+ case _ ( DeviceID ):
234
272
* value = 2 ;
235
273
return true;
236
- case 3 : /* VendorID (R) */
274
+ case _ ( VendorID ):
237
275
* value = VIRTIO_VENDOR_ID ;
238
276
return true;
239
- case 4 : /* DeviceFeatures (R) */
277
+ case _ ( DeviceFeatures ):
240
278
* value = vblk -> DeviceFeaturesSel == 0
241
279
? VBLK_FEATURES_0
242
280
: (vblk -> DeviceFeaturesSel == 1 ? VBLK_FEATURES_1 : 0 );
243
281
return true;
244
- case 13 : /* QueueNumMax (R) */
282
+ case _ ( QueueNumMax ):
245
283
* value = VBLK_QUEUE_NUM_MAX ;
246
284
return true;
247
- case 17 : /* QueueReady (RW) */
285
+ case _ ( QueueReady ):
248
286
* value = VBLK_QUEUE .ready ? 1 : 0 ;
249
287
return true;
250
- case 24 : /* InterruptStatus (R) */
288
+ case _ ( InterruptStatus ):
251
289
* value = vblk -> InterruptStatus ;
252
290
return true;
253
- case 28 : /* Status (RW) */
291
+ case _ ( Status ):
254
292
* value = vblk -> Status ;
255
293
return true;
256
- case 63 : /* ConfigGeneration (R) */
294
+ case _ ( ConfigGeneration ):
257
295
* value = 0 ;
258
296
return true;
259
- case 64 : /* CapacityLow (R) */
260
- * value = 0x00000000ffffffff & vblk -> capacity ;
261
- return true;
262
- case 65 : /* CapacityHigh (R) */
263
- * value = vblk -> capacity >> 32 ;
264
- return true;
265
297
default :
266
- return false;
298
+ /* Invalid address which exceeded the range */
299
+ if (!RANGE_CHECK (addr , _ (Config ), sizeof (struct virtio_blk_config )))
300
+ return false;
301
+
302
+ /* Read configuration from the corresponding register */
303
+ * value = ((uint32_t * ) PRIV (vblk ))[addr - _ (Config )];
304
+
305
+ return true;
267
306
}
307
+ #undef _
268
308
}
269
309
270
310
static bool virtio_blk_reg_write (virtio_blk_state_t * vblk ,
271
311
uint32_t addr ,
272
312
uint32_t value )
273
313
{
274
- /* TODO: replace the register address with enum.
275
- * For the address after the configuration space, it should be
276
- * handled by structure pointer depend on the device.
277
- */
314
+ #define _ (reg ) VIRTIO_##reg
278
315
switch (addr ) {
279
- case 5 : /* DeviceFeaturesSel (W) */
316
+ case _ ( DeviceFeaturesSel ):
280
317
vblk -> DeviceFeaturesSel = value ;
281
318
return true;
282
- case 8 : /* DriverFeatures (W) */
319
+ case _ ( DriverFeatures ):
283
320
vblk -> DriverFeaturesSel == 0 ? (vblk -> DriverFeatures = value ) : 0 ;
284
321
return true;
285
- case 9 : /* DriverFeaturesSel (W) */
322
+ case _ ( DriverFeaturesSel ):
286
323
vblk -> DriverFeaturesSel = value ;
287
324
return true;
288
- case 12 : /* QueueSel (W) */
325
+ case _ ( QueueSel ):
289
326
if (value < ARRAY_SIZE (vblk -> queues ))
290
327
vblk -> QueueSel = value ;
291
328
else
292
329
virtio_blk_set_fail (vblk );
293
330
return true;
294
- case 14 : /* QueueNum (W) */
331
+ case _ ( QueueNum ):
295
332
if (value > 0 && value <= VBLK_QUEUE_NUM_MAX )
296
333
VBLK_QUEUE .QueueNum = value ;
297
334
else
298
335
virtio_blk_set_fail (vblk );
299
336
return true;
300
- case 17 : /* QueueReady (RW) */
337
+ case _ ( QueueReady ):
301
338
VBLK_QUEUE .ready = value & 1 ;
302
339
if (value & 1 )
303
340
VBLK_QUEUE .last_avail = vblk -> ram [VBLK_QUEUE .QueueAvail ] >> 16 ;
304
341
return true;
305
- case 32 : /* QueueDescLow (W) */
342
+ case _ ( QueueDescLow ):
306
343
VBLK_QUEUE .QueueDesc = vblk_preprocess (vblk , value );
307
344
return true;
308
- case 33 : /* QueueDescHigh (W) */
345
+ case _ ( QueueDescHigh ):
309
346
if (value )
310
347
virtio_blk_set_fail (vblk );
311
348
return true;
312
- case 36 : /* QueueAvailLow (W) */
349
+ case _ ( QueueDriverLow ):
313
350
VBLK_QUEUE .QueueAvail = vblk_preprocess (vblk , value );
314
351
return true;
315
- case 37 : /* QueueAvailHigh (W) */
352
+ case _ ( QueueDriverHigh ):
316
353
if (value )
317
354
virtio_blk_set_fail (vblk );
318
355
return true;
319
- case 40 : /* QueueUsedLow (W) */
356
+ case _ ( QueueDeviceLow ):
320
357
VBLK_QUEUE .QueueUsed = vblk_preprocess (vblk , value );
321
358
return true;
322
- case 41 : /* QueueUsedHigh (W) */
359
+ case _ ( QueueDeviceHigh ):
323
360
if (value )
324
361
virtio_blk_set_fail (vblk );
325
362
return true;
326
- case 20 : /* QueueNotify (W) */
363
+ case _ ( QueueNotify ):
327
364
if (value < ARRAY_SIZE (vblk -> queues ))
328
365
virtio_queue_notify_handler (vblk , value );
329
366
else
330
367
virtio_blk_set_fail (vblk );
331
368
return true;
332
- case 25 : /* InterruptACK (W) */
369
+ case _ ( InterruptACK ):
333
370
vblk -> InterruptStatus &= ~value ;
334
371
return true;
335
- case 28 : /* Status (RW) */
372
+ case _ ( Status ):
336
373
virtio_blk_update_status (vblk , value );
337
374
return true;
338
375
default :
339
- return false;
376
+ /* Invalid address which exceeded the range */
377
+ if (!RANGE_CHECK (addr , _ (Config ), sizeof (struct virtio_blk_config )))
378
+ return false;
379
+
380
+ /* Write configuration to the corresponding register */
381
+ ((uint32_t * ) PRIV (vblk ))[addr - _ (Config )] = value ;
382
+
383
+ return true;
340
384
}
385
+ #undef _
341
386
}
342
387
343
388
void virtio_blk_read (vm_t * vm ,
@@ -386,11 +431,20 @@ void virtio_blk_write(vm_t *vm,
386
431
387
432
uint32_t * virtio_blk_init (virtio_blk_state_t * vblk , char * disk_file )
388
433
{
434
+ if (vblk_dev_cnt >= VBLK_DEV_CNT_MAX ) {
435
+ fprintf (stderr ,
436
+ "Excedded the number of virtio-blk device can be allocated.\n" );
437
+ exit (2 );
438
+ }
439
+
440
+ /* Allocate memory for the private member */
441
+ vblk -> priv = & vblk_configs [vblk_dev_cnt ++ ];
442
+
389
443
/* No disk image is provided */
390
444
if (!disk_file ) {
391
445
/* By setting the block capacity to zero, the kernel will
392
446
* then not to touch the device after booting */
393
- vblk -> capacity = 0 ;
447
+ PRIV ( vblk ) -> capacity = 0 ;
394
448
return NULL ;
395
449
}
396
450
@@ -417,7 +471,7 @@ uint32_t *virtio_blk_init(virtio_blk_state_t *vblk, char *disk_file)
417
471
close (disk_fd );
418
472
419
473
vblk -> disk = disk_mem ;
420
- vblk -> capacity = (disk_size - 1 ) / DISK_BLK_SIZE + 1 ;
474
+ PRIV ( vblk ) -> capacity = (disk_size - 1 ) / DISK_BLK_SIZE + 1 ;
421
475
422
476
return disk_mem ;
423
477
}
0 commit comments