forked from cnlohr/mini-rv32ima
-
Notifications
You must be signed in to change notification settings - Fork 0
/
virtio-blk.c
110 lines (101 loc) · 3.12 KB
/
virtio-blk.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <stdint.h>
#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "virtio.h"
#include "plic.h"
// TODO, just #include them from linux headers?
struct virtio_blk_req {
uint32_t type;
uint32_t reserved;
uint64_t sector;
};
static int fh = 0;
static uint64_t sector_count = 0;
static void openfile(struct virtio_device *dev) {
if (fh) {
} else {
fh = open("disk.img", O_RDWR | O_CLOEXEC);
assert(fh > 0);
}
uint64_t size = lseek(fh, 0, SEEK_END);
uint64_t sectors = size / 512;
if (sectors != sector_count) {
sector_count = sectors;
virtio_config_changed(dev, false);
}
}
static uint32_t virtio_blk_config_load(struct virtio_device *dev, uint32_t offset) {
openfile(dev);
uint32_t ret = 0;
switch (offset) {
case 0: // lower 32bits of size
ret = sector_count & 0xffffffff;
break;
case 4: // upper 32bits of size
ret = sector_count >> 32;
printf("%ld %d\n", sector_count, ret);
break;
}
printf("virtio_blk_config_load(%p, %d) == 0x%x\n", dev, offset, ret);
return ret;
}
static void virtio_blk_config_store(struct virtio_device *dev, uint32_t offset, uint32_t val) {
}
static void virtio_blk_process_command(struct virtio_device *dev, virtio_chain *chain, int queue, uint16_t start_idx) {
openfile(dev);
assert(chain->chain_length == 3);
assert(chain->chain[0].message_len == 16);
assert((chain->chain[0].flags & 2) == 0);
const struct virtio_blk_req *req = chain->chain[0].message;
void *buffer = chain->chain[1].message;
assert(chain->chain[2].message_len == 1);
assert(chain->chain[2].flags & 2);
uint8_t *status = chain->chain[2].message;
uint32_t written = 0;
int ret;
printf(GREEN"type: %d, sector: %ld bytes: %d\n"DEFAULT, req->type, req->sector, chain->chain[1].message_len);
switch (req->type) {
case 0: // read
assert(chain->chain[1].flags & 2); // buffer must be write type
ret = pread(fh, buffer, chain->chain[1].message_len, req->sector * 512);
if (ret == chain->chain[1].message_len) {
*status = 0;
written = chain->chain[1].message_len + 1;
} else {
written = chain->chain[1].message_len + 1;
*status = 1;
}
break;
case 1: // write
assert((chain->chain[1].flags & 2) == 0); // buffer must be read type
ret = pwrite(fh, buffer, chain->chain[1].message_len, req->sector * 512);
if (ret == chain->chain[1].message_len) {
*status = 0;
written = chain->chain[1].message_len + 1;
} else {
written = chain->chain[1].message_len + 1;
*status = 1;
}
break;
default:
*status = 2;
written = 1;
break;
}
chain->bytes_written = written;
virtio_flag_completion(dev, chain, queue, start_idx, false);
}
static const virtio_device_type virtio_blk_type = {
.device_type = 2,
.queue_count = 1,
.config_load = virtio_blk_config_load,
.config_store = virtio_blk_config_store,
.process_command = virtio_blk_process_command,
};
struct virtio_device *virtio_blk_create(void *ram_image, uint32_t base) {
return virtio_create(ram_image, &virtio_blk_type, base, 0x200, get_next_irq());
}