From: Minep Date: Sun, 14 Aug 2022 00:19:55 +0000 (+0100) Subject: Merge branch 'vfs-dev' X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/commitdiff_plain/bc34fd00d2e81fbc890bb2060ed6693454a230bf?hp=0172e34a3d2f50358f1bd6ebbbb79555afb082bc Merge branch 'vfs-dev' --- diff --git a/.gitignore b/.gitignore index 7aaf609..cd7d5b3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ **/.~lock* workspace/ **.odp - +drafts/ diff --git a/README.md b/README.md index 38a062d..2c0bcb3 100644 --- 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) ## 目录结构 @@ -67,7 +68,7 @@ LunaixOS - 一个简单的,详细的,POSIX兼容的(但愿!),带有 运行该操作系统需要一个虚拟磁盘镜像,可以使用如下命令快速创建一个: ```bash -qemu-img create -f vdi machine/disk1.vdi 128M +qemu-img create -f vdi machine/disk0.vdi 128M ``` 如果你想要使用别的磁盘镜像,需要修改`configs/make-debug-tool` @@ -165,10 +166,32 @@ 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)` +2. `symlink(2)` +2. `chdir(2)` +2. `fchdir(2)` +2. `getcwd(2)` ### LunaixOS自有 1. `yield` +2. `geterrno` +3. `realpathat` ## 附录2:编译gcc作为交叉编译器 diff --git a/lunaix-os/.gitignore b/lunaix-os/.gitignore index 31aeefd..a54615d 100644 --- a/lunaix-os/.gitignore +++ b/lunaix-os/.gitignore @@ -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 diff --git a/lunaix-os/config/make-cc b/lunaix-os/config/make-cc index 643b4ee..7a1899c 100644 --- a/lunaix-os/config/make-cc +++ b/lunaix-os/config/make-cc @@ -4,6 +4,12 @@ AS := i686-elf-as ARCH_OPT := -D__ARCH_IA32 O := -O2 -W := -Wall -Wextra -Wno-unknown-pragmas +W := -Wall -Wextra -Wno-unknown-pragmas \ + -Wno-unused-function \ + -Wno-unused-but-set-variable \ + -Wno-unused-parameter \ + -Wno-unused-variable\ + -Werror=incompatible-pointer-types + CFLAGS := -std=gnu99 -ffreestanding $(O) $(W) $(ARCH_OPT) LDFLAGS := -ffreestanding $(O) -nostdlib -lgcc \ No newline at end of file diff --git a/lunaix-os/hal/acpi/acpi.c b/lunaix-os/hal/acpi/acpi.c index 0b1d988..c6a566e 100644 --- a/lunaix-os/hal/acpi/acpi.c +++ b/lunaix-os/hal/acpi/acpi.c @@ -1,6 +1,6 @@ #include -#include +#include #include #include @@ -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); @@ -38,7 +36,8 @@ acpi_init(multiboot_info_t* mb_info) size_t entry_n = (rsdt->header.length - sizeof(acpi_sdthdr_t)) >> 2; for (size_t i = 0; i < entry_n; i++) { - acpi_sdthdr_t* sdthdr = ((acpi_apic_t**)&(rsdt->entry))[i]; + acpi_sdthdr_t* sdthdr = + (acpi_sdthdr_t*)((acpi_apic_t**)&(rsdt->entry))[i]; switch (sdthdr->signature) { case ACPI_MADT_SIG: madt_parse((acpi_madt_t*)sdthdr, ctx); @@ -55,15 +54,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* diff --git a/lunaix-os/hal/acpi/parser/madt_parser.c b/lunaix-os/hal/acpi/parser/madt_parser.c index 971a4a0..5e9aeb4 100644 --- a/lunaix-os/hal/acpi/parser/madt_parser.c +++ b/lunaix-os/hal/acpi/parser/madt_parser.c @@ -1,5 +1,5 @@ #include "parser.h" -#include +#include void madt_parse(acpi_madt_t* madt, acpi_context* toc) @@ -13,7 +13,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*)); + (acpi_intso_t**)vcalloc(24, sizeof(acpi_intso_t*)); size_t so_idx = 0; while (ics_start < ics_end) { diff --git a/lunaix-os/hal/acpi/parser/mcfg_parser.c b/lunaix-os/hal/acpi/parser/mcfg_parser.c index 0efe0d5..49d04a7 100644 --- a/lunaix-os/hal/acpi/parser/mcfg_parser.c +++ b/lunaix-os/hal/acpi/parser/mcfg_parser.c @@ -1,6 +1,6 @@ #include "lunaix/syslog.h" #include "parser.h" -#include +#include 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){ diff --git a/lunaix-os/hal/ahci/ahci.c b/lunaix-os/hal/ahci/ahci.c index ee52156..a04bca7 100644 --- a/lunaix-os/hal/ahci/ahci.c +++ b/lunaix-os/hal/ahci/ahci.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -33,7 +34,7 @@ LOG_MODULE("AHCI") static struct ahci_hba hba; void -__ahci_hba_isr(isr_param param); +__ahci_hba_isr(const isr_param* param); int ahci_init_device(struct hba_port* port); @@ -173,6 +174,8 @@ ahci_init() if (!ahci_init_device(port)) { kprintf(KERROR "fail to init device"); } + + block_mount_disk(port->device); } } @@ -182,7 +185,7 @@ char sata_ifs[][20] = { "Not detected", "SATA III (6.0Gbps)" }; void -__ahci_hba_isr(isr_param param) +__ahci_hba_isr(const isr_param* param) { // TODO: clear the interrupt status // TODO: I/O-operation scheduler should be here @@ -276,7 +279,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)); @@ -318,7 +321,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; @@ -420,11 +424,11 @@ fail: } int -ahci_identify_device(struct hba_port* port) +ahci_identify_device(struct hba_device* device) { // 用于重新识别设备(比如在热插拔的情况下) - vfree(port->device); - return ahci_init_device(port); + vfree(device); + return ahci_init_device(device->port); } void diff --git a/lunaix-os/hal/ahci/ata.c b/lunaix-os/hal/ahci/ata.c index f6ff7c1..a77e03b 100644 --- a/lunaix-os/hal/ahci/ata.c +++ b/lunaix-os/hal/ahci/ata.c @@ -5,8 +5,16 @@ #include #include +void +sata_read_error(struct hba_port* port) +{ + uint32_t tfd = port->regs[HBA_RPxTFD]; + port->device->last_error = (tfd >> 8) & 0xff; + port->device->last_status = tfd & 0xff; +} + 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 +22,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); @@ -27,7 +36,7 @@ __sata_buffer_io(struct hba_port* port, header->options |= HBA_CMDH_WRITE * (write == 1); uint16_t count = ICEIL(size, port->device->block_size); - struct sata_reg_fis* fis = table->command_fis; + struct sata_reg_fis* fis = (struct sata_reg_fis*)table->command_fis; if ((port->device->flags & HBA_DEV_FEXTLBA)) { // 如果该设备支持48位LBA寻址 @@ -70,27 +79,19 @@ 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 -sata_read_error(struct hba_port* port) -{ - uint32_t tfd = port->regs[HBA_RPxTFD]; - port->device->last_error = (tfd >> 8) & 0xff; - port->device->last_status = tfd & 0xff; -} \ No newline at end of file diff --git a/lunaix-os/hal/ahci/atapi.c b/lunaix-os/hal/ahci/atapi.c index 397c733..85c3bab 100644 --- a/lunaix-os/hal/ahci/atapi.c +++ b/lunaix-os/hal/ahci/atapi.c @@ -41,8 +41,8 @@ scsi_parse_capacity(struct hba_device* device, uint32_t* parameter) device->block_size = SCSI_FLIP(*(parameter + 2)); } -void -__scsi_buffer_io(struct hba_port* port, +int +__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); @@ -64,7 +65,7 @@ __scsi_buffer_io(struct hba_port* port, uint32_t count = ICEIL(size, port->device->block_size); - struct sata_reg_fis* fis = table->command_fis; + struct sata_reg_fis* fis = (struct sata_reg_fis*)table->command_fis; void* cdb = table->atapi_cmd; sata_create_fis(fis, ATA_PACKET, (size << 8), 0); fis->feature = 1 | ((!write) << 2); @@ -106,20 +107,20 @@ fail: return 0; } -void -scsi_read_buffer(struct hba_port* port, +int +scsi_read_buffer(struct hba_device* dev, uint64_t lba, void* buffer, uint32_t size) { - __scsi_buffer_io(port, lba, buffer, size, 0); + return __scsi_buffer_io(dev, lba, buffer, size, 0); } -void -scsi_write_buffer(struct hba_port* port, +int +scsi_write_buffer(struct hba_device* dev, uint64_t lba, void* buffer, uint32_t size) { - __scsi_buffer_io(port, lba, buffer, size, 1); + return __scsi_buffer_io(dev, lba, buffer, size, 1); } \ No newline at end of file diff --git a/lunaix-os/hal/ahci/utils.c b/lunaix-os/hal/ahci/utils.c index e101efd..664488d 100644 --- a/lunaix-os/hal/ahci/utils.c +++ b/lunaix-os/hal/ahci/utils.c @@ -33,8 +33,8 @@ ahci_parse_dev_info(struct hba_device* dev_info, uint16_t* data) dev_info->flags |= HBA_DEV_FEXTLBA; } - ahci_parsestr(&dev_info->serial_num, data + IDDEV_OFFSERIALNUM, 10); - ahci_parsestr(&dev_info->model, data + IDDEV_OFFMODELNUM, 20); + ahci_parsestr(dev_info->serial_num, data + IDDEV_OFFSERIALNUM, 10); + ahci_parsestr(dev_info->model, data + IDDEV_OFFMODELNUM, 20); } void diff --git a/lunaix-os/hal/pci.c b/lunaix-os/hal/pci.c index 8c397b0..3d6accf 100644 --- a/lunaix-os/hal/pci.c +++ b/lunaix-os/hal/pci.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include @@ -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, @@ -126,7 +126,7 @@ pci_print_device() PCI_INTR_IRQ(pos->intr_info), PCI_INTR_PIN(pos->intr_info)); #ifdef PCI_PRINT_BAR_LISTING - pci_reg_t bar; + uint32_t bar; for (size_t i = 1; i <= 6; i++) { size_t size = pci_bar_sizing(pos, &bar, i); if (!bar) @@ -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); } diff --git a/lunaix-os/includes/arch/x86/interrupts.h b/lunaix-os/includes/arch/x86/interrupts.h index 862ef05..3643a9e 100644 --- a/lunaix-os/includes/arch/x86/interrupts.h +++ b/lunaix-os/includes/arch/x86/interrupts.h @@ -32,7 +32,7 @@ typedef struct unsigned int ss; } __attribute__((packed)) isr_param; -typedef void (*int_subscriber)(isr_param*); +typedef void (*int_subscriber)(const isr_param*); #pragma region ISR_DECLARATION @@ -63,6 +63,7 @@ ISR(21) ISR(32) ISR(33) +ISR(34) ISR(201) ISR(202) diff --git a/lunaix-os/includes/arch/x86/vectors.h b/lunaix-os/includes/arch/x86/vectors.h index e4a1968..9873db6 100644 --- a/lunaix-os/includes/arch/x86/vectors.h +++ b/lunaix-os/includes/arch/x86/vectors.h @@ -29,6 +29,7 @@ // LunaixOS related #define LUNAIX_SYS_PANIC 32 #define LUNAIX_SYS_CALL 33 +#define LUNAIX_SCHED 34 #define EX_INTERRUPT_BEGIN 200 diff --git a/lunaix-os/includes/hal/ahci/hba.h b/lunaix-os/includes/hal/ahci/hba.h index 9ca688d..c868c6f 100644 --- a/lunaix-os/includes/hal/ahci/hba.h +++ b/lunaix-os/includes/hal/ahci/hba.h @@ -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); diff --git a/lunaix-os/includes/hal/ahci/sata.h b/lunaix-os/includes/hal/ahci/sata.h index 99a45bc..dc93448 100644 --- a/lunaix-os/includes/hal/ahci/sata.h +++ b/lunaix-os/includes/hal/ahci/sata.h @@ -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); diff --git a/lunaix-os/includes/hal/ahci/scsi.h b/lunaix-os/includes/hal/ahci/scsi.h index cce9af4..0635614 100644 --- a/lunaix-os/includes/hal/ahci/scsi.h +++ b/lunaix-os/includes/hal/ahci/scsi.h @@ -47,14 +47,14 @@ scsi_create_packet16(struct scsi_cdb16* cdb, uint64_t lba, uint32_t alloc_size); -void -scsi_read_buffer(struct hba_port* port, +int +scsi_read_buffer(struct hba_device* dev, uint64_t lba, void* buffer, uint32_t size); -void -scsi_write_buffer(struct hba_port* port, +int +scsi_write_buffer(struct hba_device* dev, uint64_t lba, void* buffer, uint32_t size); diff --git a/lunaix-os/includes/hal/cpu.h b/lunaix-os/includes/hal/cpu.h index af56120..5789d4a 100644 --- a/lunaix-os/includes/hal/cpu.h +++ b/lunaix-os/includes/hal/cpu.h @@ -117,6 +117,12 @@ cpu_invtlb() : "r"(interm)); } +static inline void +cpu_int(int vect) +{ + asm("int %0" ::"i"(vect)); +} + void cpu_rdmsr(uint32_t msr_idx, uint32_t* reg_high, uint32_t* reg_low); diff --git a/lunaix-os/includes/hal/pci.h b/lunaix-os/includes/hal/pci.h index d622acb..57c04ca 100644 --- a/lunaix-os/includes/hal/pci.h +++ b/lunaix-os/includes/hal/pci.h @@ -69,14 +69,14 @@ struct pci_device // PCI Configuration Space (C-Space) r/w: // Refer to "PCI Local Bus Specification, Rev.3, Section 3.2.2.3.2" -inline pci_reg_t +static inline pci_reg_t pci_read_cspace(uint32_t base, int offset) { io_outl(PCI_CONFIG_ADDR, base | (offset & ~0x3)); return io_inl(PCI_CONFIG_DATA); } -inline void +static inline void pci_write_cspace(uint32_t base, int offset, pci_reg_t data) { io_outl(PCI_CONFIG_ADDR, base | (offset & ~0x3)); diff --git a/lunaix-os/includes/klibc/stdio.h b/lunaix-os/includes/klibc/stdio.h index 07f4716..d97f028 100644 --- a/lunaix-os/includes/klibc/stdio.h +++ b/lunaix-os/includes/klibc/stdio.h @@ -3,9 +3,11 @@ #include #include -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 */ diff --git a/lunaix-os/includes/klibc/string.h b/lunaix-os/includes/klibc/string.h index 8337ef1..35fd53e 100644 --- a/lunaix-os/includes/klibc/string.h +++ b/lunaix-os/includes/klibc/string.h @@ -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 index 0000000..4e9c4db --- /dev/null +++ b/lunaix-os/includes/lib/crc.h @@ -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 index 0000000..22998f7 --- /dev/null +++ b/lunaix-os/includes/lib/hash.h @@ -0,0 +1,26 @@ +#ifndef __LUNAIX_HASH_H +#define __LUNAIX_HASH_H + +#include + +#define HASH_SIZE_BITS 32 + +uint32_t +strhash_32(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 index 0000000..40935f9 --- /dev/null +++ b/lunaix-os/includes/lunaix/block.h @@ -0,0 +1,47 @@ +#ifndef __LUNAIX_BLOCK_H +#define __LUNAIX_BLOCK_H + +#include +#include + +#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 */ diff --git a/lunaix-os/includes/lunaix/clock.h b/lunaix-os/includes/lunaix/clock.h index dbfdfe5..44dfa04 100644 --- a/lunaix-os/includes/lunaix/clock.h +++ b/lunaix-os/includes/lunaix/clock.h @@ -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 */ diff --git a/lunaix-os/includes/lunaix/common.h b/lunaix-os/includes/lunaix/common.h index 7fdf0b3..4c8c794 100644 --- a/lunaix-os/includes/lunaix/common.h +++ b/lunaix-os/includes/lunaix/common.h @@ -32,8 +32,6 @@ #define USTACK_END (0x9fffffff - USTACK_SIZE + 1) #define UMMAP_AREA 0x4D000000 -#define SYS_TIMER_FREQUENCY_HZ 2048 - #ifndef __ASM__ #include // From Linux kernel v2.6.0 @@ -48,7 +46,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 index 0000000..14558a7 --- /dev/null +++ b/lunaix-os/includes/lunaix/device.h @@ -0,0 +1,33 @@ +#ifndef __LUNAIX_DEVICE_H +#define __LUNAIX_DEVICE_H + +#define DEVICE_NAME_SIZE 32 + +#include +#include + +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, size_t offset, size_t len); + int (*write)(struct device* dev, void* buf, size_t offset, size_t 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 index 0000000..faa56a6 --- /dev/null +++ b/lunaix-os/includes/lunaix/dirent.h @@ -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 index 0000000..ad3d04c --- /dev/null +++ b/lunaix-os/includes/lunaix/ds/btrie.h @@ -0,0 +1,40 @@ +#ifndef __LUNAIX_SPARSE_H +#define __LUNAIX_SPARSE_H + +#include +#include + +#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 index 0000000..3a21824 --- /dev/null +++ b/lunaix-os/includes/lunaix/ds/fifo.h @@ -0,0 +1,35 @@ +#ifndef __LUNAIX_FIFO_BUF_H +#define __LUNAIX_FIFO_BUF_H + +#include +#include + +#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 index f5f08c1..0000000 --- a/lunaix-os/includes/lunaix/ds/fifobuf.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __LUNAIX_FIFO_BUF_H -#define __LUNAIX_FIFO_BUF_H - -#include - -#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 index 0000000..0e8c691 --- /dev/null +++ b/lunaix-os/includes/lunaix/ds/hashtable.h @@ -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 +#include + +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 index 0000000..f3fa89e --- /dev/null +++ b/lunaix-os/includes/lunaix/ds/hstr.h @@ -0,0 +1,35 @@ +#ifndef __LUNAIX_HSTR_H +#define __LUNAIX_HSTR_H + +#include + +#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 */ diff --git a/lunaix-os/includes/lunaix/ds/llist.h b/lunaix-os/includes/lunaix/ds/llist.h index 5afc36a..6129ca0 100644 --- a/lunaix-os/includes/lunaix/ds/llist.h +++ b/lunaix-os/includes/lunaix/ds/llist.h @@ -41,13 +41,13 @@ llist_init_head(struct llist_header* head) static inline void llist_append(struct llist_header* head, struct llist_header* elem) { - __llist_add(elem, head, head->next); + __llist_add(elem, head->prev, head); } static inline void llist_prepend(struct llist_header* head, struct llist_header* elem) { - __llist_add(elem, head->prev, head); + __llist_add(elem, head, head->next); } static inline void @@ -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/ds/lru.h b/lunaix-os/includes/lunaix/ds/lru.h new file mode 100644 index 0000000..5ae607d --- /dev/null +++ b/lunaix-os/includes/lunaix/ds/lru.h @@ -0,0 +1,29 @@ +#ifndef __LUNAIX_LRU_H +#define __LUNAIX_LRU_H + +#include + +struct lru_zone +{ + struct llist_header lead_node; + struct llist_header zones; +}; + +struct lru_node +{ + struct llist_header lru_nodes; +}; + +struct lru_zone* +lru_new_zone(); + +void +lru_use_one(struct lru_zone* zone, struct lru_node* node); + +struct lru_node* +lru_evict_one(struct lru_zone* zone); + +void +lru_remove(struct lru_node* node); + +#endif /* __LUNAIX_LRU_H */ diff --git a/lunaix-os/includes/lunaix/fctrl.h b/lunaix-os/includes/lunaix/fctrl.h new file mode 100644 index 0000000..dc28872 --- /dev/null +++ b/lunaix-os/includes/lunaix/fctrl.h @@ -0,0 +1,28 @@ +#ifndef __LUNAIX_FCTRL_H +#define __LUNAIX_FCTRL_H + +#include +#include +#include + +__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 index 0000000..f43fb10 --- /dev/null +++ b/lunaix-os/includes/lunaix/foptions.h @@ -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 index 0000000..d0d59d1 --- /dev/null +++ b/lunaix-os/includes/lunaix/fs.h @@ -0,0 +1,282 @@ +#ifndef __LUNAIX_VFS_H +#define __LUNAIX_VFS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 v_inode; +struct v_superblock; +struct v_file; +struct v_fd; +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_inode* inode, void* buffer, size_t len, size_t fpos); + int (*read)(struct v_inode* inode, void* buffer, size_t len, size_t fpos); + int (*readdir)(struct v_inode* inode, struct dir_context* dctx); + int (*seek)(struct v_inode* inode, size_t offset); + int (*rename)(struct v_inode* inode, char* new_name); + int (*close)(struct v_file* file); + int (*sync)(struct v_inode* inode); +}; + +struct v_file +{ + struct v_inode* inode; + struct v_dnode* dnode; + struct llist_header* f_list; + uint32_t f_pos; + uint32_t ref_count; + 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; + uint32_t ref_count; + 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; + struct lru_node lru; + void* pg; + uint32_t flags; + uint32_t fpos; +}; + +struct pcache +{ + struct v_inode* master; + 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_inode* inode, void* data, uint32_t len, uint32_t fpos); + +int +pcache_read(struct v_inode* inode, void* data, uint32_t len, uint32_t fpos); + +void +pcache_release(struct pcache* pcache); + +int +pcache_commit(struct v_inode* inode, struct pcache_pg* page); + +void +pcache_commit_all(struct v_inode* inode); + +void +pcache_invalidate(struct pcache* pcache, struct pcache_pg* page); +#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 index 0000000..22028f3 --- /dev/null +++ b/lunaix-os/includes/lunaix/fs/twifs.h @@ -0,0 +1,48 @@ +#ifndef __LUNAIX_TWIFS_H +#define __LUNAIX_TWIFS_H + +#include + +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_inode* inode, + void* buffer, + size_t len, + size_t fpos); + int (*read)(struct v_inode* inode, + 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 */ diff --git a/lunaix-os/includes/lunaix/lunistd.h b/lunaix-os/includes/lunaix/lunistd.h index c16f2b0..cb5af35 100644 --- a/lunaix-os/includes/lunaix/lunistd.h +++ b/lunaix-os/includes/lunaix/lunistd.h @@ -3,6 +3,7 @@ #include #include +#include __LXSYSCALL(pid_t, fork) @@ -24,4 +25,34 @@ __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) + +__LXSYSCALL1(int, chdir, const char*, path) + +__LXSYSCALL1(int, fchdir, int, fd) + +__LXSYSCALL2(char*, getcwd, char*, buf, size_t, size) + #endif /* __LUNAIX_UNISTD_H */ diff --git a/lunaix-os/includes/lunaix/mm/valloc.h b/lunaix-os/includes/lunaix/mm/valloc.h index d5d0c75..9be750c 100644 --- a/lunaix-os/includes/lunaix/mm/valloc.h +++ b/lunaix-os/includes/lunaix/mm/valloc.h @@ -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); diff --git a/lunaix-os/includes/lunaix/peripheral/ps2kbd.h b/lunaix-os/includes/lunaix/peripheral/ps2kbd.h index 2d568a6..08a0d56 100644 --- a/lunaix-os/includes/lunaix/peripheral/ps2kbd.h +++ b/lunaix-os/includes/lunaix/peripheral/ps2kbd.h @@ -2,74 +2,76 @@ #define __LUNAIX_PS2KBD_H #include -#include #include - +#include #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 */ diff --git a/lunaix-os/includes/lunaix/proc.h b/lunaix-os/includes/lunaix/proc.h index eafae4f..f4de8cf 100644 --- a/lunaix-os/includes/lunaix/proc.h +++ b/lunaix-os/includes/lunaix/proc.h @@ -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 */ diff --git a/lunaix-os/includes/lunaix/process.h b/lunaix-os/includes/lunaix/process.h index d35bfe7..18cddb9 100644 --- a/lunaix-os/includes/lunaix/process.h +++ b/lunaix-os/includes/lunaix/process.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -77,6 +78,8 @@ struct proc_info sigset_t sig_inprogress; int flags; void* sig_handler[_SIG_NUM]; + struct v_fdtable* fdtable; + struct v_dnode* cwd; pid_t pgid; }; diff --git a/lunaix-os/includes/lunaix/sched.h b/lunaix-os/includes/lunaix/sched.h index 69019f3..021b55e 100644 --- a/lunaix-os/includes/lunaix/sched.h +++ b/lunaix-os/includes/lunaix/sched.h @@ -17,6 +17,6 @@ void schedule(); void -sched_yield(); +sched_yieldk(); #endif /* __LUNAIX_SCHEDULER_H */ diff --git a/lunaix-os/includes/lunaix/spike.h b/lunaix-os/includes/lunaix/spike.h index 777a457..4363b41 100644 --- a/lunaix-os/includes/lunaix/spike.h +++ b/lunaix-os/includes/lunaix/spike.h @@ -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倍数 @@ -17,6 +17,51 @@ // 获取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 diff --git a/lunaix-os/includes/lunaix/status.h b/lunaix-os/includes/lunaix/status.h index aeef93e..3d300f2 100644 --- a/lunaix-os/includes/lunaix/status.h +++ b/lunaix-os/includes/lunaix/status.h @@ -5,10 +5,28 @@ #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 +#define ERANGE -24 +#define ENOMEM LXOUTOFMEM + #endif /* __LUNAIX_CODE_H */ diff --git a/lunaix-os/includes/lunaix/syscall.h b/lunaix-os/includes/lunaix/syscall.h index 8e145e5..1e205c2 100644 --- a/lunaix-os/includes/lunaix/syscall.h +++ b/lunaix-os/includes/lunaix/syscall.h @@ -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 @@ -21,10 +22,37 @@ #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_chdir 38 +#define __SYSCALL_fchdir 39 +#define __SYSCALL_getcwd 40 #define __SYSCALL_MAX 0x100 #ifndef __ASM__ + +#define SYSCALL_ESTATUS(errno) -((errno) != 0) + void syscall_install(); @@ -90,7 +118,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) \ diff --git a/lunaix-os/includes/lunaix/tty/console.h b/lunaix-os/includes/lunaix/tty/console.h index 9eb4ea0..e5eaa34 100644 --- a/lunaix-os/includes/lunaix/tty/console.h +++ b/lunaix-os/includes/lunaix/tty/console.h @@ -1,13 +1,14 @@ #ifndef __LUNAIX_CONSOLE_H #define __LUNAIX_CONSOLE_H -#include +#include #include 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; }; diff --git a/lunaix-os/includes/lunaix/types.h b/lunaix-os/includes/lunaix/types.h index e91025a..3069a83 100644 --- a/lunaix-os/includes/lunaix/types.h +++ b/lunaix-os/includes/lunaix/types.h @@ -1,6 +1,7 @@ #ifndef __LUNAIX_TYPES_H #define __LUNAIX_TYPES_H +#include #include #define PEXITTERM 0x100 @@ -20,5 +21,6 @@ // TODO: WTERMSIG typedef int32_t pid_t; +typedef int64_t lba_t; #endif /* __LUNAIX_TYPES_H */ diff --git a/lunaix-os/kernel/asm/x86/idt.c b/lunaix-os/kernel/asm/x86/idt.c index d2578f7..e8b9524 100644 --- a/lunaix-os/kernel/asm/x86/idt.c +++ b/lunaix-os/kernel/asm/x86/idt.c @@ -63,4 +63,6 @@ _init_idt() // We make this a non-trap entry, and enable interrupt // only when needed! _set_idt_intr_entry(LUNAIX_SYS_CALL, 0x08, _asm_isr33, 3); + + _set_idt_intr_entry(LUNAIX_SCHED, 0x08, _asm_isr34, 0); } \ No newline at end of file diff --git a/lunaix-os/kernel/asm/x86/interrupt.S b/lunaix-os/kernel/asm/x86/interrupt.S index 7382142..b4ce936 100644 --- a/lunaix-os/kernel/asm/x86/interrupt.S +++ b/lunaix-os/kernel/asm/x86/interrupt.S @@ -36,6 +36,7 @@ isr_template LUNAIX_SYS_PANIC isr_template LUNAIX_SYS_CALL + isr_template LUNAIX_SCHED isr_template APIC_ERROR_IV isr_template APIC_LINT0_IV diff --git a/lunaix-os/kernel/asm/x86/intr_routines.c b/lunaix-os/kernel/asm/x86/intr_routines.c index 807dbe4..813490c 100644 --- a/lunaix-os/kernel/asm/x86/intr_routines.c +++ b/lunaix-os/kernel/asm/x86/intr_routines.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -84,6 +85,12 @@ intr_routine_apic_error(const isr_param* param) spin(); } +void +intr_routine_sched(const isr_param* param) +{ + schedule(); +} + void intr_routine_init() { @@ -91,7 +98,10 @@ intr_routine_init() intr_subscribe(FAULT_GENERAL_PROTECTION, intr_routine_general_protection); intr_subscribe(FAULT_PAGE_FAULT, intr_routine_page_fault); intr_subscribe(FAULT_STACK_SEG_FAULT, intr_routine_page_fault); + intr_subscribe(LUNAIX_SYS_PANIC, intr_routine_sys_panic); + intr_subscribe(LUNAIX_SCHED, intr_routine_sched); + intr_subscribe(APIC_SPIV_IV, intr_routine_apic_spi); intr_subscribe(APIC_ERROR_IV, intr_routine_apic_error); diff --git a/lunaix-os/kernel/asm/x86/syscall.S b/lunaix-os/kernel/asm/x86/syscall.S index b13dee0..b35a217 100644 --- a/lunaix-os/kernel/asm/x86/syscall.S +++ b/lunaix-os/kernel/asm/x86/syscall.S @@ -26,6 +26,28 @@ .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 + .long __lxsys_chdir + .long __lxsys_fchdir + .long __lxsys_getcwd 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 index 0000000..b855910 --- /dev/null +++ b/lunaix-os/kernel/block.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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, size_t offset, size_t 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, size_t offset, size_t 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 index 0000000..caa88cc --- /dev/null +++ b/lunaix-os/kernel/demos/dir_read.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include + +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 index 0000000..0ebe696 --- /dev/null +++ b/lunaix-os/kernel/demos/iotest.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include + +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."; + char read_out[256]; + + // 切换工作目录至 /dev + int errno = chdir("/dev"); + if (errno) { + write(STDOUT, "fail to chdir", 15); + return; + } + + if (getcwd(read_out, sizeof(read_out))) { + write(STDOUT, "current working dir: ", 22); + write(STDOUT, read_out, 256); + write(STDOUT, "\n", 2); + } + + // sda 设备 - 硬盘 + // sda设备属于容积设备(Volumetric Device), + // Lunaix会尽可能缓存任何对此设备的上层读写,并使用延迟写入策略。(FO_DIRECT可用于屏蔽该功能) + int fd = open("./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)); + + 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 index 0000000..017f3b3 --- /dev/null +++ b/lunaix-os/kernel/device.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include + +struct llist_header dev_list; + +static struct twifs_node* dev_root; + +int +__dev_read(struct v_inode* inode, void* buffer, size_t len, size_t fpos); + +int +__dev_write(struct v_inode* inode, 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_inode* inode, void* buffer, size_t len, size_t fpos) +{ + struct twifs_node* dev_node = (struct twifs_node*)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_inode* inode, void* buffer, size_t len, size_t fpos) +{ + struct twifs_node* dev_node = (struct twifs_node*)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 index 0000000..8a4380e --- /dev/null +++ b/lunaix-os/kernel/ds/btrie.c @@ -0,0 +1,126 @@ +/** + * @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 +#include +#include + +#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_rm_recursive(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) && !parent->data) { + __btrie_rm_recursive(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; + if (!llist_empty(&node->children)) { + node->data = NULL; + } else { + __btrie_rm_recursive(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 index 0000000..1e72e8d --- /dev/null +++ b/lunaix-os/kernel/ds/fifo.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include + +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/ds/lru.c b/lunaix-os/kernel/ds/lru.c new file mode 100644 index 0000000..ebabeef --- /dev/null +++ b/lunaix-os/kernel/ds/lru.c @@ -0,0 +1,49 @@ +#include +#include + +struct llist_header zone_lead = { .next = &zone_lead, .prev = &zone_lead }; + +struct lru_zone* +lru_new_zone() +{ + struct lru_zone* zone = valloc(sizeof(struct lru_zone)); + if (!zone) { + return NULL; + } + + llist_init_head(&zone->lead_node); + llist_append(&zone_lead, &zone->zones); + + return zone; +} + +void +lru_use_one(struct lru_zone* zone, struct lru_node* node) +{ + if (node->lru_nodes.next && node->lru_nodes.prev) { + llist_delete(&node->lru_nodes); + } + + llist_prepend(&zone->lead_node, &node->lru_nodes); +} + +struct lru_node* +lru_evict_one(struct lru_zone* zone) +{ + struct llist_header* tail = zone->lead_node.prev; + if (tail == &zone->lead_node) { + return; + } + + llist_delete(tail); + + return container_of(tail, struct lru_node, lru_nodes); +} + +void +lru_remove(struct lru_node* node) +{ + if (node->lru_nodes.next && node->lru_nodes.prev) { + llist_delete(&node->lru_nodes); + } +} \ 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 index 0000000..10e766a --- /dev/null +++ b/lunaix-os/kernel/fs/fsm.c @@ -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 +#include +#include + +#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 index 0000000..03f7502 --- /dev/null +++ b/lunaix-os/kernel/fs/pcache.c @@ -0,0 +1,209 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define PCACHE_DIRTY 0x1 + +static struct lru_zone* pcache_zone; + +void +pcache_init(struct pcache* pcache) +{ + btrie_init(&pcache->tree, PG_SIZE_BITS); + llist_init_head(&pcache->dirty); + llist_init_head(&pcache->pages); + pcache_zone = lru_new_zone(); +} + +void +pcache_release_page(struct pcache* pcache, struct pcache_pg* page) +{ + vfree(page->pg); + + llist_delete(&page->pg_list); + + vfree(page); + + pcache->n_pages--; +} + +void +pcache_evict(struct pcache* pcache) +{ + struct pcache_pg* page = + container_of(lru_evict_one(pcache_zone), struct pcache_pg, lru); + + if (!page) + return; + + pcache_invalidate(pcache, page); +} + +struct pcache_pg* +pcache_new_page(struct pcache* pcache, uint32_t index) +{ + struct pcache_pg* ppg = vzalloc(sizeof(struct pcache_pg)); + void* pg = valloc(PG_SIZE); + + if (!ppg || !pg) { + pcache_evict(pcache); + if (!ppg && !(ppg = vzalloc(sizeof(struct pcache_pg)))) { + return NULL; + } + + if (!pg && !(pg = valloc(PG_SIZE))) { + return NULL; + } + } + + ppg->pg = pg; + + 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; + } + if (pg) + lru_use_one(pcache_zone, &pg->lru); + *page = pg; + return is_new; +} + +int +pcache_write(struct v_inode* inode, void* data, uint32_t len, uint32_t fpos) +{ + uint32_t pg_off, buf_off = 0; + struct pcache* pcache = inode->pg_cache; + struct pcache_pg* pg; + + while (buf_off < len) { + pcache_get_page(pcache, fpos, &pg_off, &pg); + if (!pg) { + return ENOMEM; + } + + 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_inode* inode, void* data, uint32_t len, uint32_t fpos) +{ + uint32_t pg_off, buf_off = 0, new_pg = 0; + int errno = 0; + struct pcache* pcache = inode->pg_cache; + struct pcache_pg* pg; + + while (buf_off < len) { + if (pcache_get_page(pcache, fpos, &pg_off, &pg)) { + + if (!pg) { + return ENOMEM; + } + + // Filling up the page + errno = inode->default_fops.read(inode, 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) + { + lru_remove(&pos->lru); + vfree(pos); + } + + btrie_release(&pcache->tree); +} + +int +pcache_commit(struct v_inode* inode, struct pcache_pg* page) +{ + if (!(page->flags & PCACHE_DIRTY)) { + return; + } + + int errno = inode->default_fops.write(inode, page->pg, PG_SIZE, page->fpos); + + if (!errno) { + page->flags &= ~PCACHE_DIRTY; + llist_delete(&page->dirty_list); + inode->pg_cache->n_dirty--; + } + + return errno; +} + +void +pcache_commit_all(struct v_inode* inode) +{ + struct pcache* cache = inode->pg_cache; + struct pcache_pg *pos, *n; + + llist_for_each(pos, n, &cache->dirty, dirty_list) + { + pcache_commit(inode, pos); + } +} + +void +pcache_invalidate(struct pcache* pcache, struct pcache_pg* page) +{ + pcache_commit(pcache->master, page); + pcache_release_page(pcache, 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 index 0000000..ec2707f --- /dev/null +++ b/lunaix-os/kernel/fs/twifs/twifs.c @@ -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 +#include +#include +#include +#include +#include + +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_inode* inode, 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_inode* inode, void* buffer, size_t len, size_t fpos); + +int +__twifs_fread(struct v_inode* inode, 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_inode* inode, void* buffer, size_t len, size_t fpos) +{ + struct twifs_node* twi_node = (struct twifs_node*)inode->data; + if (!twi_node || !twi_node->ops.write) { + return ENOTSUP; + } + return twi_node->ops.write(inode, buffer, len, fpos); +} + +int +__twifs_fread(struct v_inode* inode, void* buffer, size_t len, size_t fpos) +{ + struct twifs_node* twi_node = (struct twifs_node*)inode->data; + if (!twi_node || !twi_node->ops.read) { + return ENOTSUP; + } + return twi_node->ops.read(inode, 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_inode* inode, struct dir_context* dctx) +{ + struct twifs_node* twi_node = (struct twifs_node*)(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 index 0000000..68a8d5f --- /dev/null +++ b/lunaix-os/kernel/fs/vfs.c @@ -0,0 +1,1122 @@ +/** + * @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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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(¤t_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; + const 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(__current->cwd, 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(__current->cwd, 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; + + if ((inode->itype & VFS_IFFILE) && !inode->pg_cache) { + struct pcache* pcache = vzalloc(sizeof(struct pcache)); + pcache_init(pcache); + pcache->master = inode; + inode->pg_cache = pcache; + } + + int errno = inode->ops.open(inode, vfile); + if (errno) { + cake_release(file_pile, vfile); + } else { + dnode->ref_count++; + inode->open_count++; + *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))) { + file->dnode->ref_count--; + file->inode->open_count--; + pcache_commit_all(file->inode); + cake_release(file_pile, file); + } + return errno; +} + +int +vfs_fsync(struct v_file* file) +{ + int errno = ENOTSUP; + pcache_commit_all(file->inode); + if (file->ops.sync) { + errno = file->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; }) + +#define TEST_FD(fd) (fd >= 0 && fd < VFS_MAX_FD) + +int +__vfs_getfd(int fd, struct v_fd** fd_s) +{ + if (TEST_FD(fd) && (*fd_s = __current->fdtable->fds[fd])) { + return 0; + } + return EBADF; +} + +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(__current->cwd, 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 +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_LXSYSCALL1(int, close, int, fd) +{ + struct v_fd* fd_s; + int errno = 0; + if ((errno = __vfs_getfd(fd, &fd_s))) { + 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 ((errno = __vfs_getfd(fd, &fd_s))) { + goto done; + } + + 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->inode, &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(__current->cwd, 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 ((errno = __vfs_getfd(fd, &fd_s))) { + goto done; + } + + struct v_file* file = fd_s->file; + if ((file->inode->itype & VFS_IFDIR)) { + errno = EISDIR; + goto done; + } + + __SYSCALL_INTERRUPTIBLE( + { errno = file->ops.read(file->inode, buf, count, file->f_pos); }) + + 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 ((errno = __vfs_getfd(fd, &fd_s))) { + goto done; + } + + struct v_file* file = fd_s->file; + if ((file->inode->itype & VFS_IFDIR)) { + errno = EISDIR; + goto done; + } + + __SYSCALL_INTERRUPTIBLE( + { errno = file->ops.write(file->inode, buf, count, file->f_pos); }) + + 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 ((errno = __vfs_getfd(fd, &fd_s))) { + goto done; + } + + 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->inode, fpos))) { + file->f_pos = fpos; + } + +done: + 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) +{ + const 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 ((errno = __vfs_getfd(fd, &fd_s))) { + goto done; + } + + struct v_dnode* dnode; + errno = vfs_get_path(fd_s->file->dnode, buf, size, 0); + + if (errno >= 0) { + return errno; + } + +done: + 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(__current->cwd, 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 ((errno = __vfs_getfd(dirfd, &fd_s))) { + goto done; + } + + 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; + } + +done: + return DO_STATUS(errno); +} + +__DEFINE_LXSYSCALL1(int, rmdir, const char*, pathname) +{ + int errno; + struct v_dnode* dnode; + if ((errno = vfs_walk(__current->cwd, 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(__current->cwd, 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 ((errno = __vfs_getfd(fd, &fd_s))) { + goto done; + } + + 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 (!(errno = __vfs_getfd(fildes, &fd_s))) { + 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 ((errno = __vfs_getfd(oldfd, &oldfd_s))) { + goto done; + } + + if (!TEST_FD(newfd)) { + errno = EBADF; + goto done; + } + + newfd_s = __current->fdtable->fds[newfd]; + if (newfd_s && (errno = vfs_close(newfd_s->file))) { + 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 ((errno = __vfs_getfd(oldfd, &oldfd_s))) { + goto done; + } + + if (!(errno = vfs_alloc_fdslot(&newfd)) && + !(errno = vfs_dup_fd(oldfd_s, &newfd_s))) { + __current->fdtable->fds[newfd] = newfd_s; + return newfd; + } + +done: + 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(__current->cwd, 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); +} + +int +__vfs_do_chdir(struct v_dnode* dnode) +{ + int errno = 0; + if (!(dnode->inode->itype & VFS_IFDIR)) { + errno = ENOTDIR; + goto done; + } + + if (__current->cwd) { + __current->cwd->ref_count--; + } + + dnode->ref_count++; + __current->cwd = dnode; + +done: + return errno; +} + +__DEFINE_LXSYSCALL1(int, chdir, const char*, path) +{ + struct v_dnode* dnode; + int errno = 0; + + if ((errno = vfs_walk(__current->cwd, path, &dnode, NULL, 0))) { + goto done; + } + + errno = __vfs_do_chdir(dnode); + +done: + return DO_STATUS(errno); +} + +__DEFINE_LXSYSCALL1(int, fchdir, int, fd) +{ + struct v_fd* fd_s; + int errno = 0; + + if ((errno = __vfs_getfd(fd, &fd_s))) { + goto done; + } + + errno = __vfs_do_chdir(fd_s->file->dnode); + +done: + return DO_STATUS(errno); +} + +__DEFINE_LXSYSCALL2(char*, getcwd, char*, buf, size_t, size) +{ + int errno = 0; + char* ret_ptr = 0; + if (size < 2) { + errno = ERANGE; + goto done; + } + + size_t len = 0; + + if (!__current->cwd) { + *buf = PATH_DELIM; + len = 1; + } else { + len = vfs_get_path(__current->cwd, buf, size, 0); + if (len == size) { + errno = ERANGE; + goto done; + } + } + + buf[len + 1] = '\0'; + + ret_ptr = buf; + +done: + __current->k_status = errno; + return ret_ptr; +} \ No newline at end of file diff --git a/lunaix-os/kernel/k_init.c b/lunaix-os/kernel/k_init.c index 7acd306..b0aee84 100644 --- a/lunaix-os/kernel/k_init.c +++ b/lunaix-os/kernel/k_init.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -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(); diff --git a/lunaix-os/kernel/lxconsole.c b/lunaix-os/kernel/lxconsole.c index d6b92f8..785330a 100644 --- a/lunaix-os/kernel/lxconsole.c +++ b/lunaix-os/kernel/lxconsole.c @@ -1,33 +1,97 @@ #include +#include +#include #include #include +#include #include +#include #include #include 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_yieldk(); + 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 diff --git a/lunaix-os/kernel/mm/cake.c b/lunaix-os/kernel/mm/cake.c index 7e3142b..c3cee83 100644 --- a/lunaix-os/kernel/mm/cake.c +++ b/lunaix-os/kernel/mm/cake.c @@ -29,6 +29,9 @@ void* __alloc_cake(unsigned int cake_pg) { uintptr_t pa = pmm_alloc_cpage(KERNEL_PID, cake_pg, 0); + if (!pa) { + return NULL; + } return vmm_vmap(pa, cake_pg * PG_SIZE, PG_PREM_RW); } @@ -37,12 +40,16 @@ __new_cake(struct cake_pile* pile) { struct cake_s* cake = __alloc_cake(pile->pg_per_cake); + if (!cake) { + return NULL; + } + int max_piece = pile->pieces_per_cake; cake->first_piece = (void*)((uintptr_t)cake + pile->offset); cake->next_free = 0; - piece_index_t* free_list = &cake->free_list; + piece_index_t* free_list = cake->free_list; for (size_t i = 0; i < max_piece - 1; i++) { free_list[i] = i + 1; } @@ -60,6 +67,10 @@ __init_pile(struct cake_pile* pile, unsigned int pg_per_cake, int options) { + if (!pile) { + return; + } + unsigned int offset = sizeof(long); // 默认每块儿蛋糕对齐到地址总线宽度 @@ -76,12 +87,12 @@ __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); + strncpy(pile->pile_name, name, PILE_NAME_MAXLEN); llist_init_head(&pile->free); llist_init_head(&pile->full); @@ -120,7 +131,9 @@ cake_grab(struct cake_pile* pile) pos = list_entry(pile->free.next, typeof(*pos), cakes); } -found: + if (!pos) + return NULL; + piece_index_t found_index = pos->next_free; pos->next_free = pos->free_list[found_index]; pos->used_pieces++; @@ -140,7 +153,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 +163,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,12 +174,12 @@ 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--; - llist_delete(pos); + llist_delete(&pos->cakes); if (!pos->used_pieces) { llist_append(&pile->free, &pos->cakes); } else { diff --git a/lunaix-os/kernel/mm/region.c b/lunaix-os/kernel/mm/region.c index 1f706dc..920c35b 100644 --- a/lunaix-os/kernel/mm/region.c +++ b/lunaix-os/kernel/mm/region.c @@ -1,5 +1,5 @@ -#include #include +#include 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 }; diff --git a/lunaix-os/kernel/mm/valloc.c b/lunaix-os/kernel/mm/valloc.c index 631f39e..a744ed1 100644 --- a/lunaix-os/kernel/mm/valloc.c +++ b/lunaix-os/kernel/mm/valloc.c @@ -1,59 +1,61 @@ #include #include #include +#include -#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 diff --git a/lunaix-os/kernel/mm/vmap.c b/lunaix-os/kernel/mm/vmap.c index 5df524d..deb18d3 100644 --- a/lunaix-os/kernel/mm/vmap.c +++ b/lunaix-os/kernel/mm/vmap.c @@ -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) { diff --git a/lunaix-os/kernel/peripheral/ps2kbd.c b/lunaix-os/kernel/peripheral/ps2kbd.c index 6d27b10..6905b1e 100644 --- a/lunaix-os/kernel/peripheral/ps2kbd.c +++ b/lunaix-os/kernel/peripheral/ps2kbd.c @@ -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; diff --git a/lunaix-os/kernel/proc0.c b/lunaix-os/kernel/proc0.c index 759db2c..5fac5f8 100644 --- a/lunaix-os/kernel/proc0.c +++ b/lunaix-os/kernel/proc0.c @@ -1,5 +1,9 @@ #include +#include #include +#include +#include +#include #include #include #include @@ -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(); diff --git a/lunaix-os/kernel/process.c b/lunaix-os/kernel/process.c index a783efe..086a5e3 100644 --- a/lunaix-os/kernel/process.c +++ b/lunaix-os/kernel/process.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/lunaix-os/kernel/sched.c b/lunaix-os/kernel/sched.c index 8e089d6..f8f00d4 100644 --- a/lunaix-os/kernel/sched.c +++ b/lunaix-os/kernel/sched.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -144,6 +145,12 @@ redo: run(next); } +void +sched_yieldk() +{ + cpu_int(LUNAIX_SCHED); +} + __DEFINE_LXSYSCALL1(unsigned int, sleep, unsigned int, seconds) { if (!seconds) { @@ -202,6 +209,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) { @@ -213,7 +225,6 @@ _wait(pid_t wpid, int* status, int options) } wpid = wpid ? wpid : -__current->pgid; - cpu_enable_interrupt(); repeat: llist_for_each(proc, n, &__current->children, siblings) { @@ -232,11 +243,10 @@ repeat: return 0; } // 放弃当前的运行机会 - sched_yield(); + sched_yieldk(); goto repeat; done: - cpu_disable_interrupt(); status_flags |= PEXITSIG * (proc->sig_inprogress != 0); if (status) { *status = proc->exit_code | status_flags; @@ -267,8 +277,9 @@ 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->mm.regions.head); llist_init_head(&proc->children); llist_init_head(&proc->grp_member); llist_init_head(&proc->sleep.sleepers); @@ -282,7 +293,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,17 +316,25 @@ 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) { - lxfree(pos); + vfree(pos); } vmm_mount_pd(PD_MOUNT_1, proc->page_table); diff --git a/lunaix-os/kernel/service/pconsole.c b/lunaix-os/kernel/service/pconsole.c index be59c18..200303d 100644 --- a/lunaix-os/kernel/service/pconsole.c +++ b/lunaix-os/kernel/service/pconsole.c @@ -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(); diff --git a/lunaix-os/kernel/signal.c b/lunaix-os/kernel/signal.c index cb47e8d..5f0c868 100644 --- a/lunaix-os/kernel/signal.c +++ b/lunaix-os/kernel/signal.c @@ -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); @@ -188,11 +188,10 @@ __do_pause() { __current->flags |= PROC_FINPAUSE; - __SYSCALL_INTERRUPTIBLE({ - while ((__current->flags & PROC_FINPAUSE)) { - sched_yield(); - } - }) + while ((__current->flags & PROC_FINPAUSE)) { + sched_yieldk(); + } + __current->k_status = EINTR; } diff --git a/lunaix-os/kernel/syscall.c b/lunaix-os/kernel/syscall.c index ce0f2a7..5cee205 100644 --- a/lunaix-os/kernel/syscall.c +++ b/lunaix-os/kernel/syscall.c @@ -7,7 +7,7 @@ LOG_MODULE("SYSCALL") extern void -syscall_hndlr(isr_param* param); +syscall_hndlr(const isr_param* param); void syscall_install() diff --git a/lunaix-os/kernel/time/clock.c b/lunaix-os/kernel/time/clock.c index e862f79..15a6a32 100644 --- a/lunaix-os/kernel/time/clock.c +++ b/lunaix-os/kernel/time/clock.c @@ -1,33 +1,35 @@ -#include -#include #include +#include #include +#include 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(¤t, 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 diff --git a/lunaix-os/kernel/time/timer.c b/lunaix-os/kernel/time/timer.c index b9d333b..7d9a391 100644 --- a/lunaix-os/kernel/time/timer.c +++ b/lunaix-os/kernel/time/timer.c @@ -13,7 +13,8 @@ #include #include -#include +#include +#include #include #include #include @@ -42,19 +43,21 @@ 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)); - llist_init_head(timer_ctx->active_timers); + timer_ctx->active_timers = (struct lx_timer*)cake_grab(timer_pile); + llist_init_head(&timer_ctx->active_timers->link); } void @@ -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; @@ -176,7 +178,7 @@ timer_run(ticks_t ticks, void (*callback)(void*), void* payload, uint8_t flags) timer->payload = payload; timer->flags = flags; - llist_append(timer_ctx->active_timers, &timer->link); + llist_append(&timer_ctx->active_timers->link, &timer->link); return timer; } @@ -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); } } @@ -211,12 +213,6 @@ timer_update(const isr_param* param) } } -void -sched_yield() -{ - sched_ticks_counter = sched_ticks; -} - static void temp_intr_routine_rtc_tick(const isr_param* param) { diff --git a/lunaix-os/libs/crc.c b/lunaix-os/libs/crc.c new file mode 100644 index 0000000..06ebbac --- /dev/null +++ b/lunaix-os/libs/crc.c @@ -0,0 +1,68 @@ +#include + +// 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 index 0000000..277efb3 --- /dev/null +++ b/lunaix-os/libs/hash.c @@ -0,0 +1,24 @@ +#include + +/** + * @brief Simple string hash function + * + * ref: https://stackoverflow.com/a/7666577 + * + * @param str + * @return unsigned int + */ +uint32_t +strhash_32(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 diff --git a/lunaix-os/libs/klibc/stdio/sprintf.c b/lunaix-os/libs/klibc/stdio/sprintf.c index 460b206..d357068 100644 --- a/lunaix-os/libs/klibc/stdio/sprintf.c +++ b/lunaix-os/libs/klibc/stdio/sprintf.c @@ -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 index 0000000..736bb91 --- /dev/null +++ b/lunaix-os/libs/klibc/string/strcmp.c @@ -0,0 +1,14 @@ +#include + +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 diff --git a/lunaix-os/makefile b/lunaix-os/makefile index b997ccc..879304b 100644 --- a/lunaix-os/makefile +++ b/lunaix-os/makefile @@ -48,7 +48,7 @@ all-debug: clean $(BUILD_DIR)/$(OS_ISO) clean: @rm -rf $(BUILD_DIR) || exit 1 - @sleep 2 + @sleep 1 run: $(BUILD_DIR)/$(OS_ISO) @qemu-system-i386 -cdrom $(BUILD_DIR)/$(OS_ISO) $(QEMU_OPTIONS)