Merge branch 'master' into vfs-dev
authorMinep <zelong56@gmail.com>
Tue, 9 Aug 2022 14:29:17 +0000 (15:29 +0100)
committerMinep <zelong56@gmail.com>
Tue, 9 Aug 2022 14:29:17 +0000 (15:29 +0100)
71 files changed:
.gitignore
README.md
lunaix-os/.gitignore
lunaix-os/hal/acpi/acpi.c
lunaix-os/hal/acpi/parser/madt_parser.c
lunaix-os/hal/acpi/parser/mcfg_parser.c
lunaix-os/hal/ahci/ahci.c
lunaix-os/hal/ahci/ata.c
lunaix-os/hal/ahci/atapi.c
lunaix-os/hal/pci.c
lunaix-os/includes/hal/ahci/hba.h
lunaix-os/includes/hal/ahci/sata.h
lunaix-os/includes/hal/ahci/scsi.h
lunaix-os/includes/klibc/stdio.h
lunaix-os/includes/klibc/string.h
lunaix-os/includes/lib/crc.h [new file with mode: 0644]
lunaix-os/includes/lib/hash.h [new file with mode: 0644]
lunaix-os/includes/lunaix/block.h [new file with mode: 0644]
lunaix-os/includes/lunaix/clock.h
lunaix-os/includes/lunaix/common.h
lunaix-os/includes/lunaix/device.h [new file with mode: 0644]
lunaix-os/includes/lunaix/dirent.h [new file with mode: 0644]
lunaix-os/includes/lunaix/ds/btrie.h [new file with mode: 0644]
lunaix-os/includes/lunaix/ds/fifo.h [new file with mode: 0644]
lunaix-os/includes/lunaix/ds/fifobuf.h [deleted file]
lunaix-os/includes/lunaix/ds/hashtable.h [new file with mode: 0644]
lunaix-os/includes/lunaix/ds/hstr.h [new file with mode: 0644]
lunaix-os/includes/lunaix/ds/llist.h
lunaix-os/includes/lunaix/fctrl.h [new file with mode: 0644]
lunaix-os/includes/lunaix/foptions.h [new file with mode: 0644]
lunaix-os/includes/lunaix/fs.h [new file with mode: 0644]
lunaix-os/includes/lunaix/fs/twifs.h [new file with mode: 0644]
lunaix-os/includes/lunaix/lunistd.h
lunaix-os/includes/lunaix/mm/valloc.h
lunaix-os/includes/lunaix/peripheral/ps2kbd.h
lunaix-os/includes/lunaix/proc.h
lunaix-os/includes/lunaix/process.h
lunaix-os/includes/lunaix/spike.h
lunaix-os/includes/lunaix/status.h
lunaix-os/includes/lunaix/syscall.h
lunaix-os/includes/lunaix/tty/console.h
lunaix-os/includes/lunaix/types.h
lunaix-os/kernel/asm/x86/syscall.S
lunaix-os/kernel/block.c [new file with mode: 0644]
lunaix-os/kernel/demos/dir_read.c [new file with mode: 0644]
lunaix-os/kernel/demos/iotest.c [new file with mode: 0644]
lunaix-os/kernel/device.c [new file with mode: 0644]
lunaix-os/kernel/ds/btrie.c [new file with mode: 0644]
lunaix-os/kernel/ds/fifo.c [new file with mode: 0644]
lunaix-os/kernel/fs/fsm.c [new file with mode: 0644]
lunaix-os/kernel/fs/pcache.c [new file with mode: 0644]
lunaix-os/kernel/fs/twifs/twifs.c [new file with mode: 0644]
lunaix-os/kernel/fs/vfs.c [new file with mode: 0644]
lunaix-os/kernel/k_init.c
lunaix-os/kernel/lxconsole.c
lunaix-os/kernel/mm/cake.c
lunaix-os/kernel/mm/region.c
lunaix-os/kernel/mm/valloc.c
lunaix-os/kernel/mm/vmap.c
lunaix-os/kernel/peripheral/ps2kbd.c
lunaix-os/kernel/proc0.c
lunaix-os/kernel/process.c
lunaix-os/kernel/sched.c
lunaix-os/kernel/service/pconsole.c
lunaix-os/kernel/signal.c
lunaix-os/kernel/time/clock.c
lunaix-os/kernel/time/timer.c
lunaix-os/libs/crc.c [new file with mode: 0644]
lunaix-os/libs/hash.c [new file with mode: 0644]
lunaix-os/libs/klibc/stdio/sprintf.c
lunaix-os/libs/klibc/string/strcmp.c [new file with mode: 0644]

index 7aaf609286b16fd517ce2cadf2e9a21f99168cba..cd7d5b378e65524fce4fb998518503573746db26 100644 (file)
@@ -1,4 +1,4 @@
 **/.~lock*
 workspace/
 **.odp
-
+drafts/
index a349d2371799732a71a7a1c47f382a5ad32b1f47..b9a96dc024805176f5484de09b17c5aa369d8149 100644 (file)
--- a/README.md
+++ b/README.md
@@ -22,12 +22,13 @@ LunaixOS - 一个简单的,详细的,POSIX兼容的(但愿!),带有
 + 内存管理与按需分页(Demand Paging)
 + 键盘输入
 + 多进程
-+ 17个常见的Linux/POSIX系统调用([附录1](#appendix1))
++ 33个常见的Linux/POSIX系统调用([附录1](#appendix1))
 + 用户模式
 + 信号机制
 + PCI 3.0
 + PCIe 1.1 (WIP)
-+ Serial ATA AHCI (WIP)
++ Serial ATA AHCI
++ 文件系统 (WIP)
 
 ## 目录结构
 
@@ -165,10 +166,27 @@ qemu-img create -f vdi machine/disk1.vdi 128M
 1. `kill(2)`
 1. `sigpending(2)`
 1. `sigsuspend(2)`
+2. `read(2)`
+2. `write(2)`
+2. `open(2)`
+2. `close(2)`
+2. `mkdir(2)`
+2. `lseek(2)`
+2. `readdir(2)`
+2. `readlink(2)`
+2. `readlinkat(2)`
+2. `rmdir(2)`
+2. `unlink(2)`
+2. `unlinkat(2)`
+2. `link(2)`
+2. `fsync(2)`
+2. `dup(2)`
+2. `dup2(2)`
 
 ### LunaixOS自有
 
 1. `yield`
+2. `geterrno`
 
 ## 附录2:编译gcc作为交叉编译器<a id="appendix2"></a>
 
index 31aeefdf100bce92bbf5c014e55115ced31a205c..a54615d4601a27f55b01b625befcbfc31383704a 100644 (file)
@@ -5,4 +5,5 @@ playground/
 .VSCodeCounter/
 .idea
 bx_enh_dbg.ini
-machine/
\ No newline at end of file
+machine/
+draft/
\ No newline at end of file
index 0b1d9883b00ce7e381247696852ed0cb3913df2a..55c27aea4994876ef99d7232e16f94bb45e8a709 100644 (file)
@@ -1,6 +1,6 @@
 #include <hal/acpi/acpi.h>
 
-#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/valloc.h>
 #include <lunaix/spike.h>
 #include <lunaix/syslog.h>
 
@@ -26,11 +26,9 @@ acpi_init(multiboot_info_t* mb_info)
     assert_msg(rsdp, "Fail to locate ACPI_RSDP");
     assert_msg(acpi_rsdp_validate(rsdp), "Invalid ACPI_RSDP (checksum failed)");
 
-    kprintf(KDEBUG "RSDP found at %p, RSDT: %p\n", rsdp, rsdp->rsdt);
-
     acpi_rsdt_t* rsdt = rsdp->rsdt;
 
-    ctx = lxcalloc(1, sizeof(acpi_context));
+    ctx = vzalloc(sizeof(acpi_context));
     assert_msg(ctx, "Fail to create ACPI context");
 
     strncpy(ctx->oem_id, rsdt->header.oem_id, 6);
@@ -55,15 +53,7 @@ acpi_init(multiboot_info_t* mb_info)
         }
     }
 
-    kprintf(KINFO "OEM: %s\n", ctx->oem_id);
-
-    for (size_t i = 0; i < 24; i++) {
-        acpi_intso_t* intso = ctx->madt.irq_exception[i];
-        if (!intso)
-            continue;
-
-        kprintf(KDEBUG "IRQ #%u -> GSI #%u\n", intso->source, intso->gsi);
-    }
+    kprintf(KINFO "ACPI: %s\n", ctx->oem_id);
 }
 
 acpi_context*
index 971a4a0c37213079212b1b800422ca9fd763fbc3..8456b57ce9ee2efa54341f31a08aa0f9f3b72fdd 100644 (file)
@@ -1,5 +1,5 @@
 #include "parser.h"
-#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/valloc.h>
 
 void
 madt_parse(acpi_madt_t* madt, acpi_context* toc)
@@ -12,8 +12,7 @@ madt_parse(acpi_madt_t* madt, acpi_context* toc)
 
     // Cosidering only one IOAPIC present (max 24 pins)
     // FIXME: use hash table instead
-    toc->madt.irq_exception =
-      (acpi_intso_t*)lxcalloc(24, sizeof(acpi_intso_t*));
+    toc->madt.irq_exception = (acpi_intso_t*)vcalloc(24, sizeof(acpi_intso_t*));
 
     size_t so_idx = 0;
     while (ics_start < ics_end) {
index 0efe0d590ceefc954db9ad0fff1e6d508d279be3..49d04a79cb044f1aa1ba0eda7dbc1d4ab9e2b09b 100644 (file)
@@ -1,6 +1,6 @@
 #include "lunaix/syslog.h"
 #include "parser.h"
-#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/valloc.h>
 
 LOG_MODULE("MCFG")
 
@@ -13,8 +13,7 @@ mcfg_parse(acpi_sdthdr_t* mcfg, acpi_context* toc)
       (struct acpi_mcfg_alloc*)((uintptr_t)mcfg + (sizeof(acpi_sdthdr_t) + 8));
 
     toc->mcfg.alloc_num = alloc_num;
-    toc->mcfg.allocations =
-      lxmalloc(sizeof(struct mcfg_alloc_info) * alloc_num);
+    toc->mcfg.allocations = valloc(sizeof(struct mcfg_alloc_info) * alloc_num);
 
     for (size_t i = 0; i < alloc_num; i++) {
         toc->mcfg.allocations[i] = (struct mcfg_alloc_info){
index aadb41b2aaf8ca294ec80d78b86799ffafa71e9c..39e511c33fde391a965c9b455daf06dc35312b54 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <hal/pci.h>
 #include <klibc/string.h>
+#include <lunaix/block.h>
 #include <lunaix/mm/mmio.h>
 #include <lunaix/mm/pmm.h>
 #include <lunaix/mm/valloc.h>
@@ -175,6 +176,8 @@ ahci_init()
         if (!ahci_init_device(port)) {
             kprintf(KERROR "fail to init device");
         }
+
+        block_mount_disk(port->device);
     }
 }
 
@@ -277,7 +280,7 @@ hba_prepare_cmd(struct hba_port* port,
 
     // 构建命令头(Command Header)和命令表(Command Table)
     struct hba_cmdh* cmd_header = &port->cmdlst[slot];
-    struct hba_cmdt* cmd_table = vcalloc_dma(sizeof(struct hba_cmdt));
+    struct hba_cmdt* cmd_table = vzalloc_dma(sizeof(struct hba_cmdt));
 
     memset(cmd_header, 0, sizeof(*cmd_header));
 
@@ -316,7 +319,8 @@ ahci_init_device(struct hba_port* port)
 
     // 清空任何待响应的中断
     port->regs[HBA_RPxIS] = 0;
-    port->device = vcalloc(sizeof(struct hba_device));
+    port->device = vzalloc(sizeof(struct hba_device));
+    port->device->port = port;
 
     // 在命令表中构建命令FIS
     struct sata_reg_fis* cmd_fis = (struct sata_reg_fis*)cmd_table->command_fis;
index f6ff7c15a43acc04f2ac4be1b4c1353e524ee727..a2f10ba769bfa49c24e7440baae63b7e98231c65 100644 (file)
@@ -6,7 +6,7 @@
 #include <lunaix/spike.h>
 
 int
-__sata_buffer_io(struct hba_port* port,
+__sata_buffer_io(struct hba_device* dev,
                  uint64_t lba,
                  void* buffer,
                  uint32_t size,
@@ -14,6 +14,7 @@ __sata_buffer_io(struct hba_port* port,
 {
     assert_msg(((uintptr_t)buffer & 0x3) == 0, "HBA: Bad buffer alignment");
 
+    struct hba_port* port = dev->port;
     struct hba_cmdh* header;
     struct hba_cmdt* table;
     int slot = hba_prepare_cmd(port, &table, &header, buffer, size);
@@ -70,21 +71,21 @@ fail:
 }
 
 int
-sata_read_buffer(struct hba_port* port,
+sata_read_buffer(struct hba_device* dev,
                  uint64_t lba,
                  void* buffer,
                  uint32_t size)
 {
-    return __sata_buffer_io(port, lba, buffer, size, 0);
+    return __sata_buffer_io(dev, lba, buffer, size, 0);
 }
 
 int
-sata_write_buffer(struct hba_port* port,
+sata_write_buffer(struct hba_device* dev,
                   uint64_t lba,
                   void* buffer,
                   uint32_t size)
 {
-    return __sata_buffer_io(port, lba, buffer, size, 1);
+    return __sata_buffer_io(dev, lba, buffer, size, 1);
 }
 
 void
index 397c7338033602ab916f23589fab9e99388a151a..0ef5099404b3bfa5a0f5a1211858743620662835 100644 (file)
@@ -42,7 +42,7 @@ scsi_parse_capacity(struct hba_device* device, uint32_t* parameter)
 }
 
 void
-__scsi_buffer_io(struct hba_port* port,
+__scsi_buffer_io(struct hba_device* dev,
                  uint64_t lba,
                  void* buffer,
                  uint32_t size,
@@ -50,6 +50,7 @@ __scsi_buffer_io(struct hba_port* port,
 {
     assert_msg(((uintptr_t)buffer & 0x3) == 0, "HBA: Bad buffer alignment");
 
+    struct hba_port* port = dev->port;
     struct hba_cmdh* header;
     struct hba_cmdt* table;
     int slot = hba_prepare_cmd(port, &table, &header, buffer, size);
@@ -107,19 +108,19 @@ fail:
 }
 
 void
-scsi_read_buffer(struct hba_port* port,
+scsi_read_buffer(struct hba_device* dev,
                  uint64_t lba,
                  void* buffer,
                  uint32_t size)
 {
-    __scsi_buffer_io(port, lba, buffer, size, 0);
+    __scsi_buffer_io(dev, lba, buffer, size, 0);
 }
 
 void
-scsi_write_buffer(struct hba_port* port,
+scsi_write_buffer(struct hba_device* dev,
                   uint64_t lba,
                   void* buffer,
                   uint32_t size)
 {
-    __scsi_buffer_io(port, lba, buffer, size, 1);
+    __scsi_buffer_io(dev, lba, buffer, size, 1);
 }
\ No newline at end of file
index 8c397b031b85f739b2331aeb2b512cb3931756b9..d6267682475ff74fafdffc7e23eb0796c5caad6b 100644 (file)
@@ -11,7 +11,7 @@
 #include <hal/acpi/acpi.h>
 #include <hal/apic.h>
 #include <hal/pci.h>
-#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/valloc.h>
 #include <lunaix/spike.h>
 #include <lunaix/syslog.h>
 
@@ -55,7 +55,7 @@ pci_probe_device(int bus, int dev, int funct)
     pci_reg_t intr = pci_read_cspace(base, 0x3c);
     pci_reg_t class = pci_read_cspace(base, 0x8);
 
-    struct pci_device* device = lxmalloc(sizeof(struct pci_device));
+    struct pci_device* device = valloc(sizeof(struct pci_device));
     *device = (struct pci_device){ .cspace_base = base,
                                    .class_info = class,
                                    .device_info = reg1,
@@ -196,7 +196,7 @@ pci_setup_msi(struct pci_device* device, int vector)
     }
 
     // manipulate the MSI_CTRL to allow device using MSI to request service.
-    reg1 = ((((reg1 >> 16) & ~0x70) | MSI_CAP_ENABLE) << 16) | (reg1 & 0xffff);
+    reg1 = (reg1 & 0xff8fffff) | 0x10000;
     pci_write_cspace(device->cspace_base, device->msi_loc, reg1);
 }
 
index f65a93d460563202679337bf66d8706dda49eb69..334acd508a7dda0562478b00f88b35aed7acac9e 100644 (file)
@@ -105,15 +105,16 @@ struct hba_device
     uint32_t alignment_offset;
     uint32_t block_per_sec;
     uint32_t capabilities;
+    struct hba_port* port;
 
     struct
     {
-        int (*identify)(struct hba_port* port);
-        int (*read_buffer)(struct hba_port* port,
+        int (*identify)(struct hba_device* dev);
+        int (*read_buffer)(struct hba_device* dev,
                            uint64_t lba,
                            void* buffer,
                            uint32_t size);
-        int (*write_buffer)(struct hba_port* port,
+        int (*write_buffer)(struct hba_device* dev,
                             uint64_t lba,
                             void* buffer,
                             uint32_t size);
index 99a45bc20c191cb60396b41634d1f18a68f4086e..dc934482c4e4799d95e95a56f3732f5f4c8ba46b 100644 (file)
@@ -54,13 +54,13 @@ sata_create_fis(struct sata_reg_fis* cmd_fis,
                 uint16_t sector_count);
 
 int
-sata_read_buffer(struct hba_port* port,
+sata_read_buffer(struct hba_device* dev,
                  uint64_t lba,
                  void* buffer,
                  uint32_t size);
 
 int
-sata_write_buffer(struct hba_port* port,
+sata_write_buffer(struct hba_device* dev,
                   uint64_t lba,
                   void* buffer,
                   uint32_t size);
index cce9af467725486a33985d09068071db1b7e68e8..6ba0fc2596df2b6eacdf349a2139bb7ad00f7ccf 100644 (file)
@@ -48,13 +48,13 @@ scsi_create_packet16(struct scsi_cdb16* cdb,
                      uint32_t alloc_size);
 
 void
-scsi_read_buffer(struct hba_port* port,
+scsi_read_buffer(struct hba_device* dev,
                  uint64_t lba,
                  void* buffer,
                  uint32_t size);
 
 void
-scsi_write_buffer(struct hba_port* port,
+scsi_write_buffer(struct hba_device* dev,
                   uint64_t lba,
                   void* buffer,
                   uint32_t size);
index 07f47169a9c5e9726c55c12107c76fad63d937df..d97f0285968d09e16bac247760d29b2157381280 100644 (file)
@@ -3,9 +3,11 @@
 #include <stdarg.h>
 #include <stddef.h>
 
-void
+size_t
 __sprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs);
 
-void sprintf(char* buffer, char* fmt, ...);
-void snprintf(char* buffer, size_t n, char* fmt, ...);
+size_t
+sprintf(char* buffer, char* fmt, ...);
+size_t
+snprintf(char* buffer, size_t n, char* fmt, ...);
 #endif /* __LUNAIX_STDIO_H */
index 8337ef188278663813ec1b4dcdd04d1281906256..35fd53e76c97e8a79697a7d604038ce1eb930889 100644 (file)
@@ -30,4 +30,7 @@ strncpy(char* dest, const char* src, size_t n);
 const char*
 strchr(const char* str, int character);
 
+int
+streq(const char* a, const char* b);
+
 #endif /* __LUNAIX_STRING_H */
diff --git a/lunaix-os/includes/lib/crc.h b/lunaix-os/includes/lib/crc.h
new file mode 100644 (file)
index 0000000..4e9c4db
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __LUNAIX_CRC_H
+#define __LUNAIX_CRC_H
+unsigned int
+crc32b(unsigned char* data, unsigned int size);
+
+#endif /* __LUNAIX_CRC_H */
diff --git a/lunaix-os/includes/lib/hash.h b/lunaix-os/includes/lib/hash.h
new file mode 100644 (file)
index 0000000..ad5e98b
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __LUNAIX_HASH_H
+#define __LUNAIX_HASH_H
+
+#include <stdint.h>
+
+#define HASH_SIZE_BITS 32
+
+uint32_t
+strhash_32(unsigned char* str, uint32_t truncate_to);
+
+/**
+ * @brief Simple generic hash function
+ *
+ * ref:
+ * https://elixir.bootlin.com/linux/v5.18.12/source/include/linux/hash.h#L60
+ *
+ * @param val
+ * @return uint32_t
+ */
+inline uint32_t
+hash_32(uint32_t val, uint32_t truncate_to)
+{
+    return (val * 0x61C88647u) >> (HASH_SIZE_BITS - truncate_to);
+}
+
+#endif /* __LUNAIX_HASH_H */
diff --git a/lunaix-os/includes/lunaix/block.h b/lunaix-os/includes/lunaix/block.h
new file mode 100644 (file)
index 0000000..40935f9
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef __LUNAIX_BLOCK_H
+#define __LUNAIX_BLOCK_H
+
+#include <hal/ahci/hba.h>
+#include <lunaix/device.h>
+
+#define LPT_SIG 0x414e554c
+#define PARTITION_NAME_SIZE 48
+#define DEV_ID_SIZE 32
+
+typedef uint64_t partition_t;
+typedef uint32_t bdev_t;
+
+struct block_dev
+{
+    char bdev_id[DEV_ID_SIZE];
+    char name[PARTITION_NAME_SIZE];
+    struct hba_device* hd_dev;
+    struct device* dev;
+    uint64_t base_lba;
+    uint64_t end_lba;
+};
+
+struct lpt_entry
+{
+    char part_name[PARTITION_NAME_SIZE];
+    uint64_t base_lba;
+    uint64_t end_lba;
+} __attribute__((packed));
+
+// Lunaix Partition Table
+struct lpt_header
+{
+    uint32_t signature;
+    uint32_t crc;
+    uint32_t pt_start_lba;
+    uint32_t pt_end_lba;
+    uint32_t table_len;
+} __attribute__((packed));
+
+void
+block_init();
+
+int
+block_mount_disk(struct hba_device* hd_dev);
+
+#endif /* __LUNAIX_BLOCK_H */
index dbfdfe5d8b13a79bf40430c0a2f9e6f1730bde7f..44dfa04b7da5c8e0bcdd3f5b844877d10ca0dfa3 100644 (file)
@@ -7,7 +7,7 @@ typedef uint32_t time_t;
 
 typedef struct
 {
-    uint32_t year;      // use int32 as we need to store the 4-digit year
+    uint32_t year; // use int32 as we need to store the 4-digit year
     uint8_t month;
     uint8_t day;
     uint8_t weekday;
@@ -19,7 +19,7 @@ typedef struct
 void
 clock_init();
 
-void 
+void
 clock_walltime(datetime_t* datetime);
 
 int
@@ -27,10 +27,21 @@ clock_datatime_eq(datetime_t* a, datetime_t* b);
 
 /**
  * @brief 返回当前系统时间,即自从开机到当前时刻的毫秒时。
- * 
- * @return time_t 
+ *
+ * @return time_t
  */
-time_t 
+time_t
 clock_systime();
 
+time_t
+clock_unixtime();
+
+static inline time_t
+clock_tounixtime(datetime_t* dt)
+{
+    return (dt->year - 1970) * 31556926u + (dt->month - 1) * 2629743u +
+           (dt->day - 1) * 86400u + (dt->hour - 1) * 3600u +
+           (dt->minute - 1) * 60u + dt->second;
+}
+
 #endif /* __LUNAIX_CLOCK_H */
index 7fdf0b30cbe88327a0cd111ff34f643a9f972dbc..d341daa341120feca19b36510b7987d657cbcf46 100644 (file)
@@ -48,7 +48,7 @@
 #define container_of(ptr, type, member)                                        \
     ({                                                                         \
         const typeof(((type*)0)->member)* __mptr = (ptr);                      \
-        (type*)((char*)__mptr - offsetof(type, member));                       \
+        (ptr) ? (type*)((char*)__mptr - offsetof(type, member)) : 0;           \
     })
 
 #endif
diff --git a/lunaix-os/includes/lunaix/device.h b/lunaix-os/includes/lunaix/device.h
new file mode 100644 (file)
index 0000000..08d25c4
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __LUNAIX_DEVICE_H
+#define __LUNAIX_DEVICE_H
+
+#define DEVICE_NAME_SIZE 32
+
+#include <lunaix/ds/hstr.h>
+#include <lunaix/ds/llist.h>
+
+struct device
+{
+    struct llist_header dev_list;
+    struct device* parent;
+    struct hstr name;
+    char name_val[DEVICE_NAME_SIZE];
+    void* underlay;
+    void* fs_node;
+    int (*read)(struct device* dev,
+                void* buf,
+                unsigned int offset,
+                unsigned int len);
+    int (*write)(struct device* dev,
+                 void* buf,
+                 unsigned int offset,
+                 unsigned int len);
+};
+
+void
+device_init();
+
+struct device*
+device_addseq(struct device* parent, void* underlay, char* name_fmt, ...);
+
+struct device*
+device_addvol(struct device* parent, void* underlay, char* name_fmt, ...);
+
+void
+device_remove(struct device* dev);
+
+#endif /* __LUNAIX_DEVICE_H */
diff --git a/lunaix-os/includes/lunaix/dirent.h b/lunaix-os/includes/lunaix/dirent.h
new file mode 100644 (file)
index 0000000..faa56a6
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __LUNAIX_DIRENT_H
+#define __LUNAIX_DIRENT_H
+
+#define DIRENT_NAME_MAX_LEN 256
+
+struct dirent
+{
+    unsigned int d_type;
+    unsigned int d_offset;
+    unsigned int d_nlen;
+    char d_name[DIRENT_NAME_MAX_LEN];
+};
+
+#endif /* __LUNAIX_DIRENT_H */
diff --git a/lunaix-os/includes/lunaix/ds/btrie.h b/lunaix-os/includes/lunaix/ds/btrie.h
new file mode 100644 (file)
index 0000000..ad3d04c
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef __LUNAIX_SPARSE_H
+#define __LUNAIX_SPARSE_H
+
+#include <lunaix/ds/llist.h>
+#include <lunaix/types.h>
+
+#define BTRIE_BITS 4
+
+struct btrie
+{
+    struct btrie_node* btrie_root;
+    int truncated;
+};
+
+struct btrie_node
+{
+    struct llist_header children;
+    struct llist_header siblings;
+    struct llist_header nodes;
+    struct btrie_node* parent;
+    uint32_t index;
+    void* data;
+};
+
+void
+btrie_init(struct btrie* btrie, uint32_t trunc_bits);
+
+void*
+btrie_get(struct btrie* root, uint32_t index);
+
+void
+btrie_set(struct btrie* root, uint32_t index, void* data);
+
+void*
+btrie_remove(struct btrie* root, uint32_t index);
+
+void
+btrie_release(struct btrie* tree);
+
+#endif /* __LUNAIX_SPARSE_H */
diff --git a/lunaix-os/includes/lunaix/ds/fifo.h b/lunaix-os/includes/lunaix/ds/fifo.h
new file mode 100644 (file)
index 0000000..3a21824
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __LUNAIX_FIFO_BUF_H
+#define __LUNAIX_FIFO_BUF_H
+
+#include <lunaix/ds/mutex.h>
+#include <lunaix/types.h>
+
+#define FIFO_DIRTY 1
+
+struct fifo_buf
+{
+    void* data;
+    size_t wr_pos;
+    size_t rd_pos;
+    size_t size;
+    size_t free_len;
+    size_t flags;
+    mutex_t lock;
+};
+
+int
+fifo_backone(struct fifo_buf* fbuf);
+
+size_t
+fifo_putone(struct fifo_buf* fbuf, uint8_t data);
+
+void
+fifo_init(struct fifo_buf* buf, void* data_buffer, size_t buf_size, int flags);
+
+size_t
+fifo_write(struct fifo_buf* fbuf, void* data, size_t count);
+
+size_t
+fifo_read(struct fifo_buf* fbuf, void* buf, size_t count);
+
+#endif /* __LUNAIX_FIFO_BUF_H */
diff --git a/lunaix-os/includes/lunaix/ds/fifobuf.h b/lunaix-os/includes/lunaix/ds/fifobuf.h
deleted file mode 100644 (file)
index f5f08c1..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef __LUNAIX_FIFO_BUF_H
-#define __LUNAIX_FIFO_BUF_H
-
-#include <lunaix/ds/mutex.h>
-
-#define FIFO_DIRTY 1
-
-struct fifo_buffer
-{
-    void* data;
-    unsigned int wr_pos;
-    unsigned int rd_pos;
-    unsigned int size;
-    unsigned int flags;
-    mutex_t lock;
-};
-
-#endif /* __LUNAIX_FIFO_BUF_H */
diff --git a/lunaix-os/includes/lunaix/ds/hashtable.h b/lunaix-os/includes/lunaix/ds/hashtable.h
new file mode 100644 (file)
index 0000000..0e8c691
--- /dev/null
@@ -0,0 +1,49 @@
+/**
+ * @file hashtable.h Simple hash table implementation.
+ * Based on
+ * https://elixir.bootlin.com/linux/v5.18.12/source/include/linux/hashtable.h
+ * @author Lunaixsky (zelong56@gmail.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-07-20
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+#ifndef __LUNAIX_HASHTABLE_H
+#define __LUNAIX_HASHTABLE_H
+
+#include <lib/hash.h>
+#include <lunaix/ds/llist.h>
+
+struct hbucket
+{
+    struct hlist_node* head;
+};
+
+#define __hashkey(table, hash) (hash % (sizeof(table) / sizeof(table[0])))
+
+#define DECLARE_HASHTABLE(name, bucket_num) struct hbucket name[bucket_num];
+
+#define hashtable_bucket_foreach(bucket, pos, n, member)                       \
+    for (pos = list_entry((bucket)->head, typeof(*pos), member);               \
+         pos && ({                                                             \
+             n = list_entry(pos->member.next, typeof(*pos), member);           \
+             1;                                                                \
+         });                                                                   \
+         pos = n)
+
+#define hashtable_hash_foreach(table, hash, pos, n, member)                    \
+    hashtable_bucket_foreach(&table[__hashkey(table, hash)], pos, n, member)
+
+#define hashtable_init(table)                                                  \
+    {                                                                          \
+        for (int i = 0; i < (sizeof(table) / sizeof(table[0])); i++) {         \
+            table[i].head = 0;                                                 \
+        }                                                                      \
+    }
+
+#define hashtable_hash_in(table, list_node, hash)                              \
+    hlist_add(&table[__hashkey(table, hash)].head, list_node)
+
+#endif /* __LUNAIX_HASHTABLE_H */
diff --git a/lunaix-os/includes/lunaix/ds/hstr.h b/lunaix-os/includes/lunaix/ds/hstr.h
new file mode 100644 (file)
index 0000000..f3fa89e
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __LUNAIX_HSTR_H
+#define __LUNAIX_HSTR_H
+
+#include <lib/hash.h>
+
+#define HSTR_FULL_HASH 32
+
+struct hstr
+{
+    unsigned int hash;
+    unsigned int len;
+    char* value;
+};
+
+#define HSTR(str, length)                                                      \
+    (struct hstr)                                                              \
+    {                                                                          \
+        .len = (length), .value = (str)                                        \
+    }
+
+#define HHSTR(str, length, strhash)                                            \
+    (struct hstr)                                                              \
+    {                                                                          \
+        .len = (length), .value = (str), .hash = (strhash)                     \
+    }
+
+#define HSTR_EQ(str1, str2) ((str1)->hash == (str2)->hash)
+
+inline void
+hstr_rehash(struct hstr* hash_str, unsigned int truncate_to)
+{
+    hash_str->hash = strhash_32(hash_str->value, truncate_to);
+}
+
+#endif /* __LUNAIX_HSTR_H */
index 5afc36ad43b48ec822919a7dbb6a94008b130e44..9af9dd1fba4ebe90fe86090e3e72438492cea95e 100644 (file)
@@ -87,4 +87,27 @@ llist_empty(struct llist_header* elem)
          &pos->member != (head);                                               \
          pos = n, n = list_entry(n->member.next, typeof(*n), member))
 
+struct hlist_node
+{
+    struct hlist_node *next, **pprev;
+};
+
+static inline void
+hlist_del(struct hlist_node* node)
+{
+    *node->pprev = node->next;
+    node->next = 0;
+    node->pprev = 0;
+}
+
+static inline void
+hlist_add(struct hlist_node** head, struct hlist_node* node)
+{
+    node->next = *head;
+    if (*head) {
+        (*head)->pprev = &node->next;
+    }
+    node->pprev = head;
+    *head = node;
+}
 #endif /* __LUNAIX_LLIST_H */
diff --git a/lunaix-os/includes/lunaix/fctrl.h b/lunaix-os/includes/lunaix/fctrl.h
new file mode 100644 (file)
index 0000000..dc28872
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __LUNAIX_FCTRL_H
+#define __LUNAIX_FCTRL_H
+
+#include <lunaix/dirent.h>
+#include <lunaix/syscall.h>
+#include <stddef.h>
+
+__LXSYSCALL2(int, open, const char*, path, int, options)
+
+__LXSYSCALL1(int, mkdir, const char*, path)
+__LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname)
+
+__LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent)
+
+__LXSYSCALL4(int,
+             readlinkat,
+             int,
+             dirfd,
+             const char*,
+             pathname,
+             char*,
+             buf,
+             size_t,
+             size)
+
+__LXSYSCALL3(int, realpathat, int, fd, char*, buf, size_t, size)
+
+#endif /* __LUNAIX_FCTRL_H */
diff --git a/lunaix-os/includes/lunaix/foptions.h b/lunaix-os/includes/lunaix/foptions.h
new file mode 100644 (file)
index 0000000..f43fb10
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __LUNAIX_FOPTIONS_H
+#define __LUNAIX_FOPTIONS_H
+
+#define FO_CREATE 0x1
+#define FO_APPEND 0x2
+#define FO_DIRECT 0x4
+
+#define FSEEK_SET 0x1
+#define FSEEK_CUR 0x2
+#define FSEEK_END 0x3
+
+#endif /* __LUNAIX_FOPTIONS_H */
diff --git a/lunaix-os/includes/lunaix/fs.h b/lunaix-os/includes/lunaix/fs.h
new file mode 100644 (file)
index 0000000..0764a61
--- /dev/null
@@ -0,0 +1,275 @@
+#ifndef __LUNAIX_VFS_H
+#define __LUNAIX_VFS_H
+
+#include <hal/ahci/hba.h>
+#include <lunaix/block.h>
+#include <lunaix/clock.h>
+#include <lunaix/ds/btrie.h>
+#include <lunaix/ds/hashtable.h>
+#include <lunaix/ds/hstr.h>
+#include <lunaix/ds/llist.h>
+#include <lunaix/status.h>
+
+#define VFS_NAME_MAXLEN 128
+#define VFS_MAX_FD 32
+
+#define VFS_IFDIR 0x1
+#define VFS_IFFILE 0x2
+#define VFS_IFSEQDEV 0x4
+#define VFS_IFVOLDEV 0x8
+#define VFS_IFSYMLINK 0x16
+
+#define VFS_WALK_MKPARENT 0x1
+#define VFS_WALK_FSRELATIVE 0x2
+#define VFS_WALK_PARENT 0x4
+#define VFS_WALK_NOFOLLOW 0x4
+
+#define FSTYPE_ROFS 0x1
+
+#define VFS_VALID_CHAR(chr)                                                    \
+    ('A' <= (chr) && (chr) <= 'Z' || 'a' <= (chr) && (chr) <= 'z' ||           \
+     '0' <= (chr) && (chr) <= '9' || (chr) == '.' || (chr) == '_' ||           \
+     (chr) == '-')
+
+extern struct hstr vfs_ddot;
+extern struct hstr vfs_dot;
+
+struct v_dnode;
+struct pcache;
+
+struct filesystem
+{
+    struct hlist_node fs_list;
+    struct hstr fs_name;
+    uint32_t types;
+    int (*mount)(struct v_superblock* vsb, struct v_dnode* mount_point);
+    int (*unmount)(struct v_superblock* vsb);
+};
+
+struct v_superblock
+{
+    struct llist_header sb_list;
+    int fs_id;
+    bdev_t dev;
+    struct v_dnode* root;
+    struct filesystem* fs;
+    uint32_t iobuf_size;
+    struct
+    {
+        uint32_t (*read_capacity)(struct v_superblock* vsb);
+        uint32_t (*read_usage)(struct v_superblock* vsb);
+    } ops;
+};
+
+struct dir_context
+{
+    int index;
+    void* cb_data;
+    void (*read_complete_callback)(struct dir_context* dctx,
+                                   const char* name,
+                                   const int len,
+                                   const int dtype);
+};
+
+struct v_file_ops
+{
+    int (*write)(struct v_file* file, void* buffer, size_t len, size_t fpos);
+    int (*read)(struct v_file* file, void* buffer, size_t len, size_t fpos);
+    int (*readdir)(struct v_file* file, struct dir_context* dctx);
+    int (*seek)(struct v_file* file, size_t offset);
+    int (*rename)(struct v_file* file, char* new_name);
+    int (*close)(struct v_file* file);
+    int (*sync)(struct v_file* file);
+};
+
+struct v_file
+{
+    struct v_inode* inode;
+    struct v_dnode* dnode;
+    struct llist_header* f_list;
+    uint32_t f_pos;
+    uint32_t ref_count;
+    void* data; // 允许底层FS绑定他的一些专有数据
+    struct v_file_ops ops;
+};
+
+struct v_fd
+{
+    struct v_file* file;
+    int flags;
+};
+
+struct v_inode
+{
+    uint32_t itype;
+    time_t ctime;
+    time_t mtime;
+    time_t atime;
+    lba_t lb_addr;
+    uint32_t open_count;
+    uint32_t link_count;
+    uint32_t lb_usage;
+    uint32_t fsize;
+    struct pcache* pg_cache;
+    void* data; // 允许底层FS绑定他的一些专有数据
+    struct
+    {
+        int (*create)(struct v_inode* this);
+        int (*open)(struct v_inode* this, struct v_file* file);
+        int (*sync)(struct v_inode* this);
+        int (*mkdir)(struct v_inode* this, struct v_dnode* dnode);
+        int (*rmdir)(struct v_inode* this);
+        int (*unlink)(struct v_inode* this);
+        int (*link)(struct v_inode* this, struct v_dnode* new_name);
+        int (*read_symlink)(struct v_inode* this, const char** path_out);
+        int (*symlink)(struct v_inode* this, const char* target);
+        int (*dir_lookup)(struct v_inode* this, struct v_dnode* dnode);
+    } ops;
+    struct v_file_ops default_fops;
+};
+
+struct v_dnode
+{
+    struct hstr name;
+    struct v_inode* inode;
+    struct v_dnode* parent;
+    struct hlist_node hash_list;
+    struct llist_header children;
+    struct llist_header siblings;
+    struct v_superblock* super_block;
+    struct
+    {
+        void (*destruct)(struct v_dnode* dnode);
+    } ops;
+};
+
+struct v_fdtable
+{
+    struct v_fd* fds[VFS_MAX_FD];
+};
+
+struct pcache_pg
+{
+    struct llist_header pg_list;
+    struct llist_header dirty_list;
+    void* pg;
+    uint32_t flags;
+    uint32_t fpos;
+};
+
+struct pcache
+{
+    struct btrie tree;
+    struct llist_header pages;
+    struct llist_header dirty;
+    uint32_t n_dirty;
+    uint32_t n_pages;
+};
+
+/* --- file system manager --- */
+void
+fsm_init();
+
+void
+fsm_register(struct filesystem* fs);
+
+struct filesystem*
+fsm_get(const char* fs_name);
+
+void
+vfs_init();
+
+struct v_dnode*
+vfs_dcache_lookup(struct v_dnode* parent, struct hstr* str);
+
+void
+vfs_dcache_add(struct v_dnode* parent, struct v_dnode* dnode);
+
+int
+vfs_walk(struct v_dnode* start,
+         const char* path,
+         struct v_dnode** dentry,
+         struct hstr* component,
+         int walk_options);
+
+int
+vfs_mount(const char* target, const char* fs_name, bdev_t device);
+
+int
+vfs_unmount(const char* target);
+
+int
+vfs_mount_at(const char* fs_name, bdev_t device, struct v_dnode* mnt_point);
+
+int
+vfs_unmount_at(struct v_dnode* mnt_point);
+
+int
+vfs_mkdir(const char* path, struct v_dnode** dentry);
+
+int
+vfs_open(struct v_dnode* dnode, struct v_file** file);
+
+int
+vfs_close(struct v_file* file);
+
+int
+vfs_fsync(struct v_file* file);
+
+struct v_superblock*
+vfs_sb_alloc();
+
+void
+vfs_sb_free(struct v_superblock* sb);
+
+struct v_dnode*
+vfs_d_alloc();
+
+void
+vfs_d_free(struct v_dnode* dnode);
+
+struct v_inode*
+vfs_i_alloc();
+
+void
+vfs_i_free(struct v_inode* inode);
+
+int
+vfs_dup_fd(struct v_fd* old, struct v_fd** new);
+
+void
+pcache_init(struct pcache* pcache);
+
+void
+pcache_release_page(struct pcache* pcache, struct pcache_pg* page);
+
+struct pcache_pg*
+pcache_new_page(struct pcache* pcache, uint32_t index);
+
+void
+pcache_set_dirty(struct pcache* pcache, struct pcache_pg* pg);
+
+struct pcache_pg*
+pcache_get_page(struct pcache* pcache,
+                uint32_t index,
+                uint32_t* offset,
+                struct pcache_pg** page);
+
+int
+pcache_write(struct v_file* file, void* data, uint32_t len, uint32_t fpos);
+
+int
+pcache_read(struct v_file* file, void* data, uint32_t len, uint32_t fpos);
+
+void
+pcache_release(struct pcache* pcache);
+
+int
+pcache_commit(struct v_file* file, struct pcache_pg* page);
+
+void
+pcache_invalidate(struct v_file* file, struct pcache_pg* page);
+
+void
+pcache_commit_all(struct v_file* file);
+#endif /* __LUNAIX_VFS_H */
diff --git a/lunaix-os/includes/lunaix/fs/twifs.h b/lunaix-os/includes/lunaix/fs/twifs.h
new file mode 100644 (file)
index 0000000..f2d6b15
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __LUNAIX_TWIFS_H
+#define __LUNAIX_TWIFS_H
+
+#include <lunaix/fs.h>
+
+struct twifs_node
+{
+    struct v_inode* inode;
+    struct hstr name;
+    void* data;
+    uint32_t itype;
+    struct llist_header children;
+    struct llist_header siblings;
+    struct
+    {
+        int (*write)(struct v_file* file,
+                     void* buffer,
+                     size_t len,
+                     size_t fpos);
+        int (*read)(struct v_file* file, void* buffer, size_t len, size_t fpos);
+    } ops;
+};
+
+void
+twifs_init();
+
+struct twifs_node*
+twifs_file_node(struct twifs_node* parent,
+                const char* name,
+                int name_len,
+                uint32_t itype);
+
+struct twifs_node*
+twifs_dir_node(struct twifs_node* parent,
+               const char* name,
+               int name_len,
+               uint32_t itype);
+
+struct twifs_node*
+twifs_toplevel_node(const char* name, int name_len, uint32_t itype);
+
+int
+twifs_rm_node(struct twifs_node* node);
+
+#endif /* __LUNAIX_TWIFS_H */
index c16f2b09fc6d14c4c326dd7397805ba4fcbc09a0..556f239c695c67f0dfd6b536a90b38cc5a924c53 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <lunaix/syscall.h>
 #include <lunaix/types.h>
+#include <stddef.h>
 
 __LXSYSCALL(pid_t, fork)
 
@@ -24,4 +25,28 @@ __LXSYSCALL2(int, kill, pid_t, pid, int, signum)
 
 __LXSYSCALL1(unsigned int, alarm, unsigned int, seconds)
 
+__LXSYSCALL2(int, link, const char*, oldpath, const char*, newpath)
+
+__LXSYSCALL1(int, rmdir, const char*, pathname)
+
+__LXSYSCALL3(int, read, int, fd, void*, buf, unsigned int, count)
+
+__LXSYSCALL3(int, write, int, fd, void*, buf, unsigned int, count)
+
+__LXSYSCALL3(int, readlink, const char*, path, char*, buf, size_t, size)
+
+__LXSYSCALL3(int, lseek, int, fd, int, offset, int, options)
+
+__LXSYSCALL1(int, unlink, const char*, pathname)
+
+__LXSYSCALL1(int, close, int, fd)
+
+__LXSYSCALL2(int, dup2, int, oldfd, int, newfd)
+
+__LXSYSCALL1(int, dup, int, oldfd)
+
+__LXSYSCALL1(int, fsync, int, fildes)
+
+__LXSYSCALL2(int, symlink, const char*, pathname, const char*, link_target)
+
 #endif /* __LUNAIX_UNISTD_H */
index d5d0c7530b5e97d08e225c33e8141f6164f8ede2..9be750c4e023a8e039d76256b9e6acefcdc91731 100644 (file)
@@ -5,7 +5,10 @@ void*
 valloc(unsigned int size);
 
 void*
-vcalloc(unsigned int size);
+vzalloc(unsigned int size);
+
+void*
+vcalloc(unsigned int size, unsigned int count);
 
 void
 vfree(void* ptr);
@@ -14,7 +17,7 @@ void*
 valloc_dma(unsigned int size);
 
 void*
-vcalloc_dma(unsigned int size);
+vzalloc_dma(unsigned int size);
 
 void
 vfree_dma(void* ptr);
index 2d568a6bc9ebd31fcd33006fef435f1bf4d9e1cd..08a0d56c6660e2f72d6776b9e8e849a69d54c229 100644 (file)
@@ -2,74 +2,76 @@
 #define __LUNAIX_PS2KBD_H
 
 #include <hal/io.h>
-#include <lunaix/keyboard.h>
 #include <lunaix/ds/mutex.h>
-
+#include <lunaix/keyboard.h>
 
 #define PS2_PORT_ENC_DATA 0x60
 #define PS2_PORT_ENC_CMDREG 0x60
 #define PS2_PORT_CTRL_STATUS 0x64
 #define PS2_PORT_CTRL_CMDREG 0x64
 
-#define PS2_STATUS_OFULL   0x1
-#define PS2_STATUS_IFULL   0x2
+#define PS2_STATUS_OFULL 0x1
+#define PS2_STATUS_IFULL 0x2
 
-#define PS2_RESULT_ACK  0xfa
-#define PS2_RESULT_NAK  0xfe    //resend
-#define PS2_RESULT_ECHO 0xee    
-#define PS2_RESULT_TEST_OK 0x55    
+#define PS2_RESULT_ACK 0xfa
+#define PS2_RESULT_NAK 0xfe // resend
+#define PS2_RESULT_ECHO 0xee
+#define PS2_RESULT_TEST_OK 0x55
 
 // PS/2 keyboard device related commands
-#define PS2_KBD_CMD_SETLED  0xed
-#define PS2_KBD_CMD_ECHO  0xee
-#define PS2_KBD_CMD_SCANCODE_SET  0xf0
-#define PS2_KBD_CMD_IDENTIFY  0xf2
-#define PS2_KBD_CMD_SCAN_ENABLE  0xf4
-#define PS2_KBD_CMD_SCAN_DISABLE  0xf5
+#define PS2_KBD_CMD_SETLED 0xed
+#define PS2_KBD_CMD_ECHO 0xee
+#define PS2_KBD_CMD_SCANCODE_SET 0xf0
+#define PS2_KBD_CMD_IDENTIFY 0xf2
+#define PS2_KBD_CMD_SCAN_ENABLE 0xf4
+#define PS2_KBD_CMD_SCAN_DISABLE 0xf5
 
 // PS/2 *controller* related commands
-#define PS2_CMD_PORT1_DISABLE  0xad
-#define PS2_CMD_PORT1_ENABLE  0xae
-#define PS2_CMD_PORT2_DISABLE  0xa7
-#define PS2_CMD_PORT2_ENABLE  0xa8
-#define PS2_CMD_SELFTEST      0xaa
-#define PS2_CMD_SELFTEST_PORT1      0xab
+#define PS2_CMD_PORT1_DISABLE 0xad
+#define PS2_CMD_PORT1_ENABLE 0xae
+#define PS2_CMD_PORT2_DISABLE 0xa7
+#define PS2_CMD_PORT2_ENABLE 0xa8
+#define PS2_CMD_SELFTEST 0xaa
+#define PS2_CMD_SELFTEST_PORT1 0xab
 
-#define PS2_CMD_READ_CFG       0x20 
-#define PS2_CMD_WRITE_CFG       0x60
+#define PS2_CMD_READ_CFG 0x20
+#define PS2_CMD_WRITE_CFG 0x60
 
-#define PS2_CFG_P1INT             0x1
-#define PS2_CFG_P2INT             0x2
-#define PS2_CFG_TRANSLATION       0x40
+#define PS2_CFG_P1INT 0x1
+#define PS2_CFG_P2INT 0x2
+#define PS2_CFG_TRANSLATION 0x40
 
-#define PS2_DELAY       1000
+#define PS2_DELAY 1000
 
 #define PS2_CMD_QUEUE_SIZE 8
 #define PS2_KBD_RECV_BUFFER_SIZE 8
 
 #define PS2_NO_ARG 0xff00
 
-
-struct ps2_cmd {
+struct ps2_cmd
+{
     char cmd;
     char arg;
 };
 
-struct ps2_kbd_state {
+struct ps2_kbd_state
+{
     volatile char state;
     volatile char masked;
+    volatile kbd_kstate_t key_state;
     kbd_keycode_t* translation_table;
-    kbd_kstate_t key_state;
 };
 
-struct ps2_cmd_queue {
+struct ps2_cmd_queue
+{
     struct ps2_cmd cmd_queue[PS2_CMD_QUEUE_SIZE];
     int queue_ptr;
     int queue_len;
     mutex_t mutex;
 };
 
-struct ps2_key_buffer {
+struct ps2_key_buffer
+{
     struct kdb_keyinfo_pkt buffer[PS2_KBD_RECV_BUFFER_SIZE];
     int read_ptr;
     int buffered_len;
@@ -80,39 +82,42 @@ struct ps2_key_buffer {
  * @brief 向PS/2控制器的控制端口(0x64)发送指令并等待返回代码。
  * 注意,对于没有返回代码的命令请使用`ps2_post_cmd`,否则会造成死锁。
  * 通过调用该方法向控制器发送指令,请区别 ps2_issue_dev_cmd
- * 
- * @param cmd 
+ *
+ * @param cmd
  * @param args
  */
-static uint8_t ps2_issue_cmd(char cmd, uint16_t arg);
+static uint8_t
+ps2_issue_cmd(char cmd, uint16_t arg);
 
 /**
  * @brief 向PS/2控制器的编码器端口(0x60)发送指令并等待返回代码。
  * 注意,对于没有返回代码的命令请使用`ps2_post_cmd`,否则会造成死锁。
  * 通过调用该方法向PS/2设备发送指令,请区别 ps2_issue_cmd
- * 
- * @param cmd 
+ *
+ * @param cmd
  * @param args
  */
-static uint8_t ps2_issue_dev_cmd(char cmd, uint16_t arg);
+static uint8_t
+ps2_issue_dev_cmd(char cmd, uint16_t arg);
 
 /**
  * @brief 向PS/2控制器发送指令,不等待返回代码。
- * 
+ *
  * @param port 端口号
- * @param cmd 
- * @param args 
- * @return char 
+ * @param cmd
+ * @param args
+ * @return char
  */
-static void ps2_post_cmd(uint8_t port, char cmd, uint16_t arg);
-
-void ps2_device_post_cmd(char cmd, char arg);
-
-void ps2_kbd_init();
-
-void ps2_process_cmd(void* arg);
+static void
+ps2_post_cmd(uint8_t port, char cmd, uint16_t arg);
 
+void
+ps2_device_post_cmd(char cmd, char arg);
 
+void
+ps2_kbd_init();
 
+void
+ps2_process_cmd(void* arg);
 
 #endif /* __LUNAIX_PS2KBD_H */
index eafae4fc43968e6f7958c8432b61c066271b4029..f4de8cf6260a47d4f7a19018be695e919cbdaa1a 100644 (file)
@@ -10,4 +10,6 @@ __LXSYSCALL1(pid_t, wait, int*, status);
 
 __LXSYSCALL3(pid_t, waitpid, pid_t, pid, int*, status, int, options);
 
+__LXSYSCALL(int, geterrno);
+
 #endif /* __LUNAIX_SYS_H */
index d35bfe77c7cc9ddb41be6f1ae04997a029744668..7c8c114a8c607ceb4c333ed7e6ee8e2db0e7ee3b 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <arch/x86/interrupts.h>
 #include <lunaix/clock.h>
+#include <lunaix/fs.h>
 #include <lunaix/mm/mm.h>
 #include <lunaix/signal.h>
 #include <lunaix/timer.h>
@@ -77,6 +78,7 @@ struct proc_info
     sigset_t sig_inprogress;
     int flags;
     void* sig_handler[_SIG_NUM];
+    struct v_fdtable* fdtable;
     pid_t pgid;
 };
 
index 777a457ae1a0c26a4b7952d7f1c12914841da88c..4363b4123a89efa9be46cddd743353360b5ce019 100644 (file)
@@ -3,12 +3,12 @@
 
 // Some helper functions. As helpful as Spike the Dragon! :)
 
-// 除法向上取整
+// 除法 v/(2^k) 向上取整
 #define CEIL(v, k) (((v) + (1 << (k)) - 1) >> (k))
 
 #define ICEIL(x, y) ((x) / (y) + ((x) % (y) != 0))
 
-// 除法向下取整
+// 除法 v/(2^k) 向下取整
 #define FLOOR(v, k) ((v) >> (k))
 
 // 获取v最近的最大k倍数
 // 获取v最近的最小k倍数
 #define ROUNDDOWN(v, k) ((v) & ~((k)-1))
 
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+/**
+ * @brief Fast log base 2 for integer, utilizing constant unfolding.
+ * Adopted from
+ * https://elixir.bootlin.com/linux/v4.4/source/include/linux/log2.h#L85
+ *
+ */
+#define ILOG2(x)                                                               \
+    __builtin_constant_p(x) ? ((x) == 0              ? 0                       \
+                               : ((x) & (1ul << 31)) ? 31                      \
+                               : ((x) & (1ul << 30)) ? 30                      \
+                               : ((x) & (1ul << 29)) ? 29                      \
+                               : ((x) & (1ul << 28)) ? 28                      \
+                               : ((x) & (1ul << 27)) ? 27                      \
+                               : ((x) & (1ul << 26)) ? 26                      \
+                               : ((x) & (1ul << 25)) ? 25                      \
+                               : ((x) & (1ul << 24)) ? 24                      \
+                               : ((x) & (1ul << 23)) ? 23                      \
+                               : ((x) & (1ul << 22)) ? 22                      \
+                               : ((x) & (1ul << 21)) ? 21                      \
+                               : ((x) & (1ul << 20)) ? 20                      \
+                               : ((x) & (1ul << 19)) ? 19                      \
+                               : ((x) & (1ul << 18)) ? 18                      \
+                               : ((x) & (1ul << 17)) ? 17                      \
+                               : ((x) & (1ul << 16)) ? 16                      \
+                               : ((x) & (1ul << 15)) ? 15                      \
+                               : ((x) & (1ul << 14)) ? 14                      \
+                               : ((x) & (1ul << 13)) ? 13                      \
+                               : ((x) & (1ul << 12)) ? 12                      \
+                               : ((x) & (1ul << 11)) ? 11                      \
+                               : ((x) & (1ul << 10)) ? 10                      \
+                               : ((x) & (1ul << 9))  ? 9                       \
+                               : ((x) & (1ul << 8))  ? 8                       \
+                               : ((x) & (1ul << 7))  ? 7                       \
+                               : ((x) & (1ul << 6))  ? 6                       \
+                               : ((x) & (1ul << 5))  ? 5                       \
+                               : ((x) & (1ul << 4))  ? 4                       \
+                               : ((x) & (1ul << 3))  ? 3                       \
+                               : ((x) & (1ul << 2))  ? 2                       \
+                               : ((x) & (1ul << 1))  ? 1                       \
+                                                     : 0)                       \
+                            : (31 - __builtin_clz(x))
+
 #define __USER__ __attribute__((section(".usrtext")))
 
 inline static void
index aeef93e5c16e6abf9cb44382fd490c44d857440b..4007c315a36ca54e335be97cb057af48b19ca0da 100644 (file)
@@ -5,10 +5,26 @@
 #define LXHEAPFULL -(2)
 #define LXINVLDPTR -(2)
 #define LXOUTOFMEM -(3)
-#define LXINVLDPID -(4)
 #define LXSEGFAULT -(5)
-#define LXINVL -(6)
+#define EINVAL -(6)
 
 #define EINTR -(7)
 
+#define EMFILE -8
+#define ENOENT -9
+#define ENAMETOOLONG -10
+#define ENOTDIR -11
+#define EEXIST -12
+#define EBADF -13
+#define ENOTSUP -14
+#define ENXIO -15
+#define ELOOP -16
+#define ENOTEMPTY -17
+#define EROFS -18
+#define EISDIR -19
+#define EBUSY -20
+#define EXDEV -21
+#define ELOOP -22
+#define ENODEV -23
+
 #endif /* __LUNAIX_CODE_H */
index 8e145e516f8a5830d1361b2a0c76ed5eab4db87b..94d197af1657f18329e1bee9d65f29f41290546d 100644 (file)
@@ -13,6 +13,7 @@
 #define __SYSCALL__exit 8
 #define __SYSCALL_wait 9
 #define __SYSCALL_waitpid 10
+
 #define __SYSCALL_sigreturn 11
 #define __SYSCALL_sigprocmask 12
 #define __SYSCALL_signal 13
 #define __SYSCALL_alarm 16
 #define __SYSCALL_sigpending 17
 #define __SYSCALL_sigsuspend 18
+#define __SYSCALL_open 19
+#define __SYSCALL_close 20
+
+#define __SYSCALL_read 21
+#define __SYSCALL_write 22
+#define __SYSCALL_readdir 23
+#define __SYSCALL_mkdir 24
+#define __SYSCALL_lseek 25
+#define __SYSCALL_geterrno 26
+#define __SYSCALL_readlink 27
+#define __SYSCALL_readlinkat 28
+#define __SYSCALL_rmdir 29
+
+#define __SYSCALL_unlink 30
+#define __SYSCALL_unlinkat 31
+#define __SYSCALL_link 32
+#define __SYSCALL_fsync 33
+#define __SYSCALL_dup 34
+#define __SYSCALL_dup2 35
+#define __SYSCALL_realpathat 36
+#define __SYSCALL_symlink 37
 
 #define __SYSCALL_MAX 0x100
 
 #ifndef __ASM__
+
+#define SYSCALL_ESTATUS(errno) -((errno) != 0)
+
 void
 syscall_install();
 
@@ -90,7 +115,7 @@ syscall_install();
     }
 
 #define __LXSYSCALL4(rettype, name, t1, p1, t2, p2, t3, p3, t4, p4)            \
-    static rettype name(__PARAM_MAP3(t1, p1, t2, p2, t3, p3, t4, p4))          \
+    static rettype name(__PARAM_MAP4(t1, p1, t2, p2, t3, p3, t4, p4))          \
     {                                                                          \
         asm("\n" ::"b"(p1), "c"(p2), "d"(p3), "D"(p4));                        \
         ___DOINT33(__SYSCALL_##name, rettype)                                  \
index 9eb4ea08192f98db5035608d8c800ed20b4ab79b..e5eaa34b940ad7c9ce1295250858918639bca89d 100644 (file)
@@ -1,13 +1,14 @@
 #ifndef __LUNAIX_CONSOLE_H
 #define __LUNAIX_CONSOLE_H
 
-#include <lunaix/ds/fifobuf.h>
+#include <lunaix/ds/fifo.h>
 #include <lunaix/timer.h>
 
 struct console
 {
     struct lx_timer* flush_timer;
-    struct fifo_buffer buffer;
+    struct fifo_buf output;
+    struct fifo_buf input;
     unsigned int erd_pos;
     unsigned int lines;
 };
index e91025ad920f8641346d0eae509f6cf5f906a52f..3069a833bdb9b78d9eb20889fa012a8ffcbf17b7 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __LUNAIX_TYPES_H
 #define __LUNAIX_TYPES_H
 
+#include <stddef.h>
 #include <stdint.h>
 
 #define PEXITTERM 0x100
@@ -20,5 +21,6 @@
 // TODO: WTERMSIG
 
 typedef int32_t pid_t;
+typedef int64_t lba_t;
 
 #endif /* __LUNAIX_TYPES_H */
index b13dee0f183ca68df855856ea0de59fca239f74f..328afbf924c11fd12ca0287261d116b5f696ea89 100644 (file)
         .long __lxsys_alarm
         .long __lxsys_sigpending
         .long __lxsys_sigsuspend
+        .long __lxsys_open
+        .long __lxsys_close         /* 20 */
+        .long __lxsys_read
+        .long __lxsys_write
+        .long __lxsys_readdir
+        .long __lxsys_mkdir
+        .long __lxsys_lseek         /* 25 */
+        .long __lxsys_geterrno
+        .long __lxsys_readlink
+        .long __lxsys_readlinkat
+        .long __lxsys_rmdir
+        .long __lxsys_unlink        /* 30 */
+        .long __lxsys_unlinkat
+        .long __lxsys_link
+        .long __lxsys_fsync
+        .long __lxsys_dup
+        .long __lxsys_dup2
+        .long __lxsys_realpathat
+        .long __lxsys_symlink
         2:
         .rept __SYSCALL_MAX - (2b - 1b)/4
             .long 0
diff --git a/lunaix-os/kernel/block.c b/lunaix-os/kernel/block.c
new file mode 100644 (file)
index 0000000..97e9bd6
--- /dev/null
@@ -0,0 +1,144 @@
+#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
+#define BLOCK_EFULL 3
+
+LOG_MODULE("BLOCK")
+
+#define MAX_DEV 32
+
+struct cake_pile* lbd_pile;
+struct block_dev** dev_registry;
+
+int free_slot = 0;
+
+int
+__block_mount_partitions(struct hba_device* hd_dev);
+
+int
+__block_register(struct block_dev* dev);
+
+void
+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 device* dev,
+             void* buf,
+             unsigned int offset,
+             unsigned int len)
+{
+    int errno;
+    struct block_dev* bdev = (struct block_dev*)dev->underlay;
+    size_t acc_size = 0, rd_size = 0, bsize = bdev->hd_dev->block_size,
+           rd_block = offset / bsize, r = offset % bsize;
+    void* block = vzalloc(bsize);
+
+    while (acc_size < len) {
+        if (!bdev->hd_dev->ops.read_buffer(
+              bdev->hd_dev, rd_block, block, bsize)) {
+            errno = ENXIO;
+            goto error;
+        }
+        rd_size = MIN(len - acc_size, bsize - r);
+        memcpy(buf + acc_size, block + r, rd_size);
+        acc_size += rd_size;
+        r = 0;
+        rd_block++;
+    }
+
+    vfree(block);
+    return rd_block;
+
+error:
+    vfree(block);
+    return errno;
+}
+
+int
+__block_write(struct device* dev,
+              void* buf,
+              unsigned int offset,
+              unsigned int len)
+{
+    int errno;
+    struct block_dev* bdev = (struct block_dev*)dev->underlay;
+    size_t acc_size = 0, wr_size = 0, bsize = bdev->hd_dev->block_size,
+           wr_block = offset / bsize, r = offset % bsize;
+    void* block = vzalloc(bsize);
+
+    while (acc_size < len) {
+        wr_size = MIN(len - acc_size, bsize - r);
+        memcpy(block + r, buf + acc_size, wr_size);
+        if (!bdev->hd_dev->ops.write_buffer(
+              bdev->hd_dev, wr_block, block, bsize)) {
+            errno = ENXIO;
+            break;
+        }
+        acc_size += wr_size;
+        r = 0;
+        wr_block++;
+    }
+
+    vfree(block);
+    return wr_block;
+
+error:
+    vfree(block);
+    return errno;
+}
+
+int
+block_mount_disk(struct hba_device* hd_dev)
+{
+    int errno = 0;
+    struct block_dev* bdev = cake_grab(lbd_pile);
+    strncpy(bdev->name, hd_dev->model, PARTITION_NAME_SIZE);
+    bdev->hd_dev = hd_dev;
+    bdev->base_lba = 0;
+    bdev->end_lba = hd_dev->max_lba;
+    if (!__block_register(bdev)) {
+        errno = BLOCK_EFULL;
+        goto error;
+    }
+
+    return errno;
+
+error:
+    kprintf(KERROR "Fail to mount hd: %s[%s] (%x)\n",
+            hd_dev->model,
+            hd_dev->serial_num,
+            -errno);
+}
+
+int
+__block_register(struct block_dev* bdev)
+{
+    if (free_slot >= MAX_DEV) {
+        return 0;
+    }
+
+    struct device* dev = device_addvol(NULL, bdev, "sd%c", 'a' + free_slot);
+    dev->write = __block_write;
+    dev->read = __block_read;
+
+    bdev->dev = dev;
+    dev_registry[free_slot++] = bdev;
+    return 1;
+}
\ No newline at end of file
diff --git a/lunaix-os/kernel/demos/dir_read.c b/lunaix-os/kernel/demos/dir_read.c
new file mode 100644 (file)
index 0000000..caa88cc
--- /dev/null
@@ -0,0 +1,36 @@
+#include <lunaix/dirent.h>
+#include <lunaix/fctrl.h>
+#include <lunaix/lunistd.h>
+#include <lunaix/proc.h>
+#include <lunaix/syslog.h>
+
+LOG_MODULE("RDDIR")
+
+void
+_readdir_main()
+{
+    int fd = open("/dev/./../dev/.", 0);
+    if (fd == -1) {
+        kprintf(KERROR "fail to open (%d)\n", geterrno());
+        return;
+    }
+
+    char path[129];
+    int len = realpathat(fd, path, 128);
+    if (len < 0) {
+        kprintf(KERROR "fail to read (%d)\n", geterrno());
+    } else {
+        path[len] = 0;
+        kprintf("%s\n", path);
+    }
+
+    struct dirent ent = { .d_offset = 0 };
+
+    while (!readdir(fd, &ent)) {
+        kprintf(KINFO "%s\n", ent.d_name);
+    }
+
+    close(fd);
+
+    return;
+}
\ No newline at end of file
diff --git a/lunaix-os/kernel/demos/iotest.c b/lunaix-os/kernel/demos/iotest.c
new file mode 100644 (file)
index 0000000..5e17b02
--- /dev/null
@@ -0,0 +1,62 @@
+#include <lunaix/fctrl.h>
+#include <lunaix/foptions.h>
+#include <lunaix/lunistd.h>
+#include <lunaix/proc.h>
+#include <lunaix/syslog.h>
+
+LOG_MODULE("IOTEST")
+
+#define STDIN 1
+#define STDOUT 0
+
+void
+_iotest_main()
+{
+    char test_sequence[] = "Once upon a time, in a magical land of Equestria. "
+                           "There were two regal sisters who ruled together "
+                           "and created harmony for all the land.";
+
+    // sda 设备 - 硬盘
+    //  sda设备属于容积设备(Volumetric Device),
+    //  Lunaix会尽可能缓存任何对此设备的上层读写,并使用延迟写入策略。(FO_DIRECT可用于屏蔽该功能)
+    int fd = open("/dev/sda", 0);
+
+    if (fd < 0) {
+        kprintf(KERROR "fail to open (%d)\n", geterrno());
+        return;
+    }
+
+    // 移动指针至512字节,在大多数情况下,这是第二个逻辑扇区的起始处
+    lseek(fd, 512, FSEEK_SET);
+
+    // 总共写入 64 * 136 字节,会产生3个页作为缓存
+    for (size_t i = 0; i < 64; i++) {
+        write(fd, test_sequence, sizeof(test_sequence));
+    }
+
+    // 随机读写测试
+    lseek(fd, 4 * 4096, FSEEK_SET);
+    write(fd, test_sequence, sizeof(test_sequence));
+
+    char read_out[256];
+    write(STDOUT, "input: ", 8);
+    int size = read(STDIN, read_out, 256);
+
+    write(STDOUT, "your input: ", 13);
+    write(STDOUT, read_out, size);
+    write(fd, read_out, size);
+    write(STDOUT, "\n", 1);
+
+    // 读出我们写的内容
+    lseek(fd, 512, FSEEK_SET);
+    read(fd, read_out, sizeof(read_out));
+
+    // 将读出的内容直接写入tty设备
+    write(STDOUT, read_out, sizeof(read_out));
+    write(STDOUT, "\n", 1);
+
+    // 关闭文件,这同时会将页缓存中的数据下发到底层驱动
+    close(fd);
+
+    kprint_hex(read_out, sizeof(read_out));
+}
\ No newline at end of file
diff --git a/lunaix-os/kernel/device.c b/lunaix-os/kernel/device.c
new file mode 100644 (file)
index 0000000..2471a9c
--- /dev/null
@@ -0,0 +1,110 @@
+#include <klibc/stdio.h>
+#include <lunaix/device.h>
+#include <lunaix/fs/twifs.h>
+#include <lunaix/mm/valloc.h>
+
+struct llist_header dev_list;
+
+static struct twifs_node* dev_root;
+
+int
+__dev_read(struct v_file* file, void* buffer, size_t len, size_t fpos);
+
+int
+__dev_write(struct v_file* file, void* buffer, size_t len, size_t fpos);
+
+void
+device_init()
+{
+    dev_root = twifs_toplevel_node("dev", 3, 0);
+
+    llist_init_head(&dev_list);
+}
+
+struct device*
+__device_add(struct device* parent,
+             void* underlay,
+             char* name_fmt,
+             uint32_t type,
+             va_list args)
+{
+    struct device* dev = vzalloc(sizeof(struct device));
+
+    size_t strlen =
+      __sprintf_internal(dev->name_val, name_fmt, DEVICE_NAME_SIZE, args);
+
+    dev->name = HSTR(dev->name_val, strlen);
+    dev->parent = parent;
+    dev->underlay = underlay;
+
+    hstr_rehash(&dev->name, HSTR_FULL_HASH);
+    llist_append(&dev_list, &dev->dev_list);
+
+    struct twifs_node* dev_node =
+      twifs_file_node(dev_root, dev->name_val, strlen, type);
+    dev_node->data = dev;
+    dev_node->ops.read = __dev_read;
+    dev_node->ops.write = __dev_write;
+
+    dev->fs_node = dev_node;
+
+    return dev;
+}
+
+struct device*
+device_addseq(struct device* parent, void* underlay, char* name_fmt, ...)
+{
+    va_list args;
+    va_start(args, name_fmt);
+
+    struct device* dev =
+      __device_add(parent, underlay, name_fmt, VFS_IFSEQDEV, args);
+
+    va_end(args);
+    return dev;
+}
+
+struct device*
+device_addvol(struct device* parent, void* underlay, char* name_fmt, ...)
+{
+    va_list args;
+    va_start(args, name_fmt);
+
+    struct device* dev =
+      __device_add(parent, underlay, name_fmt, VFS_IFVOLDEV, args);
+
+    va_end(args);
+    return dev;
+}
+
+int
+__dev_read(struct v_file* file, void* buffer, size_t len, size_t fpos)
+{
+    struct twifs_node* dev_node = (struct twifs_node*)file->inode->data;
+    struct device* dev = (struct device*)dev_node->data;
+
+    if (!dev->read) {
+        return ENOTSUP;
+    }
+    return dev->read(dev, buffer, fpos, len);
+}
+
+int
+__dev_write(struct v_file* file, void* buffer, size_t len, size_t fpos)
+{
+    struct twifs_node* dev_node = (struct twifs_node*)file->inode->data;
+    struct device* dev = (struct device*)dev_node->data;
+
+    if (!dev->write) {
+        return ENOTSUP;
+    }
+    return dev->write(dev, buffer, fpos, len);
+}
+
+void
+device_remove(struct device* dev)
+{
+    llist_delete(&dev->dev_list);
+    twifs_rm_node((struct twifs_node*)dev->fs_node);
+    vfree(dev);
+}
\ No newline at end of file
diff --git a/lunaix-os/kernel/ds/btrie.c b/lunaix-os/kernel/ds/btrie.c
new file mode 100644 (file)
index 0000000..fd173b9
--- /dev/null
@@ -0,0 +1,121 @@
+/**
+ * @file btrie.c
+ * @author Lunaixsky
+ * @brief Bitwise trie tree implementation for sparse array.
+ * @version 0.1
+ * @date 2022-08-01
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+
+#include <lunaix/ds/btrie.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/spike.h>
+
+#define BTRIE_INSERT 1
+
+struct btrie_node*
+__btrie_traversal(struct btrie* root, uint32_t index, int options)
+{
+    index = index >> root->truncated;
+    uint32_t lz = index ? ROUNDDOWN(31 - __builtin_clz(index), BTRIE_BITS) : 0;
+    uint32_t bitmask = ((1 << BTRIE_BITS) - 1) << lz;
+    uint32_t i = 0;
+    struct btrie_node* tree = root->btrie_root;
+
+    // Time complexity: O(log_2(log_2(N))) where N is the index to lookup
+    while (bitmask && tree) {
+        i = (index & bitmask) >> lz;
+        struct btrie_node *subtree = 0, *pos, *n;
+
+        llist_for_each(pos, n, &tree->children, siblings)
+        {
+            if (pos->index == i) {
+                subtree = pos;
+                break;
+            }
+        }
+
+        if (!subtree && (options & BTRIE_INSERT)) {
+            struct btrie_node* new_tree = vzalloc(sizeof(struct btrie_node));
+            new_tree->index = i;
+            new_tree->parent = tree;
+            llist_init_head(&new_tree->children);
+
+            llist_append(&tree->children, &new_tree->siblings);
+            llist_append(&root->btrie_root->nodes, &new_tree->nodes);
+            tree = new_tree;
+        } else {
+            tree = subtree;
+        }
+        bitmask = bitmask >> BTRIE_BITS;
+        lz -= BTRIE_BITS;
+    }
+
+    return tree;
+}
+
+void
+btrie_init(struct btrie* btrie, uint32_t trunc_bits)
+{
+    btrie->btrie_root = vzalloc(sizeof(struct btrie_node));
+    llist_init_head(&btrie->btrie_root->nodes);
+    llist_init_head(&btrie->btrie_root->children);
+    btrie->truncated = trunc_bits;
+}
+
+void*
+btrie_get(struct btrie* root, uint32_t index)
+{
+    struct btrie_node* node = __btrie_traversal(root, index, 0);
+    if (!node) {
+        return NULL;
+    }
+    return node->data;
+}
+
+void
+btrie_set(struct btrie* root, uint32_t index, void* data)
+{
+    struct btrie_node* node = __btrie_traversal(root, index, BTRIE_INSERT);
+    node->data = data;
+}
+
+void
+__btrie_remove(struct btrie_node* node)
+{
+    struct btrie_node* parent = node->parent;
+    if (parent) {
+        llist_delete(&node->siblings);
+        llist_delete(&node->nodes);
+        vfree(node);
+        if (llist_empty(&parent->children)) {
+            __btrie_remove(parent);
+        }
+    }
+}
+
+void*
+btrie_remove(struct btrie* root, uint32_t index)
+{
+    struct btrie_node* node = __btrie_traversal(root, index, 0);
+    if (!node) {
+        return 0;
+    }
+    void* data = node->data;
+    __btrie_remove(node);
+    return data;
+}
+
+void
+btrie_release(struct btrie* tree)
+{
+    struct btrie_node *pos, *n;
+    llist_for_each(pos, n, &tree->btrie_root->nodes, nodes)
+    {
+        vfree(pos);
+    }
+
+    vfree(tree->btrie_root);
+}
\ No newline at end of file
diff --git a/lunaix-os/kernel/ds/fifo.c b/lunaix-os/kernel/ds/fifo.c
new file mode 100644 (file)
index 0000000..1e72e8d
--- /dev/null
@@ -0,0 +1,119 @@
+#include <klibc/string.h>
+#include <lunaix/ds/fifo.h>
+#include <lunaix/ds/mutex.h>
+#include <lunaix/spike.h>
+
+void
+fifo_init(struct fifo_buf* buf, void* data_buffer, size_t buf_size, int flags)
+{
+    *buf = (struct fifo_buf){ .data = data_buffer,
+                              .rd_pos = 0,
+                              .wr_pos = 0,
+                              .size = buf_size,
+                              .flags = flags,
+                              .free_len = buf_size };
+    mutex_init(&buf->lock);
+}
+
+int
+fifo_backone(struct fifo_buf* fbuf)
+{
+    mutex_lock(&fbuf->lock);
+
+    if (fbuf->free_len == fbuf->size) {
+        mutex_unlock(&fbuf->lock);
+        return 0;
+    }
+
+    fbuf->wr_pos = (fbuf->wr_pos ? fbuf->wr_pos : fbuf->size) - 1;
+    fbuf->free_len++;
+
+    mutex_unlock(&fbuf->lock);
+
+    return 1;
+}
+
+size_t
+fifo_putone(struct fifo_buf* fbuf, uint8_t data)
+{
+    mutex_lock(&fbuf->lock);
+
+    if (!fbuf->free_len) {
+        mutex_unlock(&fbuf->lock);
+        return 0;
+    }
+
+    uint8_t* dest = fbuf->data;
+    dest[fbuf->wr_pos] = data;
+    fbuf->wr_pos = (fbuf->wr_pos + 1) % fbuf->size;
+    fbuf->free_len--;
+
+    mutex_unlock(&fbuf->lock);
+
+    return 1;
+}
+
+size_t
+fifo_write(struct fifo_buf* fbuf, void* data, size_t count)
+{
+    size_t wr_count = 0, wr_pos = fbuf->wr_pos;
+
+    mutex_lock(&fbuf->lock);
+
+    if (!fbuf->free_len) {
+        mutex_unlock(&fbuf->lock);
+        return 0;
+    }
+
+    if (wr_pos >= fbuf->rd_pos) {
+        // case 1
+        size_t cplen_tail = MIN(fbuf->size - wr_pos, count);
+        size_t cplen_head = MIN(fbuf->rd_pos, count - cplen_tail);
+        memcpy(fbuf->data + wr_pos, data, cplen_tail);
+        memcpy(fbuf->data, data + cplen_tail, cplen_head);
+
+        wr_count = cplen_head + cplen_tail;
+    } else {
+        // case 2
+        wr_count = MIN(fbuf->rd_pos - wr_pos, count);
+        memcpy(fbuf->data + wr_pos, data, wr_count);
+    }
+
+    fbuf->wr_pos = (wr_pos + wr_count) % fbuf->size;
+    fbuf->free_len -= wr_count;
+
+    mutex_unlock(&fbuf->lock);
+
+    return wr_count;
+}
+
+size_t
+fifo_read(struct fifo_buf* fbuf, void* buf, size_t count)
+{
+    size_t rd_count = 0, rd_pos = fbuf->rd_pos;
+    mutex_lock(&fbuf->lock);
+
+    if (fbuf->free_len == fbuf->size) {
+        mutex_unlock(&fbuf->lock);
+        return 0;
+    }
+
+    if (rd_pos >= fbuf->wr_pos) {
+        size_t cplen_tail = MIN(fbuf->size - rd_pos, count);
+        size_t cplen_head = MIN(fbuf->wr_pos, count - cplen_tail);
+        memcpy(buf, fbuf->data + rd_pos, cplen_tail);
+        memcpy(buf + cplen_tail, fbuf->data, cplen_head);
+
+        rd_count = cplen_head + cplen_tail;
+    } else {
+        rd_count = MIN(fbuf->wr_pos - rd_pos, count);
+        memcpy(buf, fbuf->data + rd_pos, rd_count);
+    }
+
+    fbuf->rd_pos = (rd_pos + rd_count) % fbuf->size;
+    fbuf->free_len += rd_count;
+
+    mutex_unlock(&fbuf->lock);
+
+    return rd_count;
+}
\ No newline at end of file
diff --git a/lunaix-os/kernel/fs/fsm.c b/lunaix-os/kernel/fs/fsm.c
new file mode 100644 (file)
index 0000000..10e766a
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * @file fsm.c File system manager
+ * @author Lunaixsky (zelong56@gmail.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-07-19
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+#include <klibc/string.h>
+#include <lunaix/ds/hashtable.h>
+#include <lunaix/fs.h>
+
+#define HASH_BUCKET_BITS 4
+#define HASH_BUCKET_NUM (1 << HASH_BUCKET_BITS)
+
+DECLARE_HASHTABLE(fs_registry, HASH_BUCKET_NUM);
+
+void
+fsm_init()
+{
+    hashtable_init(fs_registry);
+}
+
+void
+fsm_register(struct filesystem* fs)
+{
+    hstr_rehash(&fs->fs_name, HSTR_FULL_HASH);
+    hashtable_hash_in(fs_registry, &fs->fs_list, fs->fs_name.hash);
+}
+
+struct filesystem*
+fsm_get(const char* fs_name)
+{
+    struct filesystem *pos, *next;
+    struct hstr str = HSTR(fs_name, 0);
+    hstr_rehash(&str, HSTR_FULL_HASH);
+
+    hashtable_hash_foreach(fs_registry, str.hash, pos, next, fs_list)
+    {
+        if (pos->fs_name.hash == str.hash) {
+            return pos;
+        }
+    }
+
+    return NULL;
+}
\ No newline at end of file
diff --git a/lunaix-os/kernel/fs/pcache.c b/lunaix-os/kernel/fs/pcache.c
new file mode 100644 (file)
index 0000000..3db7571
--- /dev/null
@@ -0,0 +1,174 @@
+#include <klibc/string.h>
+#include <lunaix/ds/btrie.h>
+#include <lunaix/fs.h>
+#include <lunaix/mm/page.h>
+#include <lunaix/mm/pmm.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/mm/vmm.h>
+#include <lunaix/spike.h>
+
+#define PCACHE_DIRTY 0x1
+
+void
+pcache_init(struct pcache* pcache)
+{
+    btrie_init(&pcache->tree, PG_SIZE_BITS);
+    llist_init_head(&pcache->dirty);
+    llist_init_head(&pcache->pages);
+}
+
+void
+pcache_release_page(struct pcache* pcache, struct pcache_pg* page)
+{
+    pmm_free_page(KERNEL_PID, page->pg);
+    vmm_del_mapping(PD_REFERENCED, page->pg);
+
+    llist_delete(&page->pg_list);
+
+    vfree(page);
+
+    pcache->n_pages--;
+}
+
+struct pcache_pg*
+pcache_new_page(struct pcache* pcache, uint32_t index)
+{
+    void* pg = pmm_alloc_page(KERNEL_PID, 0);
+    void* pg_v = vmm_vmap(pg, PG_SIZE, PG_PREM_URW);
+    struct pcache_pg* ppg = vzalloc(sizeof(struct pcache_pg));
+    ppg->pg = pg_v;
+
+    llist_append(&pcache->pages, &ppg->pg_list);
+    btrie_set(&pcache->tree, index, ppg);
+
+    return ppg;
+}
+
+void
+pcache_set_dirty(struct pcache* pcache, struct pcache_pg* pg)
+{
+    if (!(pg->flags & PCACHE_DIRTY)) {
+        pg->flags |= PCACHE_DIRTY;
+        pcache->n_dirty++;
+        llist_append(&pcache->dirty, &pg->dirty_list);
+    }
+}
+
+struct pcache_pg*
+pcache_get_page(struct pcache* pcache,
+                uint32_t index,
+                uint32_t* offset,
+                struct pcache_pg** page)
+{
+    struct pcache_pg* pg = btrie_get(&pcache->tree, index);
+    int is_new = 0;
+    *offset = index & ((1 << pcache->tree.truncated) - 1);
+    if (!pg) {
+        pg = pcache_new_page(pcache, index);
+        pg->fpos = index - *offset;
+        pcache->n_pages++;
+        is_new = 1;
+    }
+    *page = pg;
+    return is_new;
+}
+
+int
+pcache_write(struct v_file* file, void* data, uint32_t len, uint32_t fpos)
+{
+    uint32_t pg_off, buf_off = 0;
+    struct pcache* pcache = file->inode->pg_cache;
+    struct pcache_pg* pg;
+
+    while (buf_off < len) {
+        pcache_get_page(pcache, fpos, &pg_off, &pg);
+        uint32_t wr_bytes = MIN(PG_SIZE - pg_off, len - buf_off);
+        memcpy(pg->pg + pg_off, (data + buf_off), wr_bytes);
+
+        pcache_set_dirty(pcache, pg);
+
+        buf_off += wr_bytes;
+        fpos += wr_bytes;
+    }
+
+    return buf_off;
+}
+
+int
+pcache_read(struct v_file* file, void* data, uint32_t len, uint32_t fpos)
+{
+    uint32_t pg_off, buf_off = 0, new_pg = 0;
+    int errno = 0;
+    struct pcache* pcache = file->inode->pg_cache;
+    struct pcache_pg* pg;
+    struct v_inode* inode = file->inode;
+
+    while (buf_off < len) {
+        if (pcache_get_page(pcache, fpos, &pg_off, &pg)) {
+            // Filling up the page
+            errno = inode->default_fops.read(file, pg->pg, PG_SIZE, pg->fpos);
+            if (errno >= 0 && errno < PG_SIZE) {
+                // EOF
+                len = buf_off + errno;
+            } else if (errno < 0) {
+                break;
+            }
+        }
+        uint32_t rd_bytes = MIN(PG_SIZE - pg_off, len - buf_off);
+        memcpy((data + buf_off), pg->pg + pg_off, rd_bytes);
+
+        buf_off += rd_bytes;
+        fpos += rd_bytes;
+    }
+
+    return errno < 0 ? errno : buf_off;
+}
+
+void
+pcache_release(struct pcache* pcache)
+{
+    struct pcache_pg *pos, *n;
+    llist_for_each(pos, n, &pcache->pages, pg_list)
+    {
+        vfree(pos);
+    }
+
+    btrie_release(&pcache->tree);
+}
+
+int
+pcache_commit(struct v_file* file, struct pcache_pg* page)
+{
+    if (!(page->flags & PCACHE_DIRTY)) {
+        return;
+    }
+
+    struct v_inode* inode = file->inode;
+    int errno = inode->default_fops.write(file, page->pg, PG_SIZE, page->fpos);
+
+    if (!errno) {
+        page->flags &= ~PCACHE_DIRTY;
+        llist_delete(&page->dirty_list);
+        file->inode->pg_cache->n_dirty--;
+    }
+
+    return errno;
+}
+
+void
+pcache_commit_all(struct v_file* file)
+{
+    struct pcache* cache = file->inode->pg_cache;
+    struct pcache_pg *pos, *n;
+    llist_for_each(pos, n, &cache->dirty, dirty_list)
+    {
+        pcache_commit(file, pos);
+    }
+}
+
+void
+pcache_invalidate(struct v_file* file, struct pcache_pg* page)
+{
+    pcache_commit(file, page);
+    pcache_release_page(&file->inode->pg_cache, page);
+}
\ No newline at end of file
diff --git a/lunaix-os/kernel/fs/twifs/twifs.c b/lunaix-os/kernel/fs/twifs/twifs.c
new file mode 100644 (file)
index 0000000..f535084
--- /dev/null
@@ -0,0 +1,276 @@
+/**
+ * @file twifs.c
+ * @author Lunaixsky (zelong56@gmail.com)
+ * @brief TwiFS - A pseudo file system for kernel state exposure.
+ * @version 0.1
+ * @date 2022-07-21
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+#include <klibc/string.h>
+#include <lunaix/clock.h>
+#include <lunaix/fs.h>
+#include <lunaix/fs/twifs.h>
+#include <lunaix/mm/cake.h>
+#include <lunaix/mm/valloc.h>
+
+static struct twifs_node* fs_root;
+
+static struct cake_pile* twi_pile;
+
+int
+__twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode);
+
+int
+__twifs_openfile(struct v_inode* inode, struct v_file* file);
+
+struct twifs_node*
+__twifs_get_node(struct twifs_node* parent, struct hstr* name);
+
+struct v_inode*
+__twifs_create_inode(struct twifs_node* twi_node);
+
+int
+__twifs_iterate_dir(struct v_file* file, struct dir_context* dctx);
+
+int
+__twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point);
+
+int
+__twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode);
+
+int
+__twifs_rmstuff(struct v_inode* inode);
+
+int
+__twifs_fwrite(struct v_file* file, void* buffer, size_t len, size_t fpos);
+
+int
+__twifs_fread(struct v_file* file, void* buffer, size_t len, size_t fpos);
+
+void
+twifs_init()
+{
+    twi_pile = cake_new_pile("twifs_node", sizeof(struct twifs_node), 1, 0);
+
+    struct filesystem* twifs = vzalloc(sizeof(struct filesystem));
+    twifs->fs_name = HSTR("twifs", 5);
+    twifs->mount = __twifs_mount;
+    twifs->types = FSTYPE_ROFS;
+
+    fsm_register(twifs);
+
+    fs_root = twifs_dir_node(NULL, NULL, 0, 0);
+}
+
+struct twifs_node*
+__twifs_new_node(struct twifs_node* parent,
+                 const char* name,
+                 int name_len,
+                 uint32_t itype)
+{
+    struct twifs_node* node = cake_grab(twi_pile);
+    memset(node, 0, sizeof(*node));
+
+    node->name = HSTR(name, name_len);
+    node->itype = itype;
+    hstr_rehash(&node->name, HSTR_FULL_HASH);
+    llist_init_head(&node->children);
+
+    if (parent) {
+        llist_append(&parent->children, &node->siblings);
+    }
+
+    return node;
+}
+
+int
+twifs_rm_node(struct twifs_node* node)
+{
+    if ((node->itype & VFS_IFDIR) && !llist_empty(&node->children)) {
+        return ENOTEMPTY;
+    }
+    llist_delete(&node->siblings);
+    vfs_i_free(node->inode);
+    cake_release(twi_pile, node);
+    return 0;
+}
+
+struct twifs_node*
+twifs_file_node(struct twifs_node* parent,
+                const char* name,
+                int name_len,
+                uint32_t itype)
+{
+    struct twifs_node* twi_node =
+      __twifs_new_node(parent, name, name_len, VFS_IFFILE | itype);
+
+    struct v_inode* twi_inode = __twifs_create_inode(twi_node);
+    twi_node->inode = twi_inode;
+
+    return twi_node;
+}
+
+struct twifs_node*
+twifs_dir_node(struct twifs_node* parent,
+               const char* name,
+               int name_len,
+               uint32_t itype)
+{
+    struct hstr hname = HSTR(name, name_len);
+    hstr_rehash(&hname, HSTR_FULL_HASH);
+    struct twifs_node* node = __twifs_get_node(parent, &hname);
+    if (node) {
+        return node;
+    }
+
+    struct twifs_node* twi_node =
+      __twifs_new_node(parent, name, name_len, VFS_IFDIR | itype);
+
+    struct v_inode* twi_inode = __twifs_create_inode(twi_node);
+    twi_node->inode = twi_inode;
+
+    return twi_node;
+}
+
+struct twifs_node*
+twifs_toplevel_node(const char* name, int name_len, uint32_t itype)
+{
+    return twifs_dir_node(fs_root, name, name_len, itype);
+}
+
+int
+__twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode)
+{
+    struct twifs_node* parent_node = (struct twifs_node*)inode->data;
+    if (!(parent_node->itype & VFS_IFDIR)) {
+        return ENOTDIR;
+    }
+    struct twifs_node* new_node =
+      twifs_dir_node(parent_node, dnode->name.value, dnode->name.len, 0);
+    dnode->inode = new_node->inode;
+
+    return 0;
+}
+
+int
+__twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
+{
+    mount_point->inode = fs_root->inode;
+    return 0;
+}
+
+struct v_inode*
+__twifs_create_inode(struct twifs_node* twi_node)
+{
+    struct v_inode* inode = vfs_i_alloc();
+    *inode = (struct v_inode){ .ctime = 0,
+                               .itype = twi_node->itype,
+                               .lb_addr = 0,
+                               .lb_usage = 0,
+                               .data = twi_node,
+                               .mtime = 0,
+                               .open_count = 0 };
+    inode->ops.dir_lookup = __twifs_dirlookup;
+    inode->ops.mkdir = __twifs_mkdir;
+    inode->ops.unlink = __twifs_rmstuff;
+    inode->ops.rmdir = __twifs_rmstuff;
+    inode->ops.open = __twifs_openfile;
+
+    inode->default_fops = (struct v_file_ops){ .read = __twifs_fread,
+                                               .write = __twifs_fwrite,
+                                               .readdir = __twifs_iterate_dir };
+
+    return inode;
+}
+
+int
+__twifs_fwrite(struct v_file* file, void* buffer, size_t len, size_t fpos)
+{
+    struct twifs_node* twi_node = (struct twifs_node*)file->inode->data;
+    if (!twi_node || !twi_node->ops.write) {
+        return ENOTSUP;
+    }
+    return twi_node->ops.write(file, buffer, len, fpos);
+}
+
+int
+__twifs_fread(struct v_file* file, void* buffer, size_t len, size_t fpos)
+{
+    struct twifs_node* twi_node = (struct twifs_node*)file->inode->data;
+    if (!twi_node || !twi_node->ops.read) {
+        return ENOTSUP;
+    }
+    return twi_node->ops.read(file, buffer, len, fpos);
+}
+
+struct twifs_node*
+__twifs_get_node(struct twifs_node* parent, struct hstr* name)
+{
+    if (!parent)
+        return NULL;
+
+    struct twifs_node *pos, *n;
+    llist_for_each(pos, n, &parent->children, siblings)
+    {
+        if (HSTR_EQ(&pos->name, name)) {
+            return pos;
+        }
+    }
+    return NULL;
+}
+
+int
+__twifs_rmstuff(struct v_inode* inode)
+{
+    struct twifs_node* twi_node = (struct twifs_node*)inode->data;
+    return twifs_rm_node(twi_node);
+}
+
+int
+__twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode)
+{
+    struct twifs_node* twi_node = (struct twifs_node*)inode->data;
+
+    if (!(twi_node->itype & VFS_IFDIR)) {
+        return ENOTDIR;
+    }
+
+    struct twifs_node* child_node = __twifs_get_node(twi_node, &dnode->name);
+    if (child_node) {
+        dnode->inode = child_node->inode;
+        return 0;
+    }
+    return ENOENT;
+}
+
+int
+__twifs_iterate_dir(struct v_file* file, struct dir_context* dctx)
+{
+    struct twifs_node* twi_node = (struct twifs_node*)(file->inode->data);
+    int counter = 0;
+    struct twifs_node *pos, *n;
+
+    llist_for_each(pos, n, &twi_node->children, siblings)
+    {
+        if (counter++ >= dctx->index) {
+            dctx->index = counter;
+            dctx->read_complete_callback(
+              dctx, pos->name.value, pos->name.len, pos->itype);
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+int
+__twifs_openfile(struct v_inode* inode, struct v_file* file)
+{
+    struct twifs_node* twi_node = (struct twifs_node*)inode->data;
+    if (twi_node) {
+        return 0;
+    }
+    return ENOTSUP;
+}
diff --git a/lunaix-os/kernel/fs/vfs.c b/lunaix-os/kernel/fs/vfs.c
new file mode 100644 (file)
index 0000000..11896ec
--- /dev/null
@@ -0,0 +1,1033 @@
+/**
+ * @file vfs.c
+ * @author Lunaixsky (zelong56@gmail.com)
+ * @brief Lunaix virtual file system - an abstraction layer for all file system.
+ * @version 0.1
+ * @date 2022-07-24
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+
+#include <klibc/string.h>
+#include <lunaix/dirent.h>
+#include <lunaix/foptions.h>
+#include <lunaix/fs.h>
+#include <lunaix/mm/cake.h>
+#include <lunaix/mm/page.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/process.h>
+#include <lunaix/spike.h>
+#include <lunaix/syscall.h>
+
+#define PATH_DELIM '/'
+#define DNODE_HASHTABLE_BITS 10
+#define DNODE_HASHTABLE_SIZE (1 << DNODE_HASHTABLE_BITS)
+#define DNODE_HASH_MASK (DNODE_HASHTABLE_SIZE - 1)
+#define DNODE_HASHBITS (32 - DNODE_HASHTABLE_BITS)
+
+static struct cake_pile* dnode_pile;
+static struct cake_pile* inode_pile;
+static struct cake_pile* file_pile;
+static struct cake_pile* superblock_pile;
+static struct cake_pile* fd_pile;
+
+static struct v_superblock* root_sb;
+static struct hbucket* dnode_cache;
+
+static int fs_id = 0;
+
+struct hstr vfs_ddot = HSTR("..", 2);
+struct hstr vfs_dot = HSTR(".", 1);
+struct hstr vfs_empty = HSTR("", 0);
+
+struct v_dnode*
+vfs_d_alloc();
+
+void
+vfs_d_free(struct v_dnode* dnode);
+
+struct v_superblock*
+vfs_sb_alloc();
+
+void
+vfs_sb_free(struct v_superblock* sb);
+
+void
+vfs_init()
+{
+    // 为他们专门创建一个蛋糕堆,而不使用valloc,这样我们可以最小化内碎片的产生
+    dnode_pile = cake_new_pile("dnode_cache", sizeof(struct v_dnode), 1, 0);
+    inode_pile = cake_new_pile("inode_cache", sizeof(struct v_inode), 1, 0);
+    file_pile = cake_new_pile("file_cache", sizeof(struct v_file), 1, 0);
+    fd_pile = cake_new_pile("fd_cache", sizeof(struct v_fd), 1, 0);
+    superblock_pile =
+      cake_new_pile("sb_cache", sizeof(struct v_superblock), 1, 0);
+
+    dnode_cache = vzalloc(DNODE_HASHTABLE_SIZE * sizeof(struct hbucket));
+
+    hstr_rehash(&vfs_ddot, HSTR_FULL_HASH);
+    hstr_rehash(&vfs_dot, HSTR_FULL_HASH);
+
+    // 创建一个根superblock,用来蕴含我们的根目录。
+    root_sb = vfs_sb_alloc();
+    root_sb->root = vfs_d_alloc();
+    root_sb->root->inode = vfs_i_alloc();
+}
+
+inline struct hbucket*
+__dcache_get_bucket(struct v_dnode* parent, unsigned int hash)
+{
+    // 与parent的指针值做加法,来减小碰撞的可能性。
+    hash += (uint32_t)parent;
+    // 确保低位更加随机
+    hash = hash ^ (hash >> DNODE_HASHBITS);
+    return &dnode_cache[hash & DNODE_HASH_MASK];
+}
+
+struct v_dnode*
+vfs_dcache_lookup(struct v_dnode* parent, struct hstr* str)
+{
+    if (!str->len || HSTR_EQ(str, &vfs_dot))
+        return parent;
+
+    if (HSTR_EQ(str, &vfs_ddot)) {
+        return parent->parent ? parent->parent : parent;
+    }
+
+    struct hbucket* slot = __dcache_get_bucket(parent, str->hash);
+
+    struct v_dnode *pos, *n;
+    hashtable_bucket_foreach(slot, pos, n, hash_list)
+    {
+        if (pos->name.hash == str->hash) {
+            return pos;
+        }
+    }
+    return NULL;
+}
+
+void
+vfs_dcache_add(struct v_dnode* parent, struct v_dnode* dnode)
+{
+    struct hbucket* bucket = __dcache_get_bucket(parent, dnode->name.hash);
+    hlist_add(&bucket->head, &dnode->hash_list);
+}
+
+int
+__vfs_walk(struct v_dnode* start,
+           const char* path,
+           struct v_dnode** dentry,
+           struct hstr* component,
+           int walk_options)
+{
+    int errno = 0;
+    int i = 0, j = 0;
+
+    if (path[0] == PATH_DELIM || !start) {
+        if ((walk_options & VFS_WALK_FSRELATIVE) && start) {
+            start = start->super_block->root;
+        } else {
+            start = root_sb->root;
+        }
+        i++;
+    }
+
+    struct v_dnode* dnode;
+    struct v_dnode* current_level = start;
+
+    char name_content[VFS_NAME_MAXLEN];
+    struct hstr name = HSTR(name_content, 0);
+
+    char current = path[i++], lookahead;
+    while (current) {
+        lookahead = path[i++];
+        if (current != PATH_DELIM) {
+            if (j >= VFS_NAME_MAXLEN - 1) {
+                return ENAMETOOLONG;
+            }
+            if (!VFS_VALID_CHAR(current)) {
+                return EINVAL;
+            }
+            name_content[j++] = current;
+            if (lookahead) {
+                goto cont;
+            }
+        }
+
+        // handling cases like /^.*(\/+).*$/
+        if (lookahead == PATH_DELIM) {
+            goto cont;
+        }
+
+        name_content[j] = 0;
+        name.len = j;
+        hstr_rehash(&name, HSTR_FULL_HASH);
+
+        if (!lookahead && (walk_options & VFS_WALK_PARENT)) {
+            if (component) {
+                component->hash = name.hash;
+                component->len = j;
+                strcpy(component->value, name_content);
+            }
+            break;
+        }
+
+        dnode = vfs_dcache_lookup(current_level, &name);
+
+        if (!dnode) {
+            dnode = vfs_d_alloc();
+            dnode->name = HHSTR(valloc(VFS_NAME_MAXLEN), j, name.hash);
+
+            strcpy(dnode->name.value, name_content);
+
+            errno =
+              current_level->inode->ops.dir_lookup(current_level->inode, dnode);
+
+            if (errno == ENOENT && (walk_options & VFS_WALK_MKPARENT)) {
+                if (!current_level->inode->ops.mkdir) {
+                    errno = ENOTSUP;
+                } else {
+                    errno = current_level->inode->ops.mkdir(
+                      current_level->inode, dnode);
+                }
+            }
+
+            if (errno) {
+                goto error;
+            }
+
+            vfs_dcache_add(current_level, dnode);
+
+            dnode->parent = current_level;
+            llist_append(&current_level->children, &dnode->siblings);
+        }
+
+        j = 0;
+        current_level = dnode;
+    cont:
+        current = lookahead;
+    };
+
+    *dentry = current_level;
+    return 0;
+
+error:
+    vfree(dnode->name.value);
+    vfs_d_free(dnode);
+    *dentry = NULL;
+    return errno;
+}
+
+#define VFS_MAX_SYMLINK 16
+
+int
+vfs_walk(struct v_dnode* start,
+         const char* path,
+         struct v_dnode** dentry,
+         struct hstr* component,
+         int options)
+{
+    struct v_dnode* interim;
+    char* pathname = path;
+    int errno = __vfs_walk(start, path, &interim, component, options);
+    int counter = 0;
+
+    while (!errno) {
+        if (counter >= VFS_MAX_SYMLINK) {
+            errno = ELOOP;
+            continue;
+        }
+        if ((interim->inode->itype & VFS_IFSYMLINK) &&
+            !(options & VFS_WALK_NOFOLLOW) &&
+            interim->inode->ops.read_symlink) {
+            errno = interim->inode->ops.read_symlink(interim->inode, &pathname);
+            if (errno) {
+                break;
+            }
+        } else {
+            break;
+        }
+        errno = __vfs_walk(start, pathname, &interim, component, options);
+        counter++;
+    }
+
+    *dentry = errno ? 0 : interim;
+
+    return errno;
+}
+
+int
+vfs_mount(const char* target, const char* fs_name, bdev_t device)
+{
+    int errno;
+    struct v_dnode* mnt;
+
+    if (!(errno = vfs_walk(NULL, target, &mnt, NULL, 0))) {
+        errno = vfs_mount_at(fs_name, device, mnt);
+    }
+
+    return errno;
+}
+
+int
+vfs_unmount(const char* target)
+{
+    int errno;
+    struct v_dnode* mnt;
+
+    if (!(errno = vfs_walk(NULL, target, &mnt, NULL, 0))) {
+        errno = vfs_unmount_at(mnt);
+    }
+
+    return errno;
+}
+
+int
+vfs_mount_at(const char* fs_name, bdev_t device, struct v_dnode* mnt_point)
+{
+    struct filesystem* fs = fsm_get(fs_name);
+    if (!fs)
+        return ENODEV;
+    struct v_superblock* sb = vfs_sb_alloc();
+    sb->dev = device;
+    sb->fs_id = fs_id++;
+
+    int errno = 0;
+    if (!(errno = fs->mount(sb, mnt_point))) {
+        sb->fs = fs;
+        sb->root = mnt_point;
+        mnt_point->super_block = sb;
+        llist_append(&root_sb->sb_list, &sb->sb_list);
+    }
+
+    return errno;
+}
+
+int
+vfs_unmount_at(struct v_dnode* mnt_point)
+{
+    int errno = 0;
+    struct v_superblock* sb = mnt_point->super_block;
+    if (!sb) {
+        return EINVAL;
+    }
+    if (!(errno = sb->fs->unmount(sb))) {
+        struct v_dnode* fs_root = sb->root;
+        llist_delete(&fs_root->siblings);
+        llist_delete(&sb->sb_list);
+        vfs_sb_free(sb);
+    }
+    return errno;
+}
+
+int
+vfs_open(struct v_dnode* dnode, struct v_file** file)
+{
+    if (!dnode->inode || !dnode->inode->ops.open) {
+        return ENOTSUP;
+    }
+
+    struct v_inode* inode = dnode->inode;
+    struct v_file* vfile = cake_grab(file_pile);
+    memset(vfile, 0, sizeof(*vfile));
+
+    vfile->dnode = dnode;
+    vfile->inode = inode;
+    vfile->ref_count = 1;
+    vfile->ops = inode->default_fops;
+    inode->open_count++;
+
+    if ((inode->itype & VFS_IFFILE) && !inode->pg_cache) {
+        struct pcache* pcache = vzalloc(sizeof(struct pcache));
+        pcache_init(pcache);
+        inode->pg_cache = pcache;
+    }
+
+    int errno = inode->ops.open(inode, vfile);
+    if (errno) {
+        cake_release(file_pile, vfile);
+    } else {
+        *file = vfile;
+    }
+    return errno;
+}
+
+int
+vfs_link(struct v_dnode* to_link, struct v_dnode* name)
+{
+    int errno;
+    if (to_link->super_block->root != name->super_block->root) {
+        errno = EXDEV;
+    } else if (!to_link->inode->ops.link) {
+        errno = ENOTSUP;
+    } else if (!(errno = to_link->inode->ops.link(to_link->inode, name))) {
+        name->inode = to_link->inode;
+        to_link->inode->link_count++;
+    }
+
+    return errno;
+}
+
+int
+vfs_close(struct v_file* file)
+{
+    int errno = 0;
+    if (!file->ops.close || !(errno = file->ops.close(file))) {
+        if (file->inode->open_count) {
+            file->inode->open_count--;
+        }
+        pcache_commit_all(file);
+        cake_release(file_pile, file);
+    }
+    return errno;
+}
+
+int
+vfs_fsync(struct v_file* file)
+{
+    int errno = ENOTSUP;
+    pcache_commit_all(file);
+    if (file->ops.sync) {
+        errno = file->ops.sync(file);
+    }
+    if (!errno && file->inode->ops.sync) {
+        return file->inode->ops.sync(file->inode);
+    }
+    return errno;
+}
+
+int
+vfs_alloc_fdslot(int* fd)
+{
+    for (size_t i = 0; i < VFS_MAX_FD; i++) {
+        if (!__current->fdtable->fds[i]) {
+            *fd = i;
+            return 0;
+        }
+    }
+    return EMFILE;
+}
+
+struct v_superblock*
+vfs_sb_alloc()
+{
+    struct v_superblock* sb = cake_grab(superblock_pile);
+    memset(sb, 0, sizeof(*sb));
+    llist_init_head(&sb->sb_list);
+    return sb;
+}
+
+void
+vfs_sb_free(struct v_superblock* sb)
+{
+    cake_release(superblock_pile, sb);
+}
+
+struct v_dnode*
+vfs_d_alloc()
+{
+    struct v_dnode* dnode = cake_grab(dnode_pile);
+    memset(dnode, 0, sizeof(*dnode));
+    llist_init_head(&dnode->children);
+    dnode->name = vfs_empty;
+    return dnode;
+}
+
+void
+vfs_d_free(struct v_dnode* dnode)
+{
+    if (dnode->ops.destruct) {
+        dnode->ops.destruct(dnode);
+    }
+    cake_release(dnode_pile, dnode);
+}
+
+struct v_inode*
+vfs_i_alloc()
+{
+    struct v_inode* inode = cake_grab(inode_pile);
+    memset(inode, 0, sizeof(*inode));
+    return inode;
+}
+
+void
+vfs_i_free(struct v_inode* inode)
+{
+    cake_release(inode_pile, inode);
+}
+
+/* ---- System call definition and support ---- */
+
+#define FLOCATE_CREATE_EMPTY 1
+
+#define DO_STATUS(errno) SYSCALL_ESTATUS(__current->k_status = errno)
+#define DO_STATUS_OR_RETURN(errno) ({ errno < 0 ? DO_STATUS(errno) : errno; })
+
+int
+__vfs_try_locate_file(const char* path,
+                      struct v_dnode** fdir,
+                      struct v_dnode** file,
+                      int options)
+{
+    char name_str[VFS_NAME_MAXLEN];
+    struct hstr name = HSTR(name_str, 0);
+    int errno;
+    if ((errno = vfs_walk(NULL, path, fdir, &name, VFS_WALK_PARENT))) {
+        return errno;
+    }
+
+    errno = vfs_walk(*fdir, name.value, file, NULL, 0);
+    if (errno != ENOENT || !(options & FLOCATE_CREATE_EMPTY)) {
+        return errno;
+    }
+
+    if (!(errno = (*fdir)->inode->ops.create((*fdir)->inode))) {
+        struct v_dnode* file_new;
+        file_new = vfs_d_alloc();
+        file_new->name = HHSTR(valloc(VFS_NAME_MAXLEN), name.len, name.hash);
+        strcpy(file_new->name.value, name_str);
+        *file = file_new;
+
+        llist_append(&(*fdir)->children, &file_new->siblings);
+    }
+
+    return errno;
+}
+
+int
+__file_cached_read(struct v_file* file, void* buf, size_t len, size_t fpos)
+{
+    return pcache_read(file, buf, len, fpos);
+}
+
+int
+vfs_do_open(const char* path, int options)
+{
+    int errno, fd;
+    struct v_dnode *dentry, *file;
+    struct v_file* ofile = 0;
+
+    errno = __vfs_try_locate_file(path, &dentry, &file, 0);
+
+    if (errno != ENOENT && (options & FO_CREATE)) {
+        errno = dentry->inode->ops.create(dentry->inode);
+    }
+
+    if (!errno && (errno = vfs_open(file, &ofile))) {
+        return errno;
+    }
+
+    struct v_inode* o_inode = ofile->inode;
+    if (!(o_inode->itype & VFS_IFSEQDEV) && !(options & FO_DIRECT)) {
+        // XXX Change here accordingly when signature of pcache_r/w changed.
+        ofile->ops.read = pcache_read;
+        ofile->ops.write = pcache_write;
+    }
+
+    if (!errno && !(errno = vfs_alloc_fdslot(&fd))) {
+        struct v_fd* fd_s = vzalloc(sizeof(*fd_s));
+        ofile->f_pos = ofile->inode->fsize & -((options & FO_APPEND) != 0);
+        fd_s->file = ofile;
+        fd_s->flags = options;
+        __current->fdtable->fds[fd] = fd_s;
+        return fd;
+    }
+
+    return errno;
+}
+
+__DEFINE_LXSYSCALL2(int, open, const char*, path, int, options)
+{
+    int errno = vfs_do_open(path, options);
+    return DO_STATUS_OR_RETURN(errno);
+}
+
+#define TEST_FD(fd) (fd >= 0 && fd < VFS_MAX_FD)
+#define GET_FD(fd, fd_s) (TEST_FD(fd) && (fd_s = __current->fdtable->fds[fd]))
+
+__DEFINE_LXSYSCALL1(int, close, int, fd)
+{
+    struct v_fd* fd_s;
+    int errno = 0;
+    if (!GET_FD(fd, fd_s)) {
+        errno = EBADF;
+        goto done_err;
+    }
+
+    if (fd_s->file->ref_count > 1) {
+        fd_s->file->ref_count--;
+    } else if ((errno = vfs_close(fd_s->file))) {
+        goto done_err;
+    }
+
+    vfree(fd_s);
+    __current->fdtable->fds[fd] = 0;
+
+done_err:
+    return DO_STATUS(errno);
+}
+
+void
+__vfs_readdir_callback(struct dir_context* dctx,
+                       const char* name,
+                       const int len,
+                       const int dtype)
+{
+    struct dirent* dent = (struct dirent*)dctx->cb_data;
+    strncpy(dent->d_name, name, DIRENT_NAME_MAX_LEN);
+    dent->d_nlen = len;
+    dent->d_type = dtype;
+}
+
+__DEFINE_LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent)
+{
+    struct v_fd* fd_s;
+    int errno;
+    if (!GET_FD(fd, fd_s)) {
+        errno = EBADF;
+    } else if (!(fd_s->file->inode->itype & VFS_IFDIR)) {
+        errno = ENOTDIR;
+    } else {
+        struct dir_context dctx =
+          (struct dir_context){ .cb_data = dent,
+                                .index = dent->d_offset,
+                                .read_complete_callback =
+                                  __vfs_readdir_callback };
+        if (dent->d_offset == 0) {
+            __vfs_readdir_callback(&dctx, vfs_dot.value, vfs_dot.len, 0);
+        } else if (dent->d_offset == 1) {
+            __vfs_readdir_callback(&dctx, vfs_ddot.value, vfs_ddot.len, 0);
+        } else {
+            dctx.index -= 2;
+            if ((errno = fd_s->file->ops.readdir(fd_s->file, &dctx))) {
+                goto done;
+            }
+        }
+        errno = 0;
+        dent->d_offset++;
+    }
+
+done:
+    return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL1(int, mkdir, const char*, path)
+{
+    struct v_dnode *parent, *dir;
+    struct hstr component = HSTR(valloc(VFS_NAME_MAXLEN), 0);
+    int errno = vfs_walk(NULL, path, &parent, &component, VFS_WALK_PARENT);
+    if (errno) {
+        goto done;
+    }
+
+    if ((parent->super_block->fs->types & FSTYPE_ROFS)) {
+        errno = ENOTSUP;
+    } else if (!parent->inode->ops.mkdir) {
+        errno = ENOTSUP;
+    } else if (!(parent->inode->itype & VFS_IFDIR)) {
+        errno = ENOTDIR;
+    } else {
+        dir = vfs_d_alloc();
+        dir->name = component;
+        if (!(errno = parent->inode->ops.mkdir(parent->inode, dir))) {
+            llist_append(&parent->children, &dir->siblings);
+        } else {
+            vfs_d_free(dir);
+            vfree(component.value);
+        }
+    }
+
+done:
+    return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
+{
+    int errno = 0;
+    struct v_fd* fd_s;
+    if (!GET_FD(fd, fd_s)) {
+        errno = EBADF;
+        goto done;
+    }
+
+    struct v_file* file = fd_s->file;
+    if ((file->inode->itype & VFS_IFDIR)) {
+        errno = EISDIR;
+        goto done;
+    }
+
+    cpu_enable_interrupt();
+    errno = file->ops.read(file, buf, count, file->f_pos);
+    cpu_disable_interrupt();
+
+    if (errno > 0) {
+        file->f_pos += errno;
+        return errno;
+    }
+
+done:
+    return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
+{
+    int errno = 0;
+    struct v_fd* fd_s;
+    if (!GET_FD(fd, fd_s)) {
+        errno = EBADF;
+        goto done;
+    }
+
+    struct v_file* file = fd_s->file;
+    if ((file->inode->itype & VFS_IFDIR)) {
+        errno = EISDIR;
+        goto done;
+    }
+
+    cpu_enable_interrupt();
+    errno = file->ops.write(file, buf, count, file->f_pos);
+    cpu_disable_interrupt();
+
+    if (errno > 0) {
+        file->f_pos += errno;
+        return errno;
+    }
+
+done:
+    return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL3(int, lseek, int, fd, int, offset, int, options)
+{
+    int errno = 0;
+    struct v_fd* fd_s;
+    if (!GET_FD(fd, fd_s)) {
+        errno = EBADF;
+    } else {
+        struct v_file* file = fd_s->file;
+        size_t fpos = file->f_pos;
+        switch (options) {
+            case FSEEK_CUR:
+                fpos = (size_t)((int)file->f_pos + offset);
+                break;
+            case FSEEK_END:
+                fpos = (size_t)((int)file->inode->fsize + offset);
+                break;
+            case FSEEK_SET:
+                fpos = offset;
+                break;
+        }
+        if (!file->ops.seek || !(errno = file->ops.seek(file, fpos))) {
+            file->f_pos = fpos;
+        }
+    }
+
+    return DO_STATUS(errno);
+}
+
+int
+vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth)
+{
+    if (!dnode) {
+        return 0;
+    }
+
+    if (depth > 64) {
+        return ELOOP;
+    }
+
+    size_t len = vfs_get_path(dnode->parent, buf, size, depth + 1);
+
+    if (len >= size) {
+        return len;
+    }
+
+    size_t cpy_size = MIN(dnode->name.len, size - len);
+    strncpy(buf + len, dnode->name.value, cpy_size);
+    len += cpy_size;
+
+    if (len < size) {
+        buf[len++] = PATH_DELIM;
+    }
+
+    return len;
+}
+
+int
+vfs_readlink(struct v_dnode* dnode, char* buf, size_t size)
+{
+    char* link;
+    if (dnode->inode->ops.read_symlink) {
+        int errno = dnode->inode->ops.read_symlink(dnode->inode, &link);
+        strncpy(buf, link, size);
+        return errno;
+    }
+    return 0;
+}
+
+__DEFINE_LXSYSCALL3(int, realpathat, int, fd, char*, buf, size_t, size)
+{
+    int errno;
+    struct v_fd* fd_s;
+    if (!GET_FD(fd, fd_s)) {
+        errno = EBADF;
+    } else {
+        struct v_dnode* dnode;
+        errno = vfs_get_path(fd_s->file->dnode, buf, size, 0);
+    }
+
+    if (errno >= 0) {
+        return errno;
+    }
+
+    return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL3(int, readlink, const char*, path, char*, buf, size_t, size)
+{
+    int errno;
+    struct v_dnode* dnode;
+    if (!(errno = vfs_walk(NULL, path, &dnode, NULL, VFS_WALK_NOFOLLOW))) {
+        errno = vfs_readlink(dnode, buf, size);
+    }
+
+    if (errno >= 0) {
+        return errno;
+    }
+
+    return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL4(int,
+                    readlinkat,
+                    int,
+                    dirfd,
+                    const char*,
+                    pathname,
+                    char*,
+                    buf,
+                    size_t,
+                    size)
+{
+    int errno;
+    struct v_fd* fd_s;
+    if (!GET_FD(dirfd, fd_s)) {
+        errno = EBADF;
+    } else {
+        struct v_dnode* dnode;
+        if (!(errno = vfs_walk(fd_s->file->dnode,
+                               pathname,
+                               &dnode,
+                               NULL,
+                               VFS_WALK_NOFOLLOW))) {
+            errno = vfs_readlink(fd_s->file->dnode, buf, size);
+        }
+    }
+
+    if (errno >= 0) {
+        return errno;
+    }
+
+    return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL1(int, rmdir, const char*, pathname)
+{
+    int errno;
+    struct v_dnode* dnode;
+    if ((errno = vfs_walk(NULL, pathname, &dnode, NULL, 0))) {
+        goto done;
+    }
+    if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
+        errno = EROFS;
+        goto done;
+    }
+
+    if (dnode->inode->open_count) {
+        errno = EBUSY;
+        goto done;
+    }
+
+    if ((dnode->inode->itype & VFS_IFDIR)) {
+        errno = dnode->inode->ops.rmdir(dnode->inode);
+    } else {
+        errno = ENOTDIR;
+    }
+
+done:
+    return DO_STATUS(errno);
+}
+
+int
+__vfs_do_unlink(struct v_inode* inode)
+{
+    int errno;
+    if (inode->open_count) {
+        errno = EBUSY;
+    } else if (!(inode->itype & VFS_IFDIR)) {
+        // TODO handle symbolic link and type other than regular file
+        errno = inode->ops.unlink(inode);
+        if (!errno) {
+            inode->link_count--;
+        }
+    } else {
+        errno = EISDIR;
+    }
+
+    return errno;
+}
+
+__DEFINE_LXSYSCALL1(int, unlink, const char*, pathname)
+{
+    int errno;
+    struct v_dnode* dnode;
+    if ((errno = vfs_walk(NULL, pathname, &dnode, NULL, 0))) {
+        goto done;
+    }
+    if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
+        errno = EROFS;
+        goto done;
+    }
+
+    errno = __vfs_do_unlink(dnode->inode);
+
+done:
+    return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname)
+{
+    int errno;
+    struct v_fd* fd_s;
+    if (!GET_FD(fd, fd_s)) {
+        errno = EBADF;
+    } else {
+        struct v_dnode* dnode;
+        if (!(errno = vfs_walk(fd_s->file->dnode, pathname, &dnode, NULL, 0))) {
+            errno = __vfs_do_unlink(dnode->inode);
+        }
+    }
+
+done:
+    return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL2(int, link, const char*, oldpath, const char*, newpath)
+{
+    int errno;
+    struct v_dnode *dentry, *to_link, *name_dentry, *name_file;
+
+    errno = __vfs_try_locate_file(oldpath, &dentry, &to_link, 0);
+    if (!errno) {
+        errno = __vfs_try_locate_file(
+          newpath, &name_dentry, &name_file, FLOCATE_CREATE_EMPTY);
+        if (!errno) {
+            errno = EEXIST;
+        } else if (name_file) {
+            errno = vfs_link(to_link, name_file);
+        }
+    }
+    return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL1(int, fsync, int, fildes)
+{
+    int errno;
+    struct v_fd* fd_s;
+    if (!GET_FD(fildes, fd_s)) {
+        errno = EBADF;
+    } else {
+        errno = vfs_fsync(fd_s->file);
+    }
+
+    return DO_STATUS(errno);
+}
+
+int
+vfs_dup_fd(struct v_fd* old, struct v_fd** new)
+{
+    int errno = 0;
+    struct v_fd* copied = cake_grab(fd_pile);
+
+    memcpy(copied, old, sizeof(struct v_fd));
+    old->file->ref_count++;
+
+    *new = copied;
+
+    return errno;
+}
+
+int
+vfs_dup2(int oldfd, int newfd)
+{
+    if (newfd == oldfd) {
+        return newfd;
+    }
+
+    int errno;
+    struct v_fd *oldfd_s, *newfd_s;
+    if (!GET_FD(oldfd, oldfd_s) || !TEST_FD(newfd)) {
+        errno = EBADF;
+        goto done;
+    }
+    newfd_s = __current->fdtable->fds[newfd];
+    if (newfd_s && (errno = vfs_close(newfd_s))) {
+        goto done;
+    }
+
+    if (!(errno = vfs_dup_fd(oldfd_s, &newfd_s))) {
+        __current->fdtable->fds[newfd] = newfd_s;
+        return newfd;
+    }
+
+done:
+    return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL2(int, dup2, int, oldfd, int, newfd)
+{
+    return vfs_dup2(oldfd, newfd);
+}
+
+__DEFINE_LXSYSCALL1(int, dup, int, oldfd)
+{
+    int errno, newfd;
+    struct v_fd *oldfd_s, *newfd_s;
+    if (!GET_FD(oldfd, oldfd_s)) {
+        errno = EBADF;
+    } else if (!(errno = vfs_alloc_fdslot(&newfd)) &&
+               !(errno = vfs_dup_fd(oldfd_s, &newfd_s))) {
+        __current->fdtable->fds[newfd] = newfd_s;
+        return newfd;
+    }
+
+    return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL2(int,
+                    symlink,
+                    const char*,
+                    pathname,
+                    const char*,
+                    link_target)
+{
+    int errno;
+    struct v_dnode* dnode;
+    if ((errno = vfs_walk(NULL, pathname, &dnode, NULL, 0))) {
+        goto done;
+    }
+    if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
+        errno = EROFS;
+        goto done;
+    }
+    if (!dnode->inode->ops.symlink) {
+        errno = ENOTSUP;
+        goto done;
+    }
+
+    errno = dnode->inode->ops.symlink(dnode->inode, link_target);
+
+done:
+    return DO_STATUS(errno);
+}
\ No newline at end of file
index 7acd3065b15c73f86b57e81a70dcce86d9b1805f..b0aee844c2376206ea6312ce934fa876c17b6f0d 100644 (file)
@@ -2,6 +2,7 @@
 #include <lunaix/tty/tty.h>
 
 #include <lunaix/clock.h>
+#include <lunaix/device.h>
 #include <lunaix/lxconsole.h>
 #include <lunaix/mm/kalloc.h>
 #include <lunaix/mm/page.h>
@@ -77,11 +78,20 @@ _kernel_pre_init()
 void
 _kernel_init()
 {
-    lxconsole_init();
 
-    kprintf(KINFO "[MM] Allocated %d pages for stack start at %p\n",
-            KSTACK_SIZE >> PG_SIZE_BITS,
-            KSTACK_START);
+    cake_init();
+    valloc_init();
+
+    fsm_init();
+    vfs_init();
+    twifs_init();
+
+    device_init();
+
+    // 挂载 TwiFS 为根目录
+    vfs_mount("/", "twifs", -1);
+
+    lxconsole_init();
 
     sched_init();
 
index d6b92f8c719b425571ce7235580f9d23f36172b6..e58e3f108fb7de8da6504ad617e1f1911f00afea 100644 (file)
@@ -1,33 +1,97 @@
 #include <klibc/string.h>
+#include <lunaix/device.h>
+#include <lunaix/keyboard.h>
 #include <lunaix/lxconsole.h>
 #include <lunaix/mm/pmm.h>
+#include <lunaix/mm/valloc.h>
 #include <lunaix/mm/vmm.h>
+#include <lunaix/sched.h>
 #include <lunaix/tty/console.h>
 #include <lunaix/tty/tty.h>
 
 static struct console lx_console;
 
+int
+__tty_write(struct device* dev, void* buf, size_t offset, size_t len);
+
+int
+__tty_read(struct device* dev, void* buf, size_t offset, size_t len);
+
 void
 lxconsole_init()
 {
     memset(&lx_console, 0, sizeof(lx_console));
-    lx_console.buffer.data = VGA_BUFFER_VADDR + 0x1000;
-    lx_console.buffer.size = 8192;
-    mutex_init(&lx_console.buffer.lock);
+    fifo_init(&lx_console.output, VGA_BUFFER_VADDR + 0x1000, 8192, 0);
+    fifo_init(&lx_console.input, valloc(4096), 4096, 0);
+
+    // FIXME use valloc to allocate console buffer.
+    // In doing this, the console buffer can only be accessed from kernel mode
+    //  any direct write to this buffer from user land should be purged!
 
     // 分配控制台缓存
-    for (size_t i = 0; i < PG_ALIGN(lx_console.buffer.size); i += PG_SIZE) {
+    for (size_t i = 0; i < PG_ALIGN(lx_console.output.size); i += PG_SIZE) {
         uintptr_t pa = pmm_alloc_page(KERNEL_PID, 0);
         vmm_set_mapping(PD_REFERENCED,
-                        (uintptr_t)lx_console.buffer.data + i,
+                        (uintptr_t)lx_console.output.data + i,
                         pa,
                         PG_PREM_URW,
                         0);
     }
 
-    memset(lx_console.buffer.data, 0, lx_console.buffer.size);
-
     lx_console.flush_timer = NULL;
+
+    struct device* tty_dev = device_addseq(NULL, &lx_console, "tty");
+    tty_dev->write = __tty_write;
+    tty_dev->read = __tty_read;
+}
+
+int
+__tty_write(struct device* dev, void* buf, size_t offset, size_t len)
+{
+    struct console* console = (struct console*)dev->underlay;
+    console_write(console, buf, len);
+}
+
+int
+__tty_read(struct device* dev, void* buf, size_t offset, size_t len)
+{
+    struct kdb_keyinfo_pkt keyevent;
+    struct console* console = (struct console*)dev->underlay;
+
+    size_t count = fifo_read(&console->input, buf, len);
+    if (count > 0 && ((char*)buf)[count - 1] == '\n') {
+        return count;
+    }
+
+    while (count < len) {
+        // FIXME RACE!
+        //  Consider two process that is polling the input key simultaneously.
+        //  When a key is arrived, one of the processes will win the race and
+        //  swallow it (advancing the key buffer pointer)
+        if (!kbd_recv_key(&keyevent)) {
+            sched_yield();
+            continue;
+        }
+        if (!(keyevent.state & KBD_KEY_FPRESSED)) {
+            continue;
+        }
+        if ((keyevent.keycode & 0xff00) > KEYPAD) {
+            continue;
+        }
+
+        char c = (char)(keyevent.keycode & 0x00ff);
+        if (c == 0x08) {
+            if (fifo_backone(&console->input)) {
+                console_write_char(c);
+            }
+            continue;
+        }
+        console_write_char(c);
+        if (!fifo_putone(&console->input, c) || c == '\n') {
+            break;
+        }
+    }
+    return count + fifo_read(&console->input, buf + count, len - count);
 }
 
 void
@@ -39,7 +103,7 @@ console_schedule_flush()
 void
 console_view_up()
 {
-    struct fifo_buffer* buffer = &lx_console.buffer;
+    struct fifo_buf* buffer = &lx_console.output;
     mutex_lock(&buffer->lock);
     size_t p = lx_console.erd_pos - 2;
     while (p < lx_console.erd_pos && p != buffer->wr_pos &&
@@ -61,9 +125,9 @@ size_t
 __find_next_line(size_t start)
 {
     size_t p = start;
-    while (p != lx_console.buffer.wr_pos &&
-           ((char*)lx_console.buffer.data)[p] != '\n') {
-        p = (p + 1) % lx_console.buffer.size;
+    while (p != lx_console.output.wr_pos &&
+           ((char*)lx_console.output.data)[p] != '\n') {
+        p = (p + 1) % lx_console.output.size;
     }
     return p + 1;
 }
@@ -71,7 +135,7 @@ __find_next_line(size_t start)
 void
 console_view_down()
 {
-    struct fifo_buffer* buffer = &lx_console.buffer;
+    struct fifo_buf* buffer = &lx_console.output;
     mutex_lock(&buffer->lock);
 
     lx_console.erd_pos = __find_next_line(lx_console.erd_pos);
@@ -82,52 +146,59 @@ console_view_down()
 void
 console_flush()
 {
-    if (mutex_on_hold(&lx_console.buffer.lock)) {
+    if (mutex_on_hold(&lx_console.output.lock)) {
         return;
     }
-    if (!(lx_console.buffer.flags & FIFO_DIRTY)) {
+    if (!(lx_console.output.flags & FIFO_DIRTY)) {
         return;
     }
 
-    tty_flush_buffer(lx_console.buffer.data,
+    tty_flush_buffer(lx_console.output.data,
                      lx_console.erd_pos,
-                     lx_console.buffer.wr_pos,
-                     lx_console.buffer.size);
-    lx_console.buffer.flags &= ~FIFO_DIRTY;
+                     lx_console.output.wr_pos,
+                     lx_console.output.size);
+    lx_console.output.flags &= ~FIFO_DIRTY;
 }
 
 void
 console_write(struct console* console, uint8_t* data, size_t size)
 {
-    mutex_lock(&console->buffer.lock);
-    uint8_t* buffer = console->buffer.data;
-    uintptr_t ptr = console->buffer.wr_pos;
-    uintptr_t rd_ptr = console->buffer.rd_pos;
+    mutex_lock(&console->output.lock);
+    uint8_t* buffer = console->output.data;
+    uintptr_t ptr = console->output.wr_pos;
+    uintptr_t rd_ptr = console->output.rd_pos;
 
     char c;
     int lines = 0;
+    int j = 0;
     for (size_t i = 0; i < size; i++) {
         c = data[i];
-        buffer[(ptr + i) % console->buffer.size] = c;
+        if (!c) {
+            continue;
+        }
+        buffer[(ptr + j) % console->output.size] = c;
         lines += (c == '\n');
+        j++;
     }
 
-    uintptr_t new_ptr = (ptr + size) % console->buffer.size;
-    console->buffer.wr_pos = new_ptr;
+    size = j;
+
+    uintptr_t new_ptr = (ptr + size) % console->output.size;
+    console->output.wr_pos = new_ptr;
 
     if (console->lines > TTY_HEIGHT && lines > 0) {
-        console->buffer.rd_pos =
-          __find_next_line((size + rd_ptr) % console->buffer.size);
+        console->output.rd_pos =
+          __find_next_line((size + rd_ptr) % console->output.size);
     }
 
     if (new_ptr < ptr + size && new_ptr > rd_ptr) {
-        console->buffer.rd_pos = new_ptr;
+        console->output.rd_pos = new_ptr;
     }
 
     console->lines += lines;
-    console->erd_pos = console->buffer.rd_pos;
-    console->buffer.flags |= FIFO_DIRTY;
-    mutex_unlock(&console->buffer.lock);
+    console->erd_pos = console->output.rd_pos;
+    console->output.flags |= FIFO_DIRTY;
+    mutex_unlock(&console->output.lock);
 }
 
 void
index 7e3142b1fbe6579b3d5dc2351cba4e1dae074c87..a64b3ea6acf40f02098c3536076325e3dcfe120d 100644 (file)
@@ -76,10 +76,10 @@ __init_pile(struct cake_pile* pile,
                                   (piece_size + sizeof(piece_index_t)),
                                 .pg_per_cake = pg_per_cake };
 
-    unsigned int overhead_size =
-      sizeof(struct cake_s) + pile->pieces_per_cake * sizeof(piece_index_t);
+    unsigned int free_list_size = pile->pieces_per_cake * sizeof(piece_index_t);
 
-    pile->offset = ROUNDUP(overhead_size, offset);
+    pile->offset = ROUNDUP(sizeof(struct cake_s) + free_list_size, offset);
+    pile->pieces_per_cake -= ICEIL((pile->offset - free_list_size), piece_size);
 
     strncpy(&pile->pile_name, name, PILE_NAME_MAXLEN);
 
@@ -120,7 +120,6 @@ cake_grab(struct cake_pile* pile)
         pos = list_entry(pile->free.next, typeof(*pos), cakes);
     }
 
-found:
     piece_index_t found_index = pos->next_free;
     pos->next_free = pos->free_list[found_index];
     pos->used_pieces++;
@@ -140,7 +139,7 @@ found:
 int
 cake_release(struct cake_pile* pile, void* area)
 {
-    piece_index_t area_index;
+    piece_index_t piece_index;
     struct cake_s *pos, *n;
     struct llist_header* hdrs[2] = { &pile->full, &pile->partial };
 
@@ -150,9 +149,9 @@ cake_release(struct cake_pile* pile, void* area)
             if (pos->first_piece > area) {
                 continue;
             }
-            area_index =
+            piece_index =
               (uintptr_t)(area - pos->first_piece) / pile->piece_size;
-            if (area_index < pile->pieces_per_cake) {
+            if (piece_index < pile->pieces_per_cake) {
                 goto found;
             }
         }
@@ -161,8 +160,8 @@ cake_release(struct cake_pile* pile, void* area)
     return 0;
 
 found:
-    pos->free_list[area_index] = pos->next_free;
-    pos->next_free = area_index;
+    pos->free_list[piece_index] = pos->next_free;
+    pos->next_free = piece_index;
     pos->used_pieces--;
     pile->alloced_pieces--;
 
index 1f706dc362140c5203a36b9371b04571b8f492b1..920c35bbb86a3ea26cf04c247bce0b317128c5e1 100644 (file)
@@ -1,5 +1,5 @@
-#include <lunaix/mm/kalloc.h>
 #include <lunaix/mm/region.h>
+#include <lunaix/mm/valloc.h>
 
 void
 region_add(struct mm_region* regions,
@@ -7,7 +7,7 @@ region_add(struct mm_region* regions,
            unsigned long end,
            unsigned int attr)
 {
-    struct mm_region* region = lxmalloc(sizeof(struct mm_region));
+    struct mm_region* region = valloc(sizeof(struct mm_region));
 
     *region = (struct mm_region){ .attr = attr, .end = end, .start = start };
 
index 631f39ee6f0ccd8070f8882bce4a40193588c1f3..04379e1dcf047ea3f6bf1e63a2c658ef7aba4487 100644 (file)
@@ -1,59 +1,61 @@
 #include <klibc/string.h>
 #include <lunaix/mm/cake.h>
 #include <lunaix/mm/valloc.h>
+#include <lunaix/spike.h>
 
-#define MAX_CLASS 6
+#define CLASS_LEN(class) (sizeof(class) / sizeof(class[0]))
 
-static char piles_names[MAX_CLASS][PILE_NAME_MAXLEN] = {
-    "valloc_16",  "valloc_32",  "valloc_64",
-    "valloc_128", "valloc_256", "valloc_512"
+static char piles_names[][PILE_NAME_MAXLEN] = {
+    "valloc_8",   "valloc_16",  "valloc_32",  "valloc_64",
+    "valloc_128", "valloc_256", "valloc_512", "valloc_1k",
+    "valloc_2k",  "valloc_4k",  "valloc_8k"
 };
 
-static char piles_names_dma[MAX_CLASS][PILE_NAME_MAXLEN] = {
+static char piles_names_dma[][PILE_NAME_MAXLEN] = {
     "valloc_dma_128", "valloc_dma_256", "valloc_dma_512",
     "valloc_dma_1k",  "valloc_dma_2k",  "valloc_dma_4k"
 };
 
-static struct cake_pile* piles[MAX_CLASS];
-static struct cake_pile* piles_dma[MAX_CLASS];
+static struct cake_pile* piles[CLASS_LEN(piles_names)];
+static struct cake_pile* piles_dma[CLASS_LEN(piles_names_dma)];
 
 void
 valloc_init()
 {
-    for (size_t i = 0; i < MAX_CLASS; i++) {
-        int size = 1 << (i + 4);
-        piles[i] = cake_new_pile(&piles_names[i], size, 1, 0);
+    for (size_t i = 0; i < CLASS_LEN(piles_names); i++) {
+        int size = 1 << (i + 3);
+        piles[i] = cake_new_pile(&piles_names[i], size, size > 1024 ? 8 : 1, 0);
     }
 
     // DMA 内存保证128字节对齐
-    for (size_t i = 0; i < MAX_CLASS; i++) {
+    for (size_t i = 0; i < CLASS_LEN(piles_names_dma); i++) {
         int size = 1 << (i + 7);
         piles_dma[i] = cake_new_pile(
-          &piles_names_dma[i], size, size > 1024 ? 8 : 1, PILE_CACHELINE);
+          &piles_names_dma[i], size, size > 1024 ? 4 : 1, PILE_CACHELINE);
     }
 }
 
 void*
-__valloc(unsigned int size, struct cake_pile** segregate_list)
+__valloc(unsigned int size,
+         struct cake_pile** segregate_list,
+         size_t len,
+         size_t boffset)
 {
-    size_t i = 0;
-    for (; i < MAX_CLASS; i++) {
-        if (segregate_list[i]->piece_size >= size) {
-            goto found_class;
-        }
-    }
+    size_t i = ILOG2(size);
+    i += (size - (1 << i) != 0);
+    i -= boffset;
 
-    return NULL;
+    if (i >= len)
+        return NULL;
 
-found_class:
     return cake_grab(segregate_list[i]);
 }
 
 void
-__vfree(void* ptr, struct cake_pile** segregate_list)
+__vfree(void* ptr, struct cake_pile** segregate_list, size_t len)
 {
     size_t i = 0;
-    for (; i < MAX_CLASS; i++) {
+    for (; i < len; i++) {
         if (cake_release(segregate_list[i], ptr)) {
             return;
         }
@@ -63,33 +65,46 @@ __vfree(void* ptr, struct cake_pile** segregate_list)
 void*
 valloc(unsigned int size)
 {
-    return __valloc(size, &piles);
+    return __valloc(size, &piles, CLASS_LEN(piles_names), 3);
 }
 
 void*
-vcalloc(unsigned int size)
+vzalloc(unsigned int size)
 {
-    void* ptr = __valloc(size, &piles);
+    void* ptr = __valloc(size, &piles, CLASS_LEN(piles_names), 3);
     memset(ptr, 0, size);
     return ptr;
 }
 
+void*
+vcalloc(unsigned int size, unsigned int count)
+{
+    unsigned int alloc_size;
+    if (__builtin_umul_overflow(size, count, &alloc_size)) {
+        return 0;
+    }
+
+    void* ptr = __valloc(alloc_size, &piles, CLASS_LEN(piles_names), 3);
+    memset(ptr, 0, alloc_size);
+    return ptr;
+}
+
 void
 vfree(void* ptr)
 {
-    __vfree(ptr, &piles);
+    __vfree(ptr, &piles, CLASS_LEN(piles_names));
 }
 
 void*
 valloc_dma(unsigned int size)
 {
-    return __valloc(size, &piles_dma);
+    return __valloc(size, &piles_dma, CLASS_LEN(piles_names_dma), 7);
 }
 
 void*
-vcalloc_dma(unsigned int size)
+vzalloc_dma(unsigned int size)
 {
-    void* ptr = __valloc(size, &piles_dma);
+    void* ptr = __valloc(size, &piles_dma, CLASS_LEN(piles_names_dma), 7);
     memset(ptr, 0, size);
     return ptr;
 }
@@ -97,5 +112,5 @@ vcalloc_dma(unsigned int size)
 void
 vfree_dma(void* ptr)
 {
-    __vfree(ptr, &piles_dma);
+    __vfree(ptr, &piles_dma, CLASS_LEN(piles_names_dma));
 }
\ No newline at end of file
index 5df524d532986fd2111521d0a6c6c378ed1f010c..deb18d30a05577333e824f3c7c8d7ded5e093b55 100644 (file)
@@ -27,7 +27,7 @@ vmm_vmap(uintptr_t paddr, size_t size, pt_attr attr)
         } else {
             x86_page_table* ptd = (x86_page_table*)(L2_VADDR(l1inx));
             size_t i = L2_INDEX(current_addr);
-            for (; i < 1024 && examed_size < size; i++) {
+            for (; i < PG_MAX_ENTRIES && examed_size < size; i++) {
                 if (!ptd->entry[i]) {
                     examed_size += PG_SIZE;
                 } else if (examed_size) {
index 6d27b10847c8f28802548aa77a806f3a395a5205..6905b1eb059fc8995aeaf3c2cbb5c13a007967b8 100644 (file)
@@ -427,11 +427,9 @@ kbd_recv_key(struct kdb_keyinfo_pkt* key_event)
     if (!key_buf.buffered_len) {
         return 0;
     }
-    mutex_lock(&key_buf.mutex);
-
-    struct kdb_keyinfo_pkt* pkt_current = &key_buf.buffer[key_buf.read_ptr];
 
-    *key_event = *pkt_current;
+    mutex_lock(&key_buf.mutex);
+    *key_event = key_buf.buffer[key_buf.read_ptr];
     key_buf.buffered_len--;
     key_buf.read_ptr = (key_buf.read_ptr + 1) % PS2_KBD_RECV_BUFFER_SIZE;
 
index 759db2c0d19906bdffd2a34e8639615659e50bdb..5fac5f86f609e3efc078701234451291fe7ca454 100644 (file)
@@ -1,5 +1,9 @@
 #include <arch/x86/boot/multiboot.h>
+#include <lunaix/block.h>
 #include <lunaix/common.h>
+#include <lunaix/fctrl.h>
+#include <lunaix/fs.h>
+#include <lunaix/fs/twifs.h>
 #include <lunaix/lunistd.h>
 #include <lunaix/lxconsole.h>
 #include <lunaix/mm/cake.h>
@@ -38,8 +42,10 @@ unlock_reserved_memory();
 void
 __do_reserved_memory(int unlock);
 
-//#define USE_DEMO
-#define DEMO_SIGNAL
+#define USE_DEMO
+// #define DEMO_SIGNAL
+// #define DEMO_READDIR
+#define DEMO_IOTEST
 
 extern void
 _pconsole_main();
@@ -50,9 +56,21 @@ _signal_demo_main();
 extern void
 _lxinit_main();
 
+extern void
+_readdir_main();
+
+extern void
+_iotest_main();
+
 void __USER__
 __proc0_usr()
 {
+    // 打开tty设备(控制台),作为标准输入输出。
+    //  tty设备属于序列设备(Sequential Device),该类型设备的上层读写
+    //  无须经过Lunaix的缓存层,而是直接下发到底层驱动。(不受FO_DIRECT的影响)
+    int stdout = open("/dev/tty", 0);
+    int stdin = dup2(stdout, 1);
+
     pid_t p;
     if (!fork()) {
         _pconsole_main();
@@ -63,6 +81,10 @@ __proc0_usr()
         _exit(0);
 #elif defined DEMO_SIGNAL
         _signal_demo_main();
+#elif defined DEMO_READDIR
+        _readdir_main();
+#elif defined DEMO_IOTEST
+        _iotest_main();
 #else
         _lxinit_main();
 #endif
@@ -111,51 +133,13 @@ extern uint8_t __kernel_end;              /* link/linker.ld */
 extern uint8_t __init_hhk_end;            /* link/linker.ld */
 extern multiboot_info_t* _k_init_mb_info; /* k_init.c */
 
-char test_sequence[] = "Once upon a time, in a magical land of Equestria. "
-                       "There were two regal sisters who ruled together "
-                       "and created harmony for all the land.";
-
-void
-__test_disk_io()
-{
-    struct hba_port* port = ahci_get_port(0);
-    char* buffer = vcalloc_dma(port->device->block_size);
-    strcpy(buffer, test_sequence);
-    kprintf("WRITE: %s\n", buffer);
-    int result;
-
-    // 写入第一扇区 (LBA=0)
-    result =
-      port->device->ops.write_buffer(port, 0, buffer, port->device->block_size);
-    if (!result) {
-        kprintf(KWARN "fail to write: %x\n", port->device->last_error);
-    }
-
-    memset(buffer, 0, port->device->block_size);
-
-    // 读出我们刚刚写的内容!
-    result =
-      port->device->ops.read_buffer(port, 0, buffer, port->device->block_size);
-    kprintf(KDEBUG "%x, %x\n", port->regs[HBA_RPxIS], port->regs[HBA_RPxTFD]);
-    if (!result) {
-        kprintf(KWARN "fail to read: %x\n", port->device->last_error);
-    } else {
-        kprint_hex(buffer, 256);
-    }
-
-    vfree_dma(buffer);
-}
-
 void
 init_platform()
 {
     // 锁定所有系统预留页(内存映射IO,ACPI之类的),并且进行1:1映射
     lock_reserved_memory();
 
-    cake_init();
-
     assert_msg(kalloc_init(), "Fail to initialize heap");
-    valloc_init();
 
     acpi_init(_k_init_mb_info);
     apic_init();
@@ -164,12 +148,10 @@ init_platform()
     clock_init();
     ps2_kbd_init();
     pci_init();
+    block_init();
     ahci_init();
-    ahci_list_device();
-
-    __test_disk_io();
-
-    cake_stats();
+    // ahci_list_device();
+    // cake_stats();
 
     syscall_install();
 
index a783efe13987a6a2b1c46fd932d67b863314b594..086a5e3105a184ca3ccf784f3f8fb7cba46445f9 100644 (file)
@@ -3,6 +3,7 @@
 #include <lunaix/common.h>
 #include <lunaix/mm/pmm.h>
 #include <lunaix/mm/region.h>
+#include <lunaix/mm/valloc.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/process.h>
 #include <lunaix/spike.h>
@@ -114,7 +115,7 @@ __DEFINE_LXSYSCALL2(int, setpgid, pid_t, pid, pid_t, pgid)
     struct proc_info* proc = pid ? get_process(pid) : __current;
 
     if (!proc) {
-        __current->k_status = LXINVL;
+        __current->k_status = EINVAL;
         return -1;
     }
 
@@ -123,7 +124,7 @@ __DEFINE_LXSYSCALL2(int, setpgid, pid_t, pid, pid_t, pgid)
     struct proc_info* gruppenfuhrer = get_process(pgid);
 
     if (!gruppenfuhrer || proc->pgid == proc->pid) {
-        __current->k_status = LXINVL;
+        __current->k_status = EINVAL;
         return -1;
     }
 
@@ -176,6 +177,17 @@ __mark_region(uintptr_t start_vpn, uintptr_t end_vpn, int attr)
     }
 }
 
+void
+__copy_fdtable(struct proc_info* pcb)
+{
+    for (size_t i = 0; i < VFS_MAX_FD; i++) {
+        struct v_fd* fd = __current->fdtable->fds[i];
+        if (!fd)
+            continue;
+        vfs_dup_fd(fd, &pcb->fdtable->fds[i]);
+    }
+}
+
 pid_t
 dup_proc()
 {
@@ -184,6 +196,7 @@ dup_proc()
     pcb->intr_ctx = __current->intr_ctx;
     pcb->parent = __current;
 
+    __copy_fdtable(pcb);
     region_copy(&__current->mm.regions, &pcb->mm.regions);
 
     setup_proc_mem(pcb, PD_REFERENCED);
index 8e089d64b976be61ddf22fb77259caf9dea54f5b..be9952519fe282993a29154123c89a90f8d7b249 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <lunaix/mm/kalloc.h>
 #include <lunaix/mm/pmm.h>
+#include <lunaix/mm/valloc.h>
 #include <lunaix/mm/vmm.h>
 #include <lunaix/process.h>
 #include <lunaix/sched.h>
@@ -202,6 +203,11 @@ __DEFINE_LXSYSCALL3(pid_t, waitpid, pid_t, pid, int*, status, int, options)
     return _wait(pid, status, options);
 }
 
+__DEFINE_LXSYSCALL(int, geterrno)
+{
+    return __current->k_status;
+}
+
 pid_t
 _wait(pid_t wpid, int* status, int options)
 {
@@ -267,6 +273,7 @@ alloc_process()
     proc->pid = i;
     proc->created = clock_systime();
     proc->pgid = proc->pid;
+    proc->fdtable = vzalloc(sizeof(struct v_fdtable));
 
     llist_init_head(&proc->mm.regions);
     llist_init_head(&proc->children);
@@ -282,7 +289,7 @@ commit_process(struct proc_info* process)
     assert(process == &sched_ctx._procs[process->pid]);
 
     if (process->state != PS_CREATED) {
-        __current->k_status = LXINVL;
+        __current->k_status = EINVAL;
         return;
     }
 
@@ -305,13 +312,21 @@ destroy_process(pid_t pid)
 {
     int index = pid;
     if (index <= 0 || index > sched_ctx.ptable_len) {
-        __current->k_status = LXINVLDPID;
+        __current->k_status = EINVAL;
         return;
     }
     struct proc_info* proc = &sched_ctx._procs[index];
     proc->state = PS_DESTROY;
     llist_delete(&proc->siblings);
 
+    for (size_t i = 0; i < VFS_MAX_FD; i++) {
+        struct v_fd* fd = proc->fdtable->fds[i];
+        if (fd)
+            vfs_close(fd->file);
+    }
+
+    vfree(proc->fdtable);
+
     struct mm_region *pos, *n;
     llist_for_each(pos, n, &proc->mm.regions.head, head)
     {
index be59c18912240148c475d35c6ee7dcdc1728f49a..200303d5720e340db76a29f5c191e64a6cbd7801 100644 (file)
@@ -12,9 +12,7 @@ _pconsole_main()
             continue;
         }
         if ((keyevent.state & KBD_KEY_FPRESSED)) {
-            if ((keyevent.keycode & 0xff00) <= KEYPAD) {
-                console_write_char((char)(keyevent.keycode & 0x00ff));
-            } else if (keyevent.keycode == KEY_UP) {
+            if (keyevent.keycode == KEY_UP) {
                 console_view_up();
             } else if (keyevent.keycode == KEY_DOWN) {
                 console_view_down();
index cb47e8dacfc164548954bde39412c6da75eadf6f..db1d4ff8ac89817f550905763fe3161196d55a4c 100644 (file)
@@ -99,7 +99,7 @@ int
 signal_send(pid_t pid, int signum)
 {
     if (signum < 0 || signum >= _SIG_NUM) {
-        __current->k_status = LXINVL;
+        __current->k_status = EINVAL;
         return -1;
     }
 
@@ -116,7 +116,7 @@ signal_send(pid_t pid, int signum)
     } else {
         // TODO: send to all process.
         //  But I don't want to support it yet.
-        __current->k_status = LXINVL;
+        __current->k_status = EINVAL;
         return -1;
     }
 
@@ -130,7 +130,7 @@ send_grp:
 
 send_single:
     if (PROC_TERMINATED(proc->state)) {
-        __current->k_status = LXINVL;
+        __current->k_status = EINVAL;
         return -1;
     }
     __SIGSET(proc->sig_pending, signum);
index e862f79f090362f3b6303fd0dc98c0912c9098cb..15a6a32aaf5fbf67527457578d30ebf52f46f18c 100644 (file)
@@ -1,33 +1,35 @@
-#include <lunaix/clock.h>
-#include <lunaix/timer.h>
 #include <hal/rtc.h>
+#include <lunaix/clock.h>
 #include <lunaix/spike.h>
+#include <lunaix/timer.h>
 
 static volatile time_t sys_time;
 
-void clock_systime_counter(void* arg);
+void
+clock_systime_counter(void* arg);
 
 void
-clock_init() {
+clock_init()
+{
     if (!timer_context()) {
         panick("Systimer not initialized");
     }
-    
+
     // 系统计时器每毫秒累加。
     timer_run_ms(1, clock_systime_counter, NULL, TIMER_MODE_PERIODIC);
 }
 
-void clock_systime_counter(void* arg) {
+void
+clock_systime_counter(void* arg)
+{
     sys_time++;
 }
 
 int
-clock_datatime_eq(datetime_t* a, datetime_t* b) {
-    return a->year == b->year &&
-           a->month == b->month &&
-           a->day == b->day &&
-           a->weekday == b->weekday &&
-           a->minute == b->minute &&
+clock_datatime_eq(datetime_t* a, datetime_t* b)
+{
+    return a->year == b->year && a->month == b->month && a->day == b->day &&
+           a->weekday == b->weekday && a->minute == b->minute &&
            a->second == b->second;
 }
 
@@ -35,10 +37,10 @@ void
 clock_walltime(datetime_t* datetime)
 {
     datetime_t current;
-    
-    do
-    {
-        while (rtc_read_reg(RTC_REG_A) & 0x80);
+
+    do {
+        while (rtc_read_reg(RTC_REG_A) & 0x80)
+            ;
         memcpy(&current, datetime, sizeof(datetime_t));
 
         datetime->year = rtc_read_reg(RTC_REG_YRS);
@@ -62,7 +64,6 @@ clock_walltime(datetime_t* datetime)
         datetime->second = bcd2dec(datetime->second);
     }
 
-
     // To 24 hour format
     if (!RTC_24HRS_ENCODED(regbv) && (datetime->hour >> 7)) {
         datetime->hour = (12 + datetime->hour & 0x80);
@@ -71,8 +72,16 @@ clock_walltime(datetime_t* datetime)
     datetime->year += RTC_CURRENT_CENTRY * 100;
 }
 
+time_t
+clock_unixtime()
+{
+    datetime_t dt;
+    clock_walltime(&dt);
+    return clock_tounixtime(&dt);
+}
 
-time_t 
-clock_systime() {
+time_t
+clock_systime()
+{
     return sys_time;
 }
\ No newline at end of file
index b9d333b1273856d202d2db4a0625e6cb9948654e..f479f581a34f6849593824bdb5dc1d37f4bcb59e 100644 (file)
@@ -13,7 +13,8 @@
 #include <hal/apic.h>
 #include <hal/rtc.h>
 
-#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/cake.h>
+#include <lunaix/mm/valloc.h>
 #include <lunaix/sched.h>
 #include <lunaix/spike.h>
 #include <lunaix/syslog.h>
@@ -42,18 +43,20 @@ static volatile uint8_t apic_timer_done = 0;
 static volatile uint32_t sched_ticks = 0;
 static volatile uint32_t sched_ticks_counter = 0;
 
+static struct cake_pile* timer_pile;
+
 #define APIC_CALIBRATION_CONST 0x100000
 
 void
 timer_init_context()
 {
+    timer_pile = cake_new_pile("timer", sizeof(struct lx_timer), 1, 0);
     timer_ctx =
-      (struct lx_timer_context*)lxmalloc(sizeof(struct lx_timer_context));
+      (struct lx_timer_context*)valloc(sizeof(struct lx_timer_context));
 
     assert_msg(timer_ctx, "Fail to initialize timer contex");
 
-    timer_ctx->active_timers =
-      (struct lx_timer*)lxmalloc(sizeof(struct lx_timer));
+    timer_ctx->active_timers = (struct lx_timer*)cake_grab(timer_pile);
     llist_init_head(timer_ctx->active_timers);
 }
 
@@ -164,8 +167,7 @@ timer_run_ms(uint32_t millisecond,
 struct lx_timer*
 timer_run(ticks_t ticks, void (*callback)(void*), void* payload, uint8_t flags)
 {
-    struct lx_timer* timer =
-      (struct lx_timer*)lxmalloc(sizeof(struct lx_timer));
+    struct lx_timer* timer = (struct lx_timer*)cake_grab(timer_pile);
 
     if (!timer)
         return NULL;
@@ -199,7 +201,7 @@ timer_update(const isr_param* param)
             pos->counter = pos->deadline;
         } else {
             llist_delete(&pos->link);
-            lxfree(pos);
+            cake_release(timer_pile, pos);
         }
     }
 
diff --git a/lunaix-os/libs/crc.c b/lunaix-os/libs/crc.c
new file mode 100644 (file)
index 0000000..06ebbac
--- /dev/null
@@ -0,0 +1,68 @@
+#include <lib/crc.h>
+
+// crc32 lookup table. (https://web.mit.edu/freebsd/head/sys/libkern/crc32.c)
+const unsigned int crc32_tab[] = {
+    0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+    0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+    0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+    0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+    0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+    0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+    0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+    0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+    0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+    0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+    0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+    0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+    0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+    0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+    0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+    0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+    0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+    0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+    0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+    0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+    0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+    0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+    0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+    0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+    0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+    0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+    0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+    0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+    0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+    0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+    0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+    0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+/**
+ * @brief CRC32 checksum
+ *  ref: https://en.wikipedia.org/wiki/Cyclic_redundancy_check#CRC-32_algorithm
+ * @param data
+ * @param size
+ * @return unsigned int
+ */
+unsigned int
+crc32b(unsigned char* data, unsigned int size)
+{
+    unsigned int crc = (unsigned int)-1, i = 0;
+
+    while (i < size) {
+        crc = (crc >> 8) ^ crc32_tab[(crc ^ data[i]) & 0xff];
+        i = i + 1;
+    }
+
+    return ~crc;
+}
\ No newline at end of file
diff --git a/lunaix-os/libs/hash.c b/lunaix-os/libs/hash.c
new file mode 100644 (file)
index 0000000..c1580ed
--- /dev/null
@@ -0,0 +1,24 @@
+#include <lib/hash.h>
+
+/**
+ * @brief Simple string hash function
+ *
+ * ref: https://stackoverflow.com/a/7666577
+ *
+ * @param str
+ * @return unsigned int
+ */
+uint32_t
+strhash_32(unsigned char* str, uint32_t truncate_to)
+{
+    if (!str)
+        return 0;
+
+    uint32_t hash = 5381;
+    int c;
+
+    while ((c = *str++))
+        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+    return hash >> (HASH_SIZE_BITS - truncate_to);
+}
\ No newline at end of file
index 460b206e08a1a131e1f76d0b4324c8fa0fda0625..d35706883ea8facc7ade8668a4a659859fb460ec 100644 (file)
@@ -8,20 +8,20 @@
 
 static const char flag_chars[] = "#0- +";
 
-#define FLAG_ALT                (1<<0)
-#define FLAG_ZERO               (1<<1)
-#define FLAG_LEFTJUSTIFY        (1<<2)
-#define FLAG_SPACEPOSITIVE      (1<<3)
-#define FLAG_PLUSPOSITIVE       (1<<4)
-#define FLAG_NUMERIC            (1<<5)
-#define FLAG_SIGNED             (1<<6)
-#define FLAG_NEGATIVE           (1<<7)
-#define FLAG_ALT2               (1<<8)
-#define FLAG_CAPS               (1<<9)
-
-
-// FIXME: use something like IO_FILE to abstract this into a more flexible, stream based, vprintf
-void
+#define FLAG_ALT (1 << 0)
+#define FLAG_ZERO (1 << 1)
+#define FLAG_LEFTJUSTIFY (1 << 2)
+#define FLAG_SPACEPOSITIVE (1 << 3)
+#define FLAG_PLUSPOSITIVE (1 << 4)
+#define FLAG_NUMERIC (1 << 5)
+#define FLAG_SIGNED (1 << 6)
+#define FLAG_NEGATIVE (1 << 7)
+#define FLAG_ALT2 (1 << 8)
+#define FLAG_CAPS (1 << 9)
+
+// FIXME: use something like IO_FILE to abstract this into a more flexible,
+// stream based, vprintf
+size_t
 __sprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs)
 {
     // This sprintf just a random implementation I found it on Internet . lol.
@@ -33,7 +33,7 @@ __sprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs)
         if (max_len && ptr >= max_len - 1) {
             break;
         }
-        
+
         if (*fmt != '%') {
             buffer[ptr++] = *fmt;
             continue;
@@ -53,7 +53,7 @@ __sprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs)
         // process width
         int width = -1;
         if (*fmt >= '1' && *fmt <= '9') {
-            for (width = 0; *fmt >= '0' && *fmt <= '9'; ) {
+            for (width = 0; *fmt >= '0' && *fmt <= '9';) {
                 width = 10 * width + *fmt++ - '0';
             }
         } else if (*fmt == '*') {
@@ -66,7 +66,7 @@ __sprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs)
         if (*fmt == '.') {
             ++fmt;
             if (*fmt >= '0' && *fmt <= '9') {
-                for (precision = 0; *fmt >= '0' && *fmt <= '9'; ) {
+                for (precision = 0; *fmt >= '0' && *fmt <= '9';) {
                     precision = 10 * precision + *fmt++ - '0';
                 }
             } else if (*fmt == '*') {
@@ -85,60 +85,60 @@ __sprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs)
         char* data = "";
     again:
         switch (*fmt) {
-        case 'l':
-        case 'z':
-            length = 1;
-            ++fmt;
-            goto again;
-        case 'd':
-        case 'i': {
-            long x = length ? va_arg(vargs, long) : va_arg(vargs, int);
-            int negative = x < 0 ? FLAG_NEGATIVE : 0;
-            num = negative ? -x : x;
-            flags |= FLAG_NUMERIC | FLAG_SIGNED | negative;
-            break;
-        }
-        case 'u':
-        format_unsigned:
-            num = length ? va_arg(vargs, unsigned long) : va_arg(vargs, unsigned);
-            flags |= FLAG_NUMERIC;
-            break;
-        case 'x':
-            base = 16;
-            goto format_unsigned;
-        case 'X':
-            flags = flags | FLAG_CAPS;
-            base = 16;
-            goto format_unsigned;
-        case 'p':
-            num = (uintptr_t) va_arg(vargs, void*);
-            base = 16;
-            flags |= FLAG_ALT | FLAG_ALT2 | FLAG_NUMERIC;
-            break;
-        case 's':
-            data = va_arg(vargs, char*);
-            break;
-        case 'c':
-            data = numbuf;
-            numbuf[0] = va_arg(vargs, int);
-            numbuf[1] = '\0';
-            break;
-        default:
-            data = numbuf;
-            numbuf[0] = (*fmt ? *fmt : '%');
-            numbuf[1] = '\0';
-            if (!*fmt) {
-                fmt--;
+            case 'l':
+            case 'z':
+                length = 1;
+                ++fmt;
+                goto again;
+            case 'd':
+            case 'i': {
+                long x = length ? va_arg(vargs, long) : va_arg(vargs, int);
+                int negative = x < 0 ? FLAG_NEGATIVE : 0;
+                num = negative ? -x : x;
+                flags |= FLAG_NUMERIC | FLAG_SIGNED | negative;
+                break;
             }
-            break;
+            case 'u':
+            format_unsigned:
+                num = length ? va_arg(vargs, unsigned long)
+                             : va_arg(vargs, unsigned);
+                flags |= FLAG_NUMERIC;
+                break;
+            case 'x':
+                base = 16;
+                goto format_unsigned;
+            case 'X':
+                flags = flags | FLAG_CAPS;
+                base = 16;
+                goto format_unsigned;
+            case 'p':
+                num = (uintptr_t)va_arg(vargs, void*);
+                base = 16;
+                flags |= FLAG_ALT | FLAG_ALT2 | FLAG_NUMERIC;
+                break;
+            case 's':
+                data = va_arg(vargs, char*);
+                break;
+            case 'c':
+                data = numbuf;
+                numbuf[0] = va_arg(vargs, int);
+                numbuf[1] = '\0';
+                break;
+            default:
+                data = numbuf;
+                numbuf[0] = (*fmt ? *fmt : '%');
+                numbuf[1] = '\0';
+                if (!*fmt) {
+                    fmt--;
+                }
+                break;
         }
 
         if (flags & FLAG_NUMERIC) {
             data = itoa(num, numbuf, base);
             int i = 0;
             char c;
-            while ((flags & FLAG_CAPS) && (c = data[i]))
-            {
+            while ((flags & FLAG_CAPS) && (c = data[i])) {
                 data[i] = c & ~((c & 0x40) >> 1);
                 i++;
             }
@@ -153,9 +153,9 @@ __sprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs)
             } else if (flags & FLAG_SPACEPOSITIVE) {
                 prefix = " ";
             }
-        } else if ((flags & FLAG_NUMERIC) && (flags & FLAG_ALT)
-                   && (base == 16 || base == -16)
-                   && (num || (flags & FLAG_ALT2))) {
+        } else if ((flags & FLAG_NUMERIC) && (flags & FLAG_ALT) &&
+                   (base == 16 || base == -16) &&
+                   (num || (flags & FLAG_ALT2))) {
             prefix = "0x";
         }
 
@@ -168,9 +168,9 @@ __sprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs)
         int zeros;
         if ((flags & FLAG_NUMERIC) && precision >= 0) {
             zeros = precision > len ? precision - len : 0;
-        } else if ((flags & FLAG_NUMERIC) && (flags & FLAG_ZERO)
-                   && !(flags & FLAG_LEFTJUSTIFY)
-                   && len + (int) strlen(prefix) < width) {
+        } else if ((flags & FLAG_NUMERIC) && (flags & FLAG_ZERO) &&
+                   !(flags & FLAG_LEFTJUSTIFY) &&
+                   len + (int)strlen(prefix) < width) {
             zeros = width - len - strlen(prefix);
         } else {
             zeros = 0;
@@ -193,22 +193,26 @@ __sprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs)
         }
     }
     buffer[ptr++] = '\0';
+
+    return ptr;
 }
 
-void
+size_t
 sprintf(char* buffer, char* fmt, ...)
 {
     va_list args;
     va_start(args, fmt);
-    __sprintf_internal(buffer, fmt, 0, args);
+    size_t len = __sprintf_internal(buffer, fmt, 0, args);
     va_end(args);
+    return len;
 }
 
-void
+size_t
 snprintf(char* buffer, size_t n, char* fmt, ...)
 {
     va_list args;
     va_start(args, fmt);
-    __sprintf_internal(buffer, fmt, n, args);
+    size_t len = __sprintf_internal(buffer, fmt, n, args);
     va_end(args);
+    return len;
 }
\ No newline at end of file
diff --git a/lunaix-os/libs/klibc/string/strcmp.c b/lunaix-os/libs/klibc/string/strcmp.c
new file mode 100644 (file)
index 0000000..736bb91
--- /dev/null
@@ -0,0 +1,14 @@
+#include <klibc/string.h>
+
+int
+streq(const char* a, const char* b)
+{
+    while (*a == *b) {
+        if (!(*a)) {
+            return 1;
+        }
+        a++;
+        b++;
+    }
+    return 0;
+}
\ No newline at end of file