refactor: rewrite kernel's make script
[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 static struct device* blk_parent_dev;
28
29 int free_slot = 0;
30
31 int
32 __block_mount_partitions(struct hba_device* hd_dev);
33
34 int
35 __block_register(struct block_dev* dev);
36
37 void
38 block_init()
39 {
40     blkio_init();
41     lbd_pile = cake_new_pile("block_dev", sizeof(struct block_dev), 1, 0);
42     dev_registry = vcalloc(sizeof(struct block_dev*), MAX_DEV);
43     free_slot = 0;
44     blk_sysroot = twifs_dir_node(NULL, "block");
45     blk_parent_dev = device_addcat(NULL, "block");
46 }
47
48 int
49 __block_read(struct device* dev, void* buf, size_t offset, size_t len)
50 {
51     int errno;
52     struct block_dev* bdev = (struct block_dev*)dev->underlay;
53     size_t bsize = bdev->blk_size, rd_block = offset / bsize + bdev->start_lba,
54            r = offset % bsize, rd_size = 0;
55
56     if (!(len = MIN(len, ((size_t)bdev->end_lba - rd_block + 1) * bsize))) {
57         return 0;
58     }
59
60     struct vecbuf* vbuf = NULL;
61     struct blkio_req* req;
62     void *head_buf = NULL, *tail_buf = NULL;
63
64     // align the boundary
65     if (r || len < bsize) {
66         head_buf = valloc(bsize);
67         rd_size = MIN(len, bsize - r);
68         vbuf_alloc(&vbuf, head_buf, bsize);
69     }
70
71     // align the length
72     if ((len - rd_size)) {
73         size_t llen = len - rd_size;
74         assert_msg(!(llen % bsize), "misalign block read");
75         vbuf_alloc(&vbuf, buf + rd_size, llen);
76     }
77
78     req = blkio_vrd(vbuf, rd_block, NULL, NULL, 0);
79     blkio_commit(bdev->blkio, req, BLKIO_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     req = blkio_vwr(vbuf, wr_block, NULL, NULL, 0);
127     blkio_commit(bdev->blkio, req, BLKIO_WAIT);
128
129     int errno = req->errcode;
130     if (!errno) {
131         errno = len;
132     } else {
133         errno = -errno;
134     }
135
136     if (tmp_buf) {
137         vfree(tmp_buf);
138     }
139
140     blkio_free_req(req);
141     vbuf_free(vbuf);
142     return errno;
143 }
144
145 int
146 __block_read_page(struct device* dev, void* buf, size_t offset)
147 {
148     struct vecbuf* vbuf = NULL;
149     struct block_dev* bdev = (struct block_dev*)dev->underlay;
150
151     u32_t lba = offset / bdev->blk_size + bdev->start_lba;
152     u32_t rd_lba = MIN(lba + PG_SIZE / bdev->blk_size, bdev->end_lba);
153
154     if (rd_lba <= lba) {
155         return 0;
156     }
157
158     rd_lba -= lba;
159
160     vbuf_alloc(&vbuf, buf, rd_lba * bdev->blk_size);
161
162     struct blkio_req* req = blkio_vrd(vbuf, lba, NULL, NULL, 0);
163
164     blkio_commit(bdev->blkio, req, BLKIO_WAIT);
165
166     int errno = req->errcode;
167     if (!errno) {
168         errno = rd_lba * bdev->blk_size;
169     } else {
170         errno = -errno;
171     }
172
173     blkio_free_req(req);
174     vbuf_free(vbuf);
175     return errno;
176 }
177
178 int
179 __block_write_page(struct device* dev, void* buf, size_t offset)
180 {
181     struct vecbuf* vbuf = NULL;
182     struct block_dev* bdev = (struct block_dev*)dev->underlay;
183
184     u32_t lba = offset / bdev->blk_size + bdev->start_lba;
185     u32_t rd_lba = MIN(lba + PG_SIZE / bdev->blk_size, bdev->end_lba);
186
187     if (rd_lba <= lba) {
188         return 0;
189     }
190
191     rd_lba -= lba;
192
193     vbuf_alloc(&vbuf, buf, rd_lba * bdev->blk_size);
194
195     struct blkio_req* req = blkio_vwr(vbuf, lba, NULL, NULL, 0);
196
197     blkio_commit(bdev->blkio, req, BLKIO_WAIT);
198
199     int errno = req->errcode;
200     if (!errno) {
201         errno = rd_lba * bdev->blk_size;
202     } else {
203         errno = -errno;
204     }
205
206     blkio_free_req(req);
207     vbuf_free(vbuf);
208     return errno;
209 }
210
211 int
212 __block_rd_lb(struct block_dev* bdev, void* buf, u64_t start, size_t count)
213 {
214     struct vecbuf* vbuf = NULL;
215     vbuf_alloc(&vbuf, buf, bdev->blk_size * count);
216
217     struct blkio_req* req = blkio_vrd(vbuf, start, NULL, NULL, 0);
218     blkio_commit(bdev->blkio, req, BLKIO_WAIT);
219
220     int errno = req->errcode;
221     if (!errno) {
222         errno = count;
223     } else {
224         errno = -errno;
225     }
226
227     blkio_free_req(req);
228     vbuf_free(vbuf);
229
230     return errno;
231 }
232
233 int
234 __block_wr_lb(struct block_dev* bdev, void* buf, u64_t start, size_t count)
235 {
236     struct vecbuf* vbuf = NULL;
237     vbuf_alloc(&vbuf, buf, bdev->blk_size * count);
238
239     struct blkio_req* req = blkio_vwr(vbuf, start, NULL, NULL, 0);
240     blkio_commit(bdev->blkio, req, BLKIO_WAIT);
241
242     int errno = req->errcode;
243     if (!errno) {
244         errno = count;
245     } else {
246         errno = -errno;
247     }
248
249     blkio_free_req(req);
250     vbuf_free(vbuf);
251
252     return errno;
253 }
254
255 void*
256 block_alloc_buf(struct block_dev* bdev)
257 {
258     return valloc(bdev->blk_size);
259 }
260
261 void
262 block_free_buf(struct block_dev* bdev, void* buf)
263 {
264     return vfree(buf);
265 }
266
267 struct block_dev*
268 block_alloc_dev(const char* blk_id, void* driver, req_handler ioreq_handler)
269 {
270     struct block_dev* bdev = cake_grab(lbd_pile);
271     memset(bdev, 0, sizeof(struct block_dev));
272     llist_init_head(&bdev->parts);
273     strncpy(bdev->name, blk_id, PARTITION_NAME_SIZE);
274
275     bdev->blkio = blkio_newctx(ioreq_handler);
276     bdev->driver = driver;
277     bdev->blkio->driver = driver;
278     bdev->ops = (struct block_dev_ops){ .block_read = __block_rd_lb,
279                                         .block_write = __block_wr_lb };
280
281     return bdev;
282 }
283
284 int
285 block_mount(struct block_dev* bdev, devfs_exporter fs_export)
286 {
287     int errno = 0;
288
289     if (!__block_register(bdev)) {
290         errno = BLOCK_EFULL;
291         goto error;
292     }
293
294     errno = blkpart_probegpt(bdev->dev);
295     if (errno < 0) {
296         kprintf(KERROR "Fail to parse partition table (%d)\n", errno);
297     } else if (!errno) {
298         // TODO try other PT parser...
299     }
300
301     struct twifs_node* dev_root = twifs_dir_node(blk_sysroot, bdev->bdev_id);
302     blk_set_blkmapping(bdev, dev_root);
303     fs_export(bdev, dev_root);
304
305     return errno;
306
307 error:
308     kprintf(KERROR "Fail to mount block device: %s (%x)\n", bdev->name, -errno);
309     return errno;
310 }
311
312 int
313 __block_register(struct block_dev* bdev)
314 {
315     if (free_slot >= MAX_DEV) {
316         return 0;
317     }
318
319     struct device* dev =
320       device_addvol(blk_parent_dev, bdev, "sd%c", 'a' + free_slot);
321     dev->write = __block_write;
322     dev->write_page = __block_write_page;
323     dev->read = __block_read;
324     dev->read_page = __block_read_page;
325
326     bdev->dev = dev;
327     strcpy(bdev->bdev_id, dev->name_val);
328     dev_registry[free_slot++] = bdev;
329     return 1;
330 }
331
332 struct block_dev*
333 blk_mount_part(struct block_dev* bdev,
334                const char* name,
335                size_t index,
336                u64_t start_lba,
337                u64_t end_lba)
338 {
339     struct block_dev* pbdev = cake_grab(lbd_pile);
340     memcpy(pbdev, bdev, sizeof(*bdev));
341
342     struct device* dev =
343       device_addvol(NULL, pbdev, "%sp%d", bdev->bdev_id, index + 1);
344     dev->write = __block_write;
345     dev->write_page = __block_write_page;
346     dev->read = __block_read;
347     dev->read_page = __block_read_page;
348
349     pbdev->start_lba = start_lba;
350     pbdev->end_lba = end_lba;
351     pbdev->dev = dev;
352
353     strcpy(pbdev->bdev_id, dev->name_val);
354     if (name) {
355         strncpy(pbdev->name, name, PARTITION_NAME_SIZE);
356     }
357
358     llist_append(&bdev->parts, &pbdev->parts);
359
360     return pbdev;
361 }