feat: lseek(2), read(2), write(2) implementation
[lunaix-os.git] / lunaix-os / kernel / 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/spike.h>
12
13 #define BLOCK_EREAD 1
14 #define BLOCK_ESIG 2
15 #define BLOCK_ECRC 3
16 #define BLOCK_EFULL 3
17
18 LOG_MODULE("BLOCK")
19
20 #define MAX_DEV 32
21
22 struct cake_pile* lbd_pile;
23 struct block_dev** dev_registry;
24
25 int free_slot = 0;
26
27 int
28 __block_mount_partitions(struct hba_device* hd_dev);
29
30 int
31 __block_register(struct block_dev* dev);
32
33 void
34 block_init()
35 {
36     lbd_pile = cake_new_pile("block_dev", sizeof(struct block_dev), 1, 0);
37     dev_registry = vcalloc(sizeof(struct block_dev*), MAX_DEV);
38     free_slot = 0;
39 }
40
41 int
42 __block_read(struct v_file* file, void* buffer, size_t len);
43
44 int
45 __block_write(struct v_file* file, void* buffer, size_t len);
46
47 void
48 block_twifs_create()
49 {
50     struct twifs_node* dev = twifs_toplevel_node("dev", 3);
51     struct twifs_node* dev_block = twifs_dir_node(dev, "block", 5);
52
53     if (!dev_block) {
54         kprintf(KERROR "fail to create twifs node");
55         return;
56     }
57
58     struct block_dev* bdev;
59     struct twifs_node* bdev_node;
60     for (size_t i = 0; i < MAX_DEV; i++) {
61         if (!(bdev = dev_registry[i])) {
62             continue;
63         }
64
65         bdev_node =
66           twifs_dir_node(dev_block, bdev->bdev_id, strlen(bdev->bdev_id));
67         bdev_node->fops.read = __block_read;
68         bdev_node->fops.write = __block_write;
69         bdev_node->data = i;
70         bdev_node->inode->fsize = bdev->hd_dev->max_lba;
71     }
72 }
73
74 int
75 __block_read(struct v_file* file, void* buffer, size_t len)
76 {
77     int index = (int)((struct twifs_node*)file->inode->data)->data;
78     int errno;
79     struct block_dev* bdev;
80     if (index < 0 || index >= MAX_DEV || !(bdev = dev_registry[index])) {
81         return ENXIO;
82     }
83     size_t acc_size = 0, rd_size = 0, bsize = bdev->hd_dev->block_size,
84            rd_block = 0;
85     void* block = valloc(bsize);
86
87     while (acc_size < len) {
88         if (!bdev->hd_dev->ops.read_buffer(
89               bdev->hd_dev, file->f_pos + rd_block, block, bsize)) {
90             errno = ENXIO;
91             goto error;
92         }
93         rd_size = MIN(len - acc_size, bsize);
94         memcpy(buffer + acc_size, block, rd_size);
95         acc_size += rd_size;
96         rd_block++;
97     }
98
99     vfree(block);
100     return rd_block;
101
102 error:
103     vfree(block);
104     return errno;
105 }
106
107 int
108 __block_write(struct v_file* file, void* buffer, size_t len)
109 {
110     int index = (int)((struct twifs_node*)file->inode->data)->data;
111     int errno;
112     struct block_dev* bdev;
113     if (index < 0 || index >= MAX_DEV || !(bdev = dev_registry[index])) {
114         return ENXIO;
115     }
116     size_t acc_size = 0, wr_size = 0, bsize = bdev->hd_dev->block_size,
117            wr_block = 0;
118     void* block = valloc(bsize);
119
120     while (acc_size < len) {
121         wr_size = MIN(len - acc_size, bsize);
122         memcpy(block, buffer + acc_size, wr_size);
123         if (!bdev->hd_dev->ops.write_buffer(
124               bdev->hd_dev, file->f_pos + wr_block, block, bsize)) {
125             errno = ENXIO;
126             break;
127         }
128         acc_size += wr_size;
129         wr_block++;
130     }
131
132     vfree(block);
133     return wr_block;
134
135 error:
136     vfree(block);
137     return errno;
138 }
139
140 int
141 block_mount_disk(struct hba_device* hd_dev)
142 {
143     int errno = 0;
144     struct block_dev* dev = cake_grab(lbd_pile);
145     strncpy(dev->name, hd_dev->model, PARTITION_NAME_SIZE);
146     dev->hd_dev = hd_dev;
147     dev->base_lba = 0;
148     dev->end_lba = hd_dev->max_lba;
149     if (!__block_register(dev)) {
150         errno = BLOCK_EFULL;
151         goto error;
152     }
153
154     return errno;
155
156 error:
157     kprintf(KERROR "Fail to mount hd: %s[%s] (%x)\n",
158             hd_dev->model,
159             hd_dev->serial_num,
160             -errno);
161 }
162
163 // FIXME make it more general, manipulate the device through vfs mapping
164 int
165 __block_mount_partitions(struct hba_device* hd_dev)
166 {
167     int errno = 0;
168     void* buffer = valloc_dma(hd_dev->block_size);
169     if (!hd_dev->ops.read_buffer(hd_dev, 1, buffer, hd_dev->block_size)) {
170         errno = BLOCK_EREAD;
171         goto done;
172     }
173
174     struct lpt_header* header = (struct lpt_header*)buffer;
175     if (header->signature != LPT_SIG) {
176         errno = BLOCK_ESIG;
177         goto done;
178     }
179
180     if (header->crc != crc32b(buffer, sizeof(*header))) {
181         errno = BLOCK_ECRC;
182         goto done;
183     }
184
185     uint64_t lba = header->pt_start_lba;
186     int j = 0;
187     int count_per_sector = hd_dev->block_size / sizeof(struct lpt_entry);
188     while (lba < header->pt_end_lba) {
189         if (!hd_dev->ops.read_buffer(hd_dev, lba, buffer, hd_dev->block_size)) {
190             errno = BLOCK_EREAD;
191             goto done;
192         }
193         struct lpt_entry* entry = (struct lpt_entry*)buffer;
194         for (int i = 0; i < count_per_sector; i++, j++) {
195             struct block_dev* dev = cake_grab(lbd_pile);
196             strncpy(dev->name, entry->part_name, PARTITION_NAME_SIZE);
197             dev->hd_dev = hd_dev;
198             dev->base_lba = entry->base_lba;
199             dev->end_lba = entry->end_lba;
200             __block_register(dev);
201
202             if (j >= header->table_len) {
203                 goto done;
204             }
205         }
206     }
207
208 done:
209     vfree_dma(buffer);
210     return -errno;
211 }
212
213 int
214 __block_register(struct block_dev* dev)
215 {
216     if (free_slot >= MAX_DEV) {
217         return 0;
218     }
219     snprintf(dev->bdev_id, DEV_ID_SIZE, "bd%x", free_slot);
220     dev_registry[free_slot++] = dev;
221     return 1;
222 }