feat: (iso9660) implement file read (for both interleaved and non-interleaved mode)
[lunaix-os.git] / lunaix-os / kernel / block / block.c
1 #include <hal/ahci/hba.h>
2 #include <klibc/stdio.h>
3 #include <klibc/string.h>
4 #include <lib/crc.h>
5 #include <lunaix/block.h>
6 #include <lunaix/fs/twifs.h>
7 #include <lunaix/mm/cake.h>
8 #include <lunaix/mm/valloc.h>
9 #include <lunaix/syslog.h>
10
11 #include <lunaix/blkpart_gpt.h>
12
13 #include <lunaix/spike.h>
14
15 #define BLOCK_EREAD 1
16 #define BLOCK_ESIG 2
17 #define BLOCK_ECRC 3
18 #define BLOCK_EFULL 3
19
20 LOG_MODULE("BLOCK")
21
22 #define MAX_DEV 32
23
24 static struct cake_pile* lbd_pile;
25 static struct block_dev** dev_registry;
26 static struct twifs_node* blk_sysroot;
27
28 int free_slot = 0;
29
30 int
31 __block_mount_partitions(struct hba_device* hd_dev);
32
33 int
34 __block_register(struct block_dev* dev);
35
36 void
37 block_init()
38 {
39     blkio_init();
40     lbd_pile = cake_new_pile("block_dev", sizeof(struct block_dev), 1, 0);
41     dev_registry = vcalloc(sizeof(struct block_dev*), MAX_DEV);
42     free_slot = 0;
43     blk_sysroot = twifs_dir_node(NULL, "block");
44 }
45
46 int
47 __block_read(struct device* dev, void* buf, size_t offset, size_t len)
48 {
49     int errno;
50     struct block_dev* bdev = (struct block_dev*)dev->underlay;
51     size_t bsize = bdev->blk_size, rd_block = offset / bsize + bdev->start_lba,
52            r = offset % bsize, rd_size = 0;
53
54     if (!(len = MIN(len, ((size_t)bdev->end_lba - rd_block + 1) * bsize))) {
55         return 0;
56     }
57
58     struct vecbuf* vbuf = NULL;
59     struct blkio_req* req;
60     void *head_buf = NULL, *tail_buf = NULL;
61
62     // align the boundary
63     if (r || len < bsize) {
64         head_buf = valloc(bsize);
65         rd_size = MIN(len, bsize - r);
66         vbuf_alloc(&vbuf, head_buf, bsize);
67     }
68
69     // align the length
70     if ((len - rd_size)) {
71         size_t llen = len - rd_size;
72         assert_msg(!(llen % bsize), "misalign block read");
73         vbuf_alloc(&vbuf, buf + rd_size, llen);
74     }
75
76     req = blkio_vrd(vbuf, rd_block, NULL, NULL, 0);
77     blkio_commit(bdev->blkio, req, BLKIO_WAIT);
78
79     if (!(errno = req->errcode)) {
80         memcpy(buf, head_buf + r, rd_size);
81         errno = len;
82     } else {
83         errno = -errno;
84     }
85
86     if (head_buf) {
87         vfree(head_buf);
88     }
89
90     blkio_free_req(req);
91     vbuf_free(vbuf);
92     return errno;
93 }
94
95 int
96 __block_write(struct device* dev, void* buf, size_t offset, size_t len)
97 {
98     struct block_dev* bdev = (struct block_dev*)dev->underlay;
99     size_t bsize = bdev->blk_size, wr_block = offset / bsize + bdev->start_lba,
100            r = offset % bsize, wr_size = 0;
101
102     if (!(len = MIN(len, ((size_t)bdev->end_lba - wr_block + 1) * bsize))) {
103         return 0;
104     }
105
106     struct vecbuf* vbuf = NULL;
107     struct blkio_req* req;
108     void* tmp_buf = NULL;
109
110     if (r) {
111         size_t wr_size = MIN(len, bsize - r);
112         tmp_buf = vzalloc(bsize);
113         vbuf_alloc(&vbuf, tmp_buf, bsize);
114
115         memcpy(tmp_buf + r, buf, wr_size);
116     }
117
118     if ((len - wr_size)) {
119         size_t llen = len - wr_size;
120         assert_msg(!(llen % bsize), "misalign block write");
121         vbuf_alloc(&vbuf, buf + wr_size, llen);
122     }
123
124     req = blkio_vwr(vbuf, wr_block, NULL, NULL, 0);
125     blkio_commit(bdev->blkio, req, BLKIO_WAIT);
126
127     int errno = req->errcode;
128     if (!errno) {
129         errno = len;
130     } else {
131         errno = -errno;
132     }
133
134     if (tmp_buf) {
135         vfree(tmp_buf);
136     }
137
138     blkio_free_req(req);
139     vbuf_free(vbuf);
140     return errno;
141 }
142
143 int
144 __block_rd_lb(struct block_dev* bdev, void* buf, u64_t start, size_t count)
145 {
146     struct vecbuf* vbuf = NULL;
147     vbuf_alloc(&vbuf, buf, bdev->blk_size * count);
148
149     struct blkio_req* req = blkio_vrd(vbuf, start, NULL, NULL, 0);
150     blkio_commit(bdev->blkio, req, BLKIO_WAIT);
151
152     int errno = req->errcode;
153     if (!errno) {
154         errno = count;
155     } else {
156         errno = -errno;
157     }
158
159     blkio_free_req(req);
160     vbuf_free(vbuf);
161
162     return errno;
163 }
164
165 int
166 __block_wr_lb(struct block_dev* bdev, void* buf, u64_t start, size_t count)
167 {
168     struct vecbuf* vbuf = NULL;
169     vbuf_alloc(&vbuf, buf, bdev->blk_size * count);
170
171     struct blkio_req* req = blkio_vwr(vbuf, start, NULL, NULL, 0);
172     blkio_commit(bdev->blkio, req, BLKIO_WAIT);
173
174     int errno = req->errcode;
175     if (!errno) {
176         errno = count;
177     } else {
178         errno = -errno;
179     }
180
181     blkio_free_req(req);
182     vbuf_free(vbuf);
183
184     return errno;
185 }
186
187 void*
188 block_alloc_buf(struct block_dev* bdev)
189 {
190     return valloc(bdev->blk_size);
191 }
192
193 void
194 block_free_buf(struct block_dev* bdev, void* buf)
195 {
196     return vfree(buf);
197 }
198
199 struct block_dev*
200 block_alloc_dev(const char* blk_id, void* driver, req_handler ioreq_handler)
201 {
202     struct block_dev* bdev = cake_grab(lbd_pile);
203     memset(bdev, 0, sizeof(struct block_dev));
204     llist_init_head(&bdev->parts);
205     strncpy(bdev->name, blk_id, PARTITION_NAME_SIZE);
206
207     bdev->blkio = blkio_newctx(ioreq_handler);
208     bdev->driver = driver;
209     bdev->blkio->driver = driver;
210     bdev->ops = (struct block_dev_ops){ .block_read = __block_rd_lb,
211                                         .block_write = __block_wr_lb };
212
213     return bdev;
214 }
215
216 int
217 block_mount(struct block_dev* bdev, devfs_exporter fs_export)
218 {
219     int errno = 0;
220
221     if (!__block_register(bdev)) {
222         errno = BLOCK_EFULL;
223         goto error;
224     }
225
226     errno = blkpart_probegpt(bdev->dev);
227     if (errno < 0) {
228         kprintf(KERROR "Fail to parse partition table (%d)\n", errno);
229     } else if (!errno) {
230         // TODO try other PT parser...
231     }
232
233     struct twifs_node* dev_root = twifs_dir_node(blk_sysroot, bdev->bdev_id);
234     blk_set_blkmapping(bdev, dev_root);
235     fs_export(bdev, dev_root);
236
237     return errno;
238
239 error:
240     kprintf(KERROR "Fail to mount block device: %s (%x)\n", bdev->name, -errno);
241     return errno;
242 }
243
244 int
245 __block_register(struct block_dev* bdev)
246 {
247     if (free_slot >= MAX_DEV) {
248         return 0;
249     }
250
251     struct device* dev = device_addvol(NULL, bdev, "sd%c", 'a' + free_slot);
252     dev->write = __block_write;
253     dev->read = __block_read;
254
255     bdev->dev = dev;
256     strcpy(bdev->bdev_id, dev->name_val);
257     dev_registry[free_slot++] = bdev;
258     return 1;
259 }
260
261 struct block_dev*
262 blk_mount_part(struct block_dev* bdev,
263                const char* name,
264                size_t index,
265                u64_t start_lba,
266                u64_t end_lba)
267 {
268     struct block_dev* pbdev = cake_grab(lbd_pile);
269     memcpy(pbdev, bdev, sizeof(*bdev));
270
271     struct device* dev =
272       device_addvol(NULL, pbdev, "%sp%d", bdev->bdev_id, index + 1);
273     dev->write = __block_write;
274     dev->read = __block_read;
275
276     pbdev->start_lba = start_lba;
277     pbdev->end_lba = end_lba;
278     pbdev->dev = dev;
279
280     strcpy(pbdev->bdev_id, dev->name_val);
281     if (name) {
282         strncpy(pbdev->name, name, PARTITION_NAME_SIZE);
283     }
284
285     llist_append(&bdev->parts, &pbdev->parts);
286
287     return pbdev;
288 }