feat: lseek(2), read(2), write(2) implementation
[lunaix-os.git] / lunaix-os / kernel / block.c
index 0e28f666e2d03548a756e00ecc63e4b05b89bcb7..23b937488a9b1cd197c942e0f1dcb60d8c4404a7 100644 (file)
@@ -1,11 +1,15 @@
 #include <hal/ahci/hba.h>
+#include <klibc/stdio.h>
 #include <klibc/string.h>
 #include <lib/crc.h>
 #include <lunaix/block.h>
+#include <lunaix/fs/twifs.h>
 #include <lunaix/mm/cake.h>
 #include <lunaix/mm/valloc.h>
 #include <lunaix/syslog.h>
 
+#include <lunaix/spike.h>
+
 #define BLOCK_EREAD 1
 #define BLOCK_ESIG 2
 #define BLOCK_ECRC 3
@@ -31,6 +35,106 @@ block_init()
 {
     lbd_pile = cake_new_pile("block_dev", sizeof(struct block_dev), 1, 0);
     dev_registry = vcalloc(sizeof(struct block_dev*), MAX_DEV);
+    free_slot = 0;
+}
+
+int
+__block_read(struct v_file* file, void* buffer, size_t len);
+
+int
+__block_write(struct v_file* file, void* buffer, size_t len);
+
+void
+block_twifs_create()
+{
+    struct twifs_node* dev = twifs_toplevel_node("dev", 3);
+    struct twifs_node* dev_block = twifs_dir_node(dev, "block", 5);
+
+    if (!dev_block) {
+        kprintf(KERROR "fail to create twifs node");
+        return;
+    }
+
+    struct block_dev* bdev;
+    struct twifs_node* bdev_node;
+    for (size_t i = 0; i < MAX_DEV; i++) {
+        if (!(bdev = dev_registry[i])) {
+            continue;
+        }
+
+        bdev_node =
+          twifs_dir_node(dev_block, bdev->bdev_id, strlen(bdev->bdev_id));
+        bdev_node->fops.read = __block_read;
+        bdev_node->fops.write = __block_write;
+        bdev_node->data = i;
+        bdev_node->inode->fsize = bdev->hd_dev->max_lba;
+    }
+}
+
+int
+__block_read(struct v_file* file, void* buffer, size_t len)
+{
+    int index = (int)((struct twifs_node*)file->inode->data)->data;
+    int errno;
+    struct block_dev* bdev;
+    if (index < 0 || index >= MAX_DEV || !(bdev = dev_registry[index])) {
+        return ENXIO;
+    }
+    size_t acc_size = 0, rd_size = 0, bsize = bdev->hd_dev->block_size,
+           rd_block = 0;
+    void* block = valloc(bsize);
+
+    while (acc_size < len) {
+        if (!bdev->hd_dev->ops.read_buffer(
+              bdev->hd_dev, file->f_pos + rd_block, block, bsize)) {
+            errno = ENXIO;
+            goto error;
+        }
+        rd_size = MIN(len - acc_size, bsize);
+        memcpy(buffer + acc_size, block, rd_size);
+        acc_size += rd_size;
+        rd_block++;
+    }
+
+    vfree(block);
+    return rd_block;
+
+error:
+    vfree(block);
+    return errno;
+}
+
+int
+__block_write(struct v_file* file, void* buffer, size_t len)
+{
+    int index = (int)((struct twifs_node*)file->inode->data)->data;
+    int errno;
+    struct block_dev* bdev;
+    if (index < 0 || index >= MAX_DEV || !(bdev = dev_registry[index])) {
+        return ENXIO;
+    }
+    size_t acc_size = 0, wr_size = 0, bsize = bdev->hd_dev->block_size,
+           wr_block = 0;
+    void* block = valloc(bsize);
+
+    while (acc_size < len) {
+        wr_size = MIN(len - acc_size, bsize);
+        memcpy(block, buffer + acc_size, wr_size);
+        if (!bdev->hd_dev->ops.write_buffer(
+              bdev->hd_dev, file->f_pos + wr_block, block, bsize)) {
+            errno = ENXIO;
+            break;
+        }
+        acc_size += wr_size;
+        wr_block++;
+    }
+
+    vfree(block);
+    return wr_block;
+
+error:
+    vfree(block);
+    return errno;
 }
 
 int
@@ -47,17 +151,16 @@ block_mount_disk(struct hba_device* hd_dev)
         goto error;
     }
 
-    if ((errno = __block_mount_partitions(hd_dev))) {
-        goto error;
-    }
+    return errno;
 
 error:
-    kprintf(KERROR "Fail to mount hd: %s[%s] (%x)",
+    kprintf(KERROR "Fail to mount hd: %s[%s] (%x)\n",
             hd_dev->model,
             hd_dev->serial_num,
             -errno);
 }
 
+// FIXME make it more general, manipulate the device through vfs mapping
 int
 __block_mount_partitions(struct hba_device* hd_dev)
 {
@@ -113,7 +216,7 @@ __block_register(struct block_dev* dev)
     if (free_slot >= MAX_DEV) {
         return 0;
     }
-
+    snprintf(dev->bdev_id, DEV_ID_SIZE, "bd%x", free_slot);
     dev_registry[free_slot++] = dev;
     return 1;
 }
\ No newline at end of file