feat: (iso9660) directory read support
[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);
78
79     pwait(&req->wait);
80
81     if (!(errno = req->errcode)) {
82         memcpy(buf, head_buf + r, rd_size);
83         errno = len;
84     } else {
85         errno = -errno;
86     }
87
88     if (head_buf) {
89         vfree(head_buf);
90     }
91
92     blkio_free_req(req);
93     vbuf_free(vbuf);
94     return errno;
95 }
96
97 int
98 __block_write(struct device* dev, void* buf, size_t offset, size_t len)
99 {
100     struct block_dev* bdev = (struct block_dev*)dev->underlay;
101     size_t bsize = bdev->blk_size, wr_block = offset / bsize + bdev->start_lba,
102            r = offset % bsize, wr_size = 0;
103
104     if (!(len = MIN(len, ((size_t)bdev->end_lba - wr_block + 1) * bsize))) {
105         return 0;
106     }
107
108     struct vecbuf* vbuf = NULL;
109     struct blkio_req* req;
110     void* tmp_buf = NULL;
111
112     if (r) {
113         size_t wr_size = MIN(len, bsize - r);
114         tmp_buf = vzalloc(bsize);
115         vbuf_alloc(&vbuf, tmp_buf, bsize);
116
117         memcpy(tmp_buf + r, buf, wr_size);
118     }
119
120     if ((len - wr_size)) {
121         size_t llen = len - wr_size;
122         assert_msg(!(llen % bsize), "misalign block write");
123         vbuf_alloc(&vbuf, buf + wr_size, llen);
124     }
125
126     // FIXME race condition between blkio_commit and pwait.
127     //  Consider: what if scheduler complete the request before process enter
128     //  wait state?
129     req = blkio_vwr(vbuf, wr_block, NULL, NULL, 0);
130     blkio_commit(bdev->blkio, req);
131
132     pwait(&req->wait);
133
134     int errno = req->errcode;
135     if (!errno) {
136         errno = len;
137     } else {
138         errno = -errno;
139     }
140
141     if (tmp_buf) {
142         vfree(tmp_buf);
143     }
144
145     blkio_free_req(req);
146     vbuf_free(vbuf);
147     return errno;
148 }
149
150 int
151 __block_rd_lb(struct block_dev* bdev, void* buf, u64_t start, size_t count)
152 {
153     struct vecbuf* vbuf = NULL;
154     vbuf_alloc(&vbuf, buf, bdev->blk_size * count);
155
156     struct blkio_req* req = blkio_vrd(vbuf, start, NULL, NULL, 0);
157     blkio_commit(bdev->blkio, req);
158     pwait(&req->wait);
159
160     int errno = req->errcode;
161     if (!errno) {
162         errno = count;
163     } else {
164         errno = -errno;
165     }
166
167     blkio_free_req(req);
168     vbuf_free(vbuf);
169
170     return errno;
171 }
172
173 int
174 __block_wr_lb(struct block_dev* bdev, void* buf, u64_t start, size_t count)
175 {
176     struct vecbuf* vbuf = NULL;
177     vbuf_alloc(&vbuf, buf, bdev->blk_size * count);
178
179     struct blkio_req* req = blkio_vwr(vbuf, start, NULL, NULL, 0);
180     blkio_commit(bdev->blkio, req);
181     pwait(&req->wait);
182
183     int errno = req->errcode;
184     if (!errno) {
185         errno = count;
186     } else {
187         errno = -errno;
188     }
189
190     blkio_free_req(req);
191     vbuf_free(vbuf);
192
193     return errno;
194 }
195
196 void*
197 block_alloc_buf(struct block_dev* bdev)
198 {
199     return valloc(bdev->blk_size);
200 }
201
202 void
203 block_free_buf(struct block_dev* bdev, void* buf)
204 {
205     return vfree(buf);
206 }
207
208 struct block_dev*
209 block_alloc_dev(const char* blk_id, void* driver, req_handler ioreq_handler)
210 {
211     struct block_dev* bdev = cake_grab(lbd_pile);
212     memset(bdev, 0, sizeof(struct block_dev));
213     llist_init_head(&bdev->parts);
214     strncpy(bdev->name, blk_id, PARTITION_NAME_SIZE);
215
216     bdev->blkio = blkio_newctx(ioreq_handler);
217     bdev->driver = driver;
218     bdev->blkio->driver = driver;
219     bdev->ops = (struct block_dev_ops){ .block_read = __block_rd_lb,
220                                         .block_write = __block_wr_lb };
221
222     return bdev;
223 }
224
225 int
226 block_mount(struct block_dev* bdev, devfs_exporter fs_export)
227 {
228     int errno = 0;
229
230     if (!__block_register(bdev)) {
231         errno = BLOCK_EFULL;
232         goto error;
233     }
234
235     errno = blkpart_probegpt(bdev->dev);
236     if (errno < 0) {
237         kprintf(KERROR "Fail to parse partition table (%d)\n", errno);
238     } else if (!errno) {
239         // TODO try other PT parser...
240     }
241
242     struct twifs_node* dev_root = twifs_dir_node(blk_sysroot, bdev->bdev_id);
243     blk_set_blkmapping(bdev, dev_root);
244     fs_export(bdev, dev_root);
245
246     return errno;
247
248 error:
249     kprintf(KERROR "Fail to mount block device: %s (%x)\n", bdev->name, -errno);
250     return errno;
251 }
252
253 int
254 __block_register(struct block_dev* bdev)
255 {
256     if (free_slot >= MAX_DEV) {
257         return 0;
258     }
259
260     struct device* dev = device_addvol(NULL, bdev, "sd%c", 'a' + free_slot);
261     dev->write = __block_write;
262     dev->read = __block_read;
263
264     bdev->dev = dev;
265     strcpy(bdev->bdev_id, dev->name_val);
266     dev_registry[free_slot++] = bdev;
267     return 1;
268 }
269
270 struct block_dev*
271 blk_mount_part(struct block_dev* bdev,
272                const char* name,
273                size_t index,
274                u64_t start_lba,
275                u64_t end_lba)
276 {
277     struct block_dev* pbdev = cake_grab(lbd_pile);
278     memcpy(pbdev, bdev, sizeof(*bdev));
279
280     struct device* dev =
281       device_addvol(NULL, pbdev, "%sp%d", bdev->bdev_id, index + 1);
282     dev->write = __block_write;
283     dev->read = __block_read;
284
285     pbdev->start_lba = start_lba;
286     pbdev->end_lba = end_lba;
287     pbdev->dev = dev;
288
289     strcpy(pbdev->bdev_id, dev->name_val);
290     if (name) {
291         strncpy(pbdev->name, name, PARTITION_NAME_SIZE);
292     }
293
294     llist_append(&bdev->parts, &pbdev->parts);
295
296     return pbdev;
297 }