**/.~lock*
workspace/
**.odp
-
+drafts/
+ 内存管理与按需分页(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)
## 目录结构
1. `kill(2)`
1. `sigpending(2)`
1. `sigsuspend(2)`
+2. `read(2)`
+2. `write(2)`
+2. `open(2)`
+2. `close(2)`
+2. `mkdir(2)`
+2. `lseek(2)`
+2. `readdir(2)`
+2. `readlink(2)`
+2. `readlinkat(2)`
+2. `rmdir(2)`
+2. `unlink(2)`
+2. `unlinkat(2)`
+2. `link(2)`
+2. `fsync(2)`
+2. `dup(2)`
+2. `dup2(2)`
### LunaixOS自有
1. `yield`
+2. `geterrno`
## 附录2:编译gcc作为交叉编译器<a id="appendix2"></a>
.VSCodeCounter/
.idea
bx_enh_dbg.ini
-machine/
\ No newline at end of file
+machine/
+draft/
\ No newline at end of file
#include <hal/acpi/acpi.h>
-#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/valloc.h>
#include <lunaix/spike.h>
#include <lunaix/syslog.h>
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);
}
}
- 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*
#include "parser.h"
-#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/valloc.h>
void
madt_parse(acpi_madt_t* madt, acpi_context* toc)
// Cosidering only one IOAPIC present (max 24 pins)
// FIXME: use hash table instead
- toc->madt.irq_exception =
- (acpi_intso_t*)lxcalloc(24, sizeof(acpi_intso_t*));
+ toc->madt.irq_exception = (acpi_intso_t*)vcalloc(24, sizeof(acpi_intso_t*));
size_t so_idx = 0;
while (ics_start < ics_end) {
#include "lunaix/syslog.h"
#include "parser.h"
-#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/valloc.h>
LOG_MODULE("MCFG")
(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){
#include <hal/pci.h>
#include <klibc/string.h>
+#include <lunaix/block.h>
#include <lunaix/mm/mmio.h>
#include <lunaix/mm/pmm.h>
#include <lunaix/mm/valloc.h>
if (!ahci_init_device(port)) {
kprintf(KERROR "fail to init device");
}
+
+ block_mount_disk(port->device);
}
}
// 构建命令头(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));
// 清空任何待响应的中断
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;
#include <lunaix/spike.h>
int
-__sata_buffer_io(struct hba_port* port,
+__sata_buffer_io(struct hba_device* dev,
uint64_t lba,
void* buffer,
uint32_t size,
{
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);
}
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
}
void
-__scsi_buffer_io(struct hba_port* port,
+__scsi_buffer_io(struct hba_device* dev,
uint64_t lba,
void* buffer,
uint32_t size,
{
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);
}
void
-scsi_read_buffer(struct hba_port* port,
+scsi_read_buffer(struct hba_device* dev,
uint64_t lba,
void* buffer,
uint32_t size)
{
- __scsi_buffer_io(port, lba, buffer, size, 0);
+ __scsi_buffer_io(dev, lba, buffer, size, 0);
}
void
-scsi_write_buffer(struct hba_port* port,
+scsi_write_buffer(struct hba_device* dev,
uint64_t lba,
void* buffer,
uint32_t size)
{
- __scsi_buffer_io(port, lba, buffer, size, 1);
+ __scsi_buffer_io(dev, lba, buffer, size, 1);
}
\ No newline at end of file
#include <hal/acpi/acpi.h>
#include <hal/apic.h>
#include <hal/pci.h>
-#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/valloc.h>
#include <lunaix/spike.h>
#include <lunaix/syslog.h>
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,
}
// 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);
}
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);
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);
uint32_t alloc_size);
void
-scsi_read_buffer(struct hba_port* port,
+scsi_read_buffer(struct hba_device* dev,
uint64_t lba,
void* buffer,
uint32_t size);
void
-scsi_write_buffer(struct hba_port* port,
+scsi_write_buffer(struct hba_device* dev,
uint64_t lba,
void* buffer,
uint32_t size);
#include <stdarg.h>
#include <stddef.h>
-void
+size_t
__sprintf_internal(char* buffer, char* fmt, size_t max_len, va_list vargs);
-void sprintf(char* buffer, char* fmt, ...);
-void snprintf(char* buffer, size_t n, char* fmt, ...);
+size_t
+sprintf(char* buffer, char* fmt, ...);
+size_t
+snprintf(char* buffer, size_t n, char* fmt, ...);
#endif /* __LUNAIX_STDIO_H */
const char*
strchr(const char* str, int character);
+int
+streq(const char* a, const char* b);
+
#endif /* __LUNAIX_STRING_H */
--- /dev/null
+#ifndef __LUNAIX_CRC_H
+#define __LUNAIX_CRC_H
+unsigned int
+crc32b(unsigned char* data, unsigned int size);
+
+#endif /* __LUNAIX_CRC_H */
--- /dev/null
+#ifndef __LUNAIX_HASH_H
+#define __LUNAIX_HASH_H
+
+#include <stdint.h>
+
+#define HASH_SIZE_BITS 32
+
+uint32_t
+strhash_32(unsigned char* str, uint32_t truncate_to);
+
+/**
+ * @brief Simple generic hash function
+ *
+ * ref:
+ * https://elixir.bootlin.com/linux/v5.18.12/source/include/linux/hash.h#L60
+ *
+ * @param val
+ * @return uint32_t
+ */
+inline uint32_t
+hash_32(uint32_t val, uint32_t truncate_to)
+{
+ return (val * 0x61C88647u) >> (HASH_SIZE_BITS - truncate_to);
+}
+
+#endif /* __LUNAIX_HASH_H */
--- /dev/null
+#ifndef __LUNAIX_BLOCK_H
+#define __LUNAIX_BLOCK_H
+
+#include <hal/ahci/hba.h>
+#include <lunaix/device.h>
+
+#define LPT_SIG 0x414e554c
+#define PARTITION_NAME_SIZE 48
+#define DEV_ID_SIZE 32
+
+typedef uint64_t partition_t;
+typedef uint32_t bdev_t;
+
+struct block_dev
+{
+ char bdev_id[DEV_ID_SIZE];
+ char name[PARTITION_NAME_SIZE];
+ struct hba_device* hd_dev;
+ struct device* dev;
+ uint64_t base_lba;
+ uint64_t end_lba;
+};
+
+struct lpt_entry
+{
+ char part_name[PARTITION_NAME_SIZE];
+ uint64_t base_lba;
+ uint64_t end_lba;
+} __attribute__((packed));
+
+// Lunaix Partition Table
+struct lpt_header
+{
+ uint32_t signature;
+ uint32_t crc;
+ uint32_t pt_start_lba;
+ uint32_t pt_end_lba;
+ uint32_t table_len;
+} __attribute__((packed));
+
+void
+block_init();
+
+int
+block_mount_disk(struct hba_device* hd_dev);
+
+#endif /* __LUNAIX_BLOCK_H */
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;
void
clock_init();
-void
+void
clock_walltime(datetime_t* datetime);
int
/**
* @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 */
#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
--- /dev/null
+#ifndef __LUNAIX_DEVICE_H
+#define __LUNAIX_DEVICE_H
+
+#define DEVICE_NAME_SIZE 32
+
+#include <lunaix/ds/hstr.h>
+#include <lunaix/ds/llist.h>
+
+struct device
+{
+ struct llist_header dev_list;
+ struct device* parent;
+ struct hstr name;
+ char name_val[DEVICE_NAME_SIZE];
+ void* underlay;
+ void* fs_node;
+ int (*read)(struct device* dev,
+ void* buf,
+ unsigned int offset,
+ unsigned int len);
+ int (*write)(struct device* dev,
+ void* buf,
+ unsigned int offset,
+ unsigned int len);
+};
+
+void
+device_init();
+
+struct device*
+device_addseq(struct device* parent, void* underlay, char* name_fmt, ...);
+
+struct device*
+device_addvol(struct device* parent, void* underlay, char* name_fmt, ...);
+
+void
+device_remove(struct device* dev);
+
+#endif /* __LUNAIX_DEVICE_H */
--- /dev/null
+#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 */
--- /dev/null
+#ifndef __LUNAIX_SPARSE_H
+#define __LUNAIX_SPARSE_H
+
+#include <lunaix/ds/llist.h>
+#include <lunaix/types.h>
+
+#define BTRIE_BITS 4
+
+struct btrie
+{
+ struct btrie_node* btrie_root;
+ int truncated;
+};
+
+struct btrie_node
+{
+ struct llist_header children;
+ struct llist_header siblings;
+ struct llist_header nodes;
+ struct btrie_node* parent;
+ uint32_t index;
+ void* data;
+};
+
+void
+btrie_init(struct btrie* btrie, uint32_t trunc_bits);
+
+void*
+btrie_get(struct btrie* root, uint32_t index);
+
+void
+btrie_set(struct btrie* root, uint32_t index, void* data);
+
+void*
+btrie_remove(struct btrie* root, uint32_t index);
+
+void
+btrie_release(struct btrie* tree);
+
+#endif /* __LUNAIX_SPARSE_H */
--- /dev/null
+#ifndef __LUNAIX_FIFO_BUF_H
+#define __LUNAIX_FIFO_BUF_H
+
+#include <lunaix/ds/mutex.h>
+#include <lunaix/types.h>
+
+#define FIFO_DIRTY 1
+
+struct fifo_buf
+{
+ void* data;
+ size_t wr_pos;
+ size_t rd_pos;
+ size_t size;
+ size_t free_len;
+ size_t flags;
+ mutex_t lock;
+};
+
+int
+fifo_backone(struct fifo_buf* fbuf);
+
+size_t
+fifo_putone(struct fifo_buf* fbuf, uint8_t data);
+
+void
+fifo_init(struct fifo_buf* buf, void* data_buffer, size_t buf_size, int flags);
+
+size_t
+fifo_write(struct fifo_buf* fbuf, void* data, size_t count);
+
+size_t
+fifo_read(struct fifo_buf* fbuf, void* buf, size_t count);
+
+#endif /* __LUNAIX_FIFO_BUF_H */
+++ /dev/null
-#ifndef __LUNAIX_FIFO_BUF_H
-#define __LUNAIX_FIFO_BUF_H
-
-#include <lunaix/ds/mutex.h>
-
-#define FIFO_DIRTY 1
-
-struct fifo_buffer
-{
- void* data;
- unsigned int wr_pos;
- unsigned int rd_pos;
- unsigned int size;
- unsigned int flags;
- mutex_t lock;
-};
-
-#endif /* __LUNAIX_FIFO_BUF_H */
--- /dev/null
+/**
+ * @file hashtable.h Simple hash table implementation.
+ * Based on
+ * https://elixir.bootlin.com/linux/v5.18.12/source/include/linux/hashtable.h
+ * @author Lunaixsky (zelong56@gmail.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-07-20
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+#ifndef __LUNAIX_HASHTABLE_H
+#define __LUNAIX_HASHTABLE_H
+
+#include <lib/hash.h>
+#include <lunaix/ds/llist.h>
+
+struct hbucket
+{
+ struct hlist_node* head;
+};
+
+#define __hashkey(table, hash) (hash % (sizeof(table) / sizeof(table[0])))
+
+#define DECLARE_HASHTABLE(name, bucket_num) struct hbucket name[bucket_num];
+
+#define hashtable_bucket_foreach(bucket, pos, n, member) \
+ for (pos = list_entry((bucket)->head, typeof(*pos), member); \
+ pos && ({ \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ 1; \
+ }); \
+ pos = n)
+
+#define hashtable_hash_foreach(table, hash, pos, n, member) \
+ hashtable_bucket_foreach(&table[__hashkey(table, hash)], pos, n, member)
+
+#define hashtable_init(table) \
+ { \
+ for (int i = 0; i < (sizeof(table) / sizeof(table[0])); i++) { \
+ table[i].head = 0; \
+ } \
+ }
+
+#define hashtable_hash_in(table, list_node, hash) \
+ hlist_add(&table[__hashkey(table, hash)].head, list_node)
+
+#endif /* __LUNAIX_HASHTABLE_H */
--- /dev/null
+#ifndef __LUNAIX_HSTR_H
+#define __LUNAIX_HSTR_H
+
+#include <lib/hash.h>
+
+#define HSTR_FULL_HASH 32
+
+struct hstr
+{
+ unsigned int hash;
+ unsigned int len;
+ char* value;
+};
+
+#define HSTR(str, length) \
+ (struct hstr) \
+ { \
+ .len = (length), .value = (str) \
+ }
+
+#define HHSTR(str, length, strhash) \
+ (struct hstr) \
+ { \
+ .len = (length), .value = (str), .hash = (strhash) \
+ }
+
+#define HSTR_EQ(str1, str2) ((str1)->hash == (str2)->hash)
+
+inline void
+hstr_rehash(struct hstr* hash_str, unsigned int truncate_to)
+{
+ hash_str->hash = strhash_32(hash_str->value, truncate_to);
+}
+
+#endif /* __LUNAIX_HSTR_H */
&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 */
--- /dev/null
+#ifndef __LUNAIX_FCTRL_H
+#define __LUNAIX_FCTRL_H
+
+#include <lunaix/dirent.h>
+#include <lunaix/syscall.h>
+#include <stddef.h>
+
+__LXSYSCALL2(int, open, const char*, path, int, options)
+
+__LXSYSCALL1(int, mkdir, const char*, path)
+__LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname)
+
+__LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent)
+
+__LXSYSCALL4(int,
+ readlinkat,
+ int,
+ dirfd,
+ const char*,
+ pathname,
+ char*,
+ buf,
+ size_t,
+ size)
+
+__LXSYSCALL3(int, realpathat, int, fd, char*, buf, size_t, size)
+
+#endif /* __LUNAIX_FCTRL_H */
--- /dev/null
+#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 */
--- /dev/null
+#ifndef __LUNAIX_VFS_H
+#define __LUNAIX_VFS_H
+
+#include <hal/ahci/hba.h>
+#include <lunaix/block.h>
+#include <lunaix/clock.h>
+#include <lunaix/ds/btrie.h>
+#include <lunaix/ds/hashtable.h>
+#include <lunaix/ds/hstr.h>
+#include <lunaix/ds/llist.h>
+#include <lunaix/status.h>
+
+#define VFS_NAME_MAXLEN 128
+#define VFS_MAX_FD 32
+
+#define VFS_IFDIR 0x1
+#define VFS_IFFILE 0x2
+#define VFS_IFSEQDEV 0x4
+#define VFS_IFVOLDEV 0x8
+#define VFS_IFSYMLINK 0x16
+
+#define VFS_WALK_MKPARENT 0x1
+#define VFS_WALK_FSRELATIVE 0x2
+#define VFS_WALK_PARENT 0x4
+#define VFS_WALK_NOFOLLOW 0x4
+
+#define FSTYPE_ROFS 0x1
+
+#define VFS_VALID_CHAR(chr) \
+ ('A' <= (chr) && (chr) <= 'Z' || 'a' <= (chr) && (chr) <= 'z' || \
+ '0' <= (chr) && (chr) <= '9' || (chr) == '.' || (chr) == '_' || \
+ (chr) == '-')
+
+extern struct hstr vfs_ddot;
+extern struct hstr vfs_dot;
+
+struct v_dnode;
+struct pcache;
+
+struct filesystem
+{
+ struct hlist_node fs_list;
+ struct hstr fs_name;
+ uint32_t types;
+ int (*mount)(struct v_superblock* vsb, struct v_dnode* mount_point);
+ int (*unmount)(struct v_superblock* vsb);
+};
+
+struct v_superblock
+{
+ struct llist_header sb_list;
+ int fs_id;
+ bdev_t dev;
+ struct v_dnode* root;
+ struct filesystem* fs;
+ uint32_t iobuf_size;
+ struct
+ {
+ uint32_t (*read_capacity)(struct v_superblock* vsb);
+ uint32_t (*read_usage)(struct v_superblock* vsb);
+ } ops;
+};
+
+struct dir_context
+{
+ int index;
+ void* cb_data;
+ void (*read_complete_callback)(struct dir_context* dctx,
+ const char* name,
+ const int len,
+ const int dtype);
+};
+
+struct v_file_ops
+{
+ int (*write)(struct v_file* file, void* buffer, size_t len, size_t fpos);
+ int (*read)(struct v_file* file, void* buffer, size_t len, size_t fpos);
+ int (*readdir)(struct v_file* file, struct dir_context* dctx);
+ int (*seek)(struct v_file* file, size_t offset);
+ int (*rename)(struct v_file* file, char* new_name);
+ int (*close)(struct v_file* file);
+ int (*sync)(struct v_file* file);
+};
+
+struct v_file
+{
+ struct v_inode* inode;
+ struct v_dnode* dnode;
+ struct llist_header* f_list;
+ uint32_t f_pos;
+ uint32_t ref_count;
+ void* data; // 允许底层FS绑定他的一些专有数据
+ struct v_file_ops ops;
+};
+
+struct v_fd
+{
+ struct v_file* file;
+ int flags;
+};
+
+struct v_inode
+{
+ uint32_t itype;
+ time_t ctime;
+ time_t mtime;
+ time_t atime;
+ lba_t lb_addr;
+ uint32_t open_count;
+ uint32_t link_count;
+ uint32_t lb_usage;
+ uint32_t fsize;
+ struct pcache* pg_cache;
+ void* data; // 允许底层FS绑定他的一些专有数据
+ struct
+ {
+ int (*create)(struct v_inode* this);
+ int (*open)(struct v_inode* this, struct v_file* file);
+ int (*sync)(struct v_inode* this);
+ int (*mkdir)(struct v_inode* this, struct v_dnode* dnode);
+ int (*rmdir)(struct v_inode* this);
+ int (*unlink)(struct v_inode* this);
+ int (*link)(struct v_inode* this, struct v_dnode* new_name);
+ int (*read_symlink)(struct v_inode* this, const char** path_out);
+ int (*symlink)(struct v_inode* this, const char* target);
+ int (*dir_lookup)(struct v_inode* this, struct v_dnode* dnode);
+ } ops;
+ struct v_file_ops default_fops;
+};
+
+struct v_dnode
+{
+ struct hstr name;
+ struct v_inode* inode;
+ struct v_dnode* parent;
+ struct hlist_node hash_list;
+ struct llist_header children;
+ struct llist_header siblings;
+ struct v_superblock* super_block;
+ struct
+ {
+ void (*destruct)(struct v_dnode* dnode);
+ } ops;
+};
+
+struct v_fdtable
+{
+ struct v_fd* fds[VFS_MAX_FD];
+};
+
+struct pcache_pg
+{
+ struct llist_header pg_list;
+ struct llist_header dirty_list;
+ void* pg;
+ uint32_t flags;
+ uint32_t fpos;
+};
+
+struct pcache
+{
+ struct btrie tree;
+ struct llist_header pages;
+ struct llist_header dirty;
+ uint32_t n_dirty;
+ uint32_t n_pages;
+};
+
+/* --- file system manager --- */
+void
+fsm_init();
+
+void
+fsm_register(struct filesystem* fs);
+
+struct filesystem*
+fsm_get(const char* fs_name);
+
+void
+vfs_init();
+
+struct v_dnode*
+vfs_dcache_lookup(struct v_dnode* parent, struct hstr* str);
+
+void
+vfs_dcache_add(struct v_dnode* parent, struct v_dnode* dnode);
+
+int
+vfs_walk(struct v_dnode* start,
+ const char* path,
+ struct v_dnode** dentry,
+ struct hstr* component,
+ int walk_options);
+
+int
+vfs_mount(const char* target, const char* fs_name, bdev_t device);
+
+int
+vfs_unmount(const char* target);
+
+int
+vfs_mount_at(const char* fs_name, bdev_t device, struct v_dnode* mnt_point);
+
+int
+vfs_unmount_at(struct v_dnode* mnt_point);
+
+int
+vfs_mkdir(const char* path, struct v_dnode** dentry);
+
+int
+vfs_open(struct v_dnode* dnode, struct v_file** file);
+
+int
+vfs_close(struct v_file* file);
+
+int
+vfs_fsync(struct v_file* file);
+
+struct v_superblock*
+vfs_sb_alloc();
+
+void
+vfs_sb_free(struct v_superblock* sb);
+
+struct v_dnode*
+vfs_d_alloc();
+
+void
+vfs_d_free(struct v_dnode* dnode);
+
+struct v_inode*
+vfs_i_alloc();
+
+void
+vfs_i_free(struct v_inode* inode);
+
+int
+vfs_dup_fd(struct v_fd* old, struct v_fd** new);
+
+void
+pcache_init(struct pcache* pcache);
+
+void
+pcache_release_page(struct pcache* pcache, struct pcache_pg* page);
+
+struct pcache_pg*
+pcache_new_page(struct pcache* pcache, uint32_t index);
+
+void
+pcache_set_dirty(struct pcache* pcache, struct pcache_pg* pg);
+
+struct pcache_pg*
+pcache_get_page(struct pcache* pcache,
+ uint32_t index,
+ uint32_t* offset,
+ struct pcache_pg** page);
+
+int
+pcache_write(struct v_file* file, void* data, uint32_t len, uint32_t fpos);
+
+int
+pcache_read(struct v_file* file, void* data, uint32_t len, uint32_t fpos);
+
+void
+pcache_release(struct pcache* pcache);
+
+int
+pcache_commit(struct v_file* file, struct pcache_pg* page);
+
+void
+pcache_invalidate(struct v_file* file, struct pcache_pg* page);
+
+void
+pcache_commit_all(struct v_file* file);
+#endif /* __LUNAIX_VFS_H */
--- /dev/null
+#ifndef __LUNAIX_TWIFS_H
+#define __LUNAIX_TWIFS_H
+
+#include <lunaix/fs.h>
+
+struct twifs_node
+{
+ struct v_inode* inode;
+ struct hstr name;
+ void* data;
+ uint32_t itype;
+ struct llist_header children;
+ struct llist_header siblings;
+ struct
+ {
+ int (*write)(struct v_file* file,
+ void* buffer,
+ size_t len,
+ size_t fpos);
+ int (*read)(struct v_file* file, void* buffer, size_t len, size_t fpos);
+ } ops;
+};
+
+void
+twifs_init();
+
+struct twifs_node*
+twifs_file_node(struct twifs_node* parent,
+ const char* name,
+ int name_len,
+ uint32_t itype);
+
+struct twifs_node*
+twifs_dir_node(struct twifs_node* parent,
+ const char* name,
+ int name_len,
+ uint32_t itype);
+
+struct twifs_node*
+twifs_toplevel_node(const char* name, int name_len, uint32_t itype);
+
+int
+twifs_rm_node(struct twifs_node* node);
+
+#endif /* __LUNAIX_TWIFS_H */
#include <lunaix/syscall.h>
#include <lunaix/types.h>
+#include <stddef.h>
__LXSYSCALL(pid_t, fork)
__LXSYSCALL1(unsigned int, alarm, unsigned int, seconds)
+__LXSYSCALL2(int, link, const char*, oldpath, const char*, newpath)
+
+__LXSYSCALL1(int, rmdir, const char*, pathname)
+
+__LXSYSCALL3(int, read, int, fd, void*, buf, unsigned int, count)
+
+__LXSYSCALL3(int, write, int, fd, void*, buf, unsigned int, count)
+
+__LXSYSCALL3(int, readlink, const char*, path, char*, buf, size_t, size)
+
+__LXSYSCALL3(int, lseek, int, fd, int, offset, int, options)
+
+__LXSYSCALL1(int, unlink, const char*, pathname)
+
+__LXSYSCALL1(int, close, int, fd)
+
+__LXSYSCALL2(int, dup2, int, oldfd, int, newfd)
+
+__LXSYSCALL1(int, dup, int, oldfd)
+
+__LXSYSCALL1(int, fsync, int, fildes)
+
+__LXSYSCALL2(int, symlink, const char*, pathname, const char*, link_target)
+
#endif /* __LUNAIX_UNISTD_H */
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);
valloc_dma(unsigned int size);
void*
-vcalloc_dma(unsigned int size);
+vzalloc_dma(unsigned int size);
void
vfree_dma(void* ptr);
#define __LUNAIX_PS2KBD_H
#include <hal/io.h>
-#include <lunaix/keyboard.h>
#include <lunaix/ds/mutex.h>
-
+#include <lunaix/keyboard.h>
#define PS2_PORT_ENC_DATA 0x60
#define PS2_PORT_ENC_CMDREG 0x60
#define PS2_PORT_CTRL_STATUS 0x64
#define PS2_PORT_CTRL_CMDREG 0x64
-#define PS2_STATUS_OFULL 0x1
-#define PS2_STATUS_IFULL 0x2
+#define PS2_STATUS_OFULL 0x1
+#define PS2_STATUS_IFULL 0x2
-#define PS2_RESULT_ACK 0xfa
-#define PS2_RESULT_NAK 0xfe //resend
-#define PS2_RESULT_ECHO 0xee
-#define PS2_RESULT_TEST_OK 0x55
+#define PS2_RESULT_ACK 0xfa
+#define PS2_RESULT_NAK 0xfe // resend
+#define PS2_RESULT_ECHO 0xee
+#define PS2_RESULT_TEST_OK 0x55
// PS/2 keyboard device related commands
-#define PS2_KBD_CMD_SETLED 0xed
-#define PS2_KBD_CMD_ECHO 0xee
-#define PS2_KBD_CMD_SCANCODE_SET 0xf0
-#define PS2_KBD_CMD_IDENTIFY 0xf2
-#define PS2_KBD_CMD_SCAN_ENABLE 0xf4
-#define PS2_KBD_CMD_SCAN_DISABLE 0xf5
+#define PS2_KBD_CMD_SETLED 0xed
+#define PS2_KBD_CMD_ECHO 0xee
+#define PS2_KBD_CMD_SCANCODE_SET 0xf0
+#define PS2_KBD_CMD_IDENTIFY 0xf2
+#define PS2_KBD_CMD_SCAN_ENABLE 0xf4
+#define PS2_KBD_CMD_SCAN_DISABLE 0xf5
// PS/2 *controller* related commands
-#define PS2_CMD_PORT1_DISABLE 0xad
-#define PS2_CMD_PORT1_ENABLE 0xae
-#define PS2_CMD_PORT2_DISABLE 0xa7
-#define PS2_CMD_PORT2_ENABLE 0xa8
-#define PS2_CMD_SELFTEST 0xaa
-#define PS2_CMD_SELFTEST_PORT1 0xab
+#define PS2_CMD_PORT1_DISABLE 0xad
+#define PS2_CMD_PORT1_ENABLE 0xae
+#define PS2_CMD_PORT2_DISABLE 0xa7
+#define PS2_CMD_PORT2_ENABLE 0xa8
+#define PS2_CMD_SELFTEST 0xaa
+#define PS2_CMD_SELFTEST_PORT1 0xab
-#define PS2_CMD_READ_CFG 0x20
-#define PS2_CMD_WRITE_CFG 0x60
+#define PS2_CMD_READ_CFG 0x20
+#define PS2_CMD_WRITE_CFG 0x60
-#define PS2_CFG_P1INT 0x1
-#define PS2_CFG_P2INT 0x2
-#define PS2_CFG_TRANSLATION 0x40
+#define PS2_CFG_P1INT 0x1
+#define PS2_CFG_P2INT 0x2
+#define PS2_CFG_TRANSLATION 0x40
-#define PS2_DELAY 1000
+#define PS2_DELAY 1000
#define PS2_CMD_QUEUE_SIZE 8
#define PS2_KBD_RECV_BUFFER_SIZE 8
#define PS2_NO_ARG 0xff00
-
-struct ps2_cmd {
+struct ps2_cmd
+{
char cmd;
char arg;
};
-struct ps2_kbd_state {
+struct ps2_kbd_state
+{
volatile char state;
volatile char masked;
+ volatile kbd_kstate_t key_state;
kbd_keycode_t* translation_table;
- kbd_kstate_t key_state;
};
-struct ps2_cmd_queue {
+struct ps2_cmd_queue
+{
struct ps2_cmd cmd_queue[PS2_CMD_QUEUE_SIZE];
int queue_ptr;
int queue_len;
mutex_t mutex;
};
-struct ps2_key_buffer {
+struct ps2_key_buffer
+{
struct kdb_keyinfo_pkt buffer[PS2_KBD_RECV_BUFFER_SIZE];
int read_ptr;
int buffered_len;
* @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 */
__LXSYSCALL3(pid_t, waitpid, pid_t, pid, int*, status, int, options);
+__LXSYSCALL(int, geterrno);
+
#endif /* __LUNAIX_SYS_H */
#include <arch/x86/interrupts.h>
#include <lunaix/clock.h>
+#include <lunaix/fs.h>
#include <lunaix/mm/mm.h>
#include <lunaix/signal.h>
#include <lunaix/timer.h>
sigset_t sig_inprogress;
int flags;
void* sig_handler[_SIG_NUM];
+ struct v_fdtable* fdtable;
pid_t pgid;
};
// Some helper functions. As helpful as Spike the Dragon! :)
-// 除法向上取整
+// 除法 v/(2^k) 向上取整
#define CEIL(v, k) (((v) + (1 << (k)) - 1) >> (k))
#define ICEIL(x, y) ((x) / (y) + ((x) % (y) != 0))
-// 除法向下取整
+// 除法 v/(2^k) 向下取整
#define FLOOR(v, k) ((v) >> (k))
// 获取v最近的最大k倍数
// 获取v最近的最小k倍数
#define ROUNDDOWN(v, k) ((v) & ~((k)-1))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+/**
+ * @brief Fast log base 2 for integer, utilizing constant unfolding.
+ * Adopted from
+ * https://elixir.bootlin.com/linux/v4.4/source/include/linux/log2.h#L85
+ *
+ */
+#define ILOG2(x) \
+ __builtin_constant_p(x) ? ((x) == 0 ? 0 \
+ : ((x) & (1ul << 31)) ? 31 \
+ : ((x) & (1ul << 30)) ? 30 \
+ : ((x) & (1ul << 29)) ? 29 \
+ : ((x) & (1ul << 28)) ? 28 \
+ : ((x) & (1ul << 27)) ? 27 \
+ : ((x) & (1ul << 26)) ? 26 \
+ : ((x) & (1ul << 25)) ? 25 \
+ : ((x) & (1ul << 24)) ? 24 \
+ : ((x) & (1ul << 23)) ? 23 \
+ : ((x) & (1ul << 22)) ? 22 \
+ : ((x) & (1ul << 21)) ? 21 \
+ : ((x) & (1ul << 20)) ? 20 \
+ : ((x) & (1ul << 19)) ? 19 \
+ : ((x) & (1ul << 18)) ? 18 \
+ : ((x) & (1ul << 17)) ? 17 \
+ : ((x) & (1ul << 16)) ? 16 \
+ : ((x) & (1ul << 15)) ? 15 \
+ : ((x) & (1ul << 14)) ? 14 \
+ : ((x) & (1ul << 13)) ? 13 \
+ : ((x) & (1ul << 12)) ? 12 \
+ : ((x) & (1ul << 11)) ? 11 \
+ : ((x) & (1ul << 10)) ? 10 \
+ : ((x) & (1ul << 9)) ? 9 \
+ : ((x) & (1ul << 8)) ? 8 \
+ : ((x) & (1ul << 7)) ? 7 \
+ : ((x) & (1ul << 6)) ? 6 \
+ : ((x) & (1ul << 5)) ? 5 \
+ : ((x) & (1ul << 4)) ? 4 \
+ : ((x) & (1ul << 3)) ? 3 \
+ : ((x) & (1ul << 2)) ? 2 \
+ : ((x) & (1ul << 1)) ? 1 \
+ : 0) \
+ : (31 - __builtin_clz(x))
+
#define __USER__ __attribute__((section(".usrtext")))
inline static void
#define LXHEAPFULL -(2)
#define LXINVLDPTR -(2)
#define LXOUTOFMEM -(3)
-#define LXINVLDPID -(4)
#define LXSEGFAULT -(5)
-#define LXINVL -(6)
+#define EINVAL -(6)
#define EINTR -(7)
+#define EMFILE -8
+#define ENOENT -9
+#define ENAMETOOLONG -10
+#define ENOTDIR -11
+#define EEXIST -12
+#define EBADF -13
+#define ENOTSUP -14
+#define ENXIO -15
+#define ELOOP -16
+#define ENOTEMPTY -17
+#define EROFS -18
+#define EISDIR -19
+#define EBUSY -20
+#define EXDEV -21
+#define ELOOP -22
+#define ENODEV -23
+
#endif /* __LUNAIX_CODE_H */
#define __SYSCALL__exit 8
#define __SYSCALL_wait 9
#define __SYSCALL_waitpid 10
+
#define __SYSCALL_sigreturn 11
#define __SYSCALL_sigprocmask 12
#define __SYSCALL_signal 13
#define __SYSCALL_alarm 16
#define __SYSCALL_sigpending 17
#define __SYSCALL_sigsuspend 18
+#define __SYSCALL_open 19
+#define __SYSCALL_close 20
+
+#define __SYSCALL_read 21
+#define __SYSCALL_write 22
+#define __SYSCALL_readdir 23
+#define __SYSCALL_mkdir 24
+#define __SYSCALL_lseek 25
+#define __SYSCALL_geterrno 26
+#define __SYSCALL_readlink 27
+#define __SYSCALL_readlinkat 28
+#define __SYSCALL_rmdir 29
+
+#define __SYSCALL_unlink 30
+#define __SYSCALL_unlinkat 31
+#define __SYSCALL_link 32
+#define __SYSCALL_fsync 33
+#define __SYSCALL_dup 34
+#define __SYSCALL_dup2 35
+#define __SYSCALL_realpathat 36
+#define __SYSCALL_symlink 37
#define __SYSCALL_MAX 0x100
#ifndef __ASM__
+
+#define SYSCALL_ESTATUS(errno) -((errno) != 0)
+
void
syscall_install();
}
#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) \
#ifndef __LUNAIX_CONSOLE_H
#define __LUNAIX_CONSOLE_H
-#include <lunaix/ds/fifobuf.h>
+#include <lunaix/ds/fifo.h>
#include <lunaix/timer.h>
struct console
{
struct lx_timer* flush_timer;
- struct fifo_buffer buffer;
+ struct fifo_buf output;
+ struct fifo_buf input;
unsigned int erd_pos;
unsigned int lines;
};
#ifndef __LUNAIX_TYPES_H
#define __LUNAIX_TYPES_H
+#include <stddef.h>
#include <stdint.h>
#define PEXITTERM 0x100
// TODO: WTERMSIG
typedef int32_t pid_t;
+typedef int64_t lba_t;
#endif /* __LUNAIX_TYPES_H */
.long __lxsys_alarm
.long __lxsys_sigpending
.long __lxsys_sigsuspend
+ .long __lxsys_open
+ .long __lxsys_close /* 20 */
+ .long __lxsys_read
+ .long __lxsys_write
+ .long __lxsys_readdir
+ .long __lxsys_mkdir
+ .long __lxsys_lseek /* 25 */
+ .long __lxsys_geterrno
+ .long __lxsys_readlink
+ .long __lxsys_readlinkat
+ .long __lxsys_rmdir
+ .long __lxsys_unlink /* 30 */
+ .long __lxsys_unlinkat
+ .long __lxsys_link
+ .long __lxsys_fsync
+ .long __lxsys_dup
+ .long __lxsys_dup2
+ .long __lxsys_realpathat
+ .long __lxsys_symlink
2:
.rept __SYSCALL_MAX - (2b - 1b)/4
.long 0
--- /dev/null
+#include <hal/ahci/hba.h>
+#include <klibc/stdio.h>
+#include <klibc/string.h>
+#include <lib/crc.h>
+#include <lunaix/block.h>
+#include <lunaix/fs/twifs.h>
+#include <lunaix/mm/cake.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/syslog.h>
+
+#include <lunaix/spike.h>
+
+#define BLOCK_EREAD 1
+#define BLOCK_ESIG 2
+#define BLOCK_ECRC 3
+#define BLOCK_EFULL 3
+
+LOG_MODULE("BLOCK")
+
+#define MAX_DEV 32
+
+struct cake_pile* lbd_pile;
+struct block_dev** dev_registry;
+
+int free_slot = 0;
+
+int
+__block_mount_partitions(struct hba_device* hd_dev);
+
+int
+__block_register(struct block_dev* dev);
+
+void
+block_init()
+{
+ lbd_pile = cake_new_pile("block_dev", sizeof(struct block_dev), 1, 0);
+ dev_registry = vcalloc(sizeof(struct block_dev*), MAX_DEV);
+ free_slot = 0;
+}
+
+int
+__block_read(struct device* dev,
+ void* buf,
+ unsigned int offset,
+ unsigned int len)
+{
+ int errno;
+ struct block_dev* bdev = (struct block_dev*)dev->underlay;
+ size_t acc_size = 0, rd_size = 0, bsize = bdev->hd_dev->block_size,
+ rd_block = offset / bsize, r = offset % bsize;
+ void* block = vzalloc(bsize);
+
+ while (acc_size < len) {
+ if (!bdev->hd_dev->ops.read_buffer(
+ bdev->hd_dev, rd_block, block, bsize)) {
+ errno = ENXIO;
+ goto error;
+ }
+ rd_size = MIN(len - acc_size, bsize - r);
+ memcpy(buf + acc_size, block + r, rd_size);
+ acc_size += rd_size;
+ r = 0;
+ rd_block++;
+ }
+
+ vfree(block);
+ return rd_block;
+
+error:
+ vfree(block);
+ return errno;
+}
+
+int
+__block_write(struct device* dev,
+ void* buf,
+ unsigned int offset,
+ unsigned int len)
+{
+ int errno;
+ struct block_dev* bdev = (struct block_dev*)dev->underlay;
+ size_t acc_size = 0, wr_size = 0, bsize = bdev->hd_dev->block_size,
+ wr_block = offset / bsize, r = offset % bsize;
+ void* block = vzalloc(bsize);
+
+ while (acc_size < len) {
+ wr_size = MIN(len - acc_size, bsize - r);
+ memcpy(block + r, buf + acc_size, wr_size);
+ if (!bdev->hd_dev->ops.write_buffer(
+ bdev->hd_dev, wr_block, block, bsize)) {
+ errno = ENXIO;
+ break;
+ }
+ acc_size += wr_size;
+ r = 0;
+ wr_block++;
+ }
+
+ vfree(block);
+ return wr_block;
+
+error:
+ vfree(block);
+ return errno;
+}
+
+int
+block_mount_disk(struct hba_device* hd_dev)
+{
+ int errno = 0;
+ struct block_dev* bdev = cake_grab(lbd_pile);
+ strncpy(bdev->name, hd_dev->model, PARTITION_NAME_SIZE);
+ bdev->hd_dev = hd_dev;
+ bdev->base_lba = 0;
+ bdev->end_lba = hd_dev->max_lba;
+ if (!__block_register(bdev)) {
+ errno = BLOCK_EFULL;
+ goto error;
+ }
+
+ return errno;
+
+error:
+ kprintf(KERROR "Fail to mount hd: %s[%s] (%x)\n",
+ hd_dev->model,
+ hd_dev->serial_num,
+ -errno);
+}
+
+int
+__block_register(struct block_dev* bdev)
+{
+ if (free_slot >= MAX_DEV) {
+ return 0;
+ }
+
+ struct device* dev = device_addvol(NULL, bdev, "sd%c", 'a' + free_slot);
+ dev->write = __block_write;
+ dev->read = __block_read;
+
+ bdev->dev = dev;
+ dev_registry[free_slot++] = bdev;
+ return 1;
+}
\ No newline at end of file
--- /dev/null
+#include <lunaix/dirent.h>
+#include <lunaix/fctrl.h>
+#include <lunaix/lunistd.h>
+#include <lunaix/proc.h>
+#include <lunaix/syslog.h>
+
+LOG_MODULE("RDDIR")
+
+void
+_readdir_main()
+{
+ int fd = open("/dev/./../dev/.", 0);
+ if (fd == -1) {
+ kprintf(KERROR "fail to open (%d)\n", geterrno());
+ return;
+ }
+
+ char path[129];
+ int len = realpathat(fd, path, 128);
+ if (len < 0) {
+ kprintf(KERROR "fail to read (%d)\n", geterrno());
+ } else {
+ path[len] = 0;
+ kprintf("%s\n", path);
+ }
+
+ struct dirent ent = { .d_offset = 0 };
+
+ while (!readdir(fd, &ent)) {
+ kprintf(KINFO "%s\n", ent.d_name);
+ }
+
+ close(fd);
+
+ return;
+}
\ No newline at end of file
--- /dev/null
+#include <lunaix/fctrl.h>
+#include <lunaix/foptions.h>
+#include <lunaix/lunistd.h>
+#include <lunaix/proc.h>
+#include <lunaix/syslog.h>
+
+LOG_MODULE("IOTEST")
+
+#define STDIN 1
+#define STDOUT 0
+
+void
+_iotest_main()
+{
+ char test_sequence[] = "Once upon a time, in a magical land of Equestria. "
+ "There were two regal sisters who ruled together "
+ "and created harmony for all the land.";
+
+ // sda 设备 - 硬盘
+ // sda设备属于容积设备(Volumetric Device),
+ // Lunaix会尽可能缓存任何对此设备的上层读写,并使用延迟写入策略。(FO_DIRECT可用于屏蔽该功能)
+ int fd = open("/dev/sda", 0);
+
+ if (fd < 0) {
+ kprintf(KERROR "fail to open (%d)\n", geterrno());
+ return;
+ }
+
+ // 移动指针至512字节,在大多数情况下,这是第二个逻辑扇区的起始处
+ lseek(fd, 512, FSEEK_SET);
+
+ // 总共写入 64 * 136 字节,会产生3个页作为缓存
+ for (size_t i = 0; i < 64; i++) {
+ write(fd, test_sequence, sizeof(test_sequence));
+ }
+
+ // 随机读写测试
+ lseek(fd, 4 * 4096, FSEEK_SET);
+ write(fd, test_sequence, sizeof(test_sequence));
+
+ char read_out[256];
+ write(STDOUT, "input: ", 8);
+ int size = read(STDIN, read_out, 256);
+
+ write(STDOUT, "your input: ", 13);
+ write(STDOUT, read_out, size);
+ write(fd, read_out, size);
+ write(STDOUT, "\n", 1);
+
+ // 读出我们写的内容
+ lseek(fd, 512, FSEEK_SET);
+ read(fd, read_out, sizeof(read_out));
+
+ // 将读出的内容直接写入tty设备
+ write(STDOUT, read_out, sizeof(read_out));
+ write(STDOUT, "\n", 1);
+
+ // 关闭文件,这同时会将页缓存中的数据下发到底层驱动
+ close(fd);
+
+ kprint_hex(read_out, sizeof(read_out));
+}
\ No newline at end of file
--- /dev/null
+#include <klibc/stdio.h>
+#include <lunaix/device.h>
+#include <lunaix/fs/twifs.h>
+#include <lunaix/mm/valloc.h>
+
+struct llist_header dev_list;
+
+static struct twifs_node* dev_root;
+
+int
+__dev_read(struct v_file* file, void* buffer, size_t len, size_t fpos);
+
+int
+__dev_write(struct v_file* file, void* buffer, size_t len, size_t fpos);
+
+void
+device_init()
+{
+ dev_root = twifs_toplevel_node("dev", 3, 0);
+
+ llist_init_head(&dev_list);
+}
+
+struct device*
+__device_add(struct device* parent,
+ void* underlay,
+ char* name_fmt,
+ uint32_t type,
+ va_list args)
+{
+ struct device* dev = vzalloc(sizeof(struct device));
+
+ size_t strlen =
+ __sprintf_internal(dev->name_val, name_fmt, DEVICE_NAME_SIZE, args);
+
+ dev->name = HSTR(dev->name_val, strlen);
+ dev->parent = parent;
+ dev->underlay = underlay;
+
+ hstr_rehash(&dev->name, HSTR_FULL_HASH);
+ llist_append(&dev_list, &dev->dev_list);
+
+ struct twifs_node* dev_node =
+ twifs_file_node(dev_root, dev->name_val, strlen, type);
+ dev_node->data = dev;
+ dev_node->ops.read = __dev_read;
+ dev_node->ops.write = __dev_write;
+
+ dev->fs_node = dev_node;
+
+ return dev;
+}
+
+struct device*
+device_addseq(struct device* parent, void* underlay, char* name_fmt, ...)
+{
+ va_list args;
+ va_start(args, name_fmt);
+
+ struct device* dev =
+ __device_add(parent, underlay, name_fmt, VFS_IFSEQDEV, args);
+
+ va_end(args);
+ return dev;
+}
+
+struct device*
+device_addvol(struct device* parent, void* underlay, char* name_fmt, ...)
+{
+ va_list args;
+ va_start(args, name_fmt);
+
+ struct device* dev =
+ __device_add(parent, underlay, name_fmt, VFS_IFVOLDEV, args);
+
+ va_end(args);
+ return dev;
+}
+
+int
+__dev_read(struct v_file* file, void* buffer, size_t len, size_t fpos)
+{
+ struct twifs_node* dev_node = (struct twifs_node*)file->inode->data;
+ struct device* dev = (struct device*)dev_node->data;
+
+ if (!dev->read) {
+ return ENOTSUP;
+ }
+ return dev->read(dev, buffer, fpos, len);
+}
+
+int
+__dev_write(struct v_file* file, void* buffer, size_t len, size_t fpos)
+{
+ struct twifs_node* dev_node = (struct twifs_node*)file->inode->data;
+ struct device* dev = (struct device*)dev_node->data;
+
+ if (!dev->write) {
+ return ENOTSUP;
+ }
+ return dev->write(dev, buffer, fpos, len);
+}
+
+void
+device_remove(struct device* dev)
+{
+ llist_delete(&dev->dev_list);
+ twifs_rm_node((struct twifs_node*)dev->fs_node);
+ vfree(dev);
+}
\ No newline at end of file
--- /dev/null
+/**
+ * @file btrie.c
+ * @author Lunaixsky
+ * @brief Bitwise trie tree implementation for sparse array.
+ * @version 0.1
+ * @date 2022-08-01
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+
+#include <lunaix/ds/btrie.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/spike.h>
+
+#define BTRIE_INSERT 1
+
+struct btrie_node*
+__btrie_traversal(struct btrie* root, uint32_t index, int options)
+{
+ index = index >> root->truncated;
+ uint32_t lz = index ? ROUNDDOWN(31 - __builtin_clz(index), BTRIE_BITS) : 0;
+ uint32_t bitmask = ((1 << BTRIE_BITS) - 1) << lz;
+ uint32_t i = 0;
+ struct btrie_node* tree = root->btrie_root;
+
+ // Time complexity: O(log_2(log_2(N))) where N is the index to lookup
+ while (bitmask && tree) {
+ i = (index & bitmask) >> lz;
+ struct btrie_node *subtree = 0, *pos, *n;
+
+ llist_for_each(pos, n, &tree->children, siblings)
+ {
+ if (pos->index == i) {
+ subtree = pos;
+ break;
+ }
+ }
+
+ if (!subtree && (options & BTRIE_INSERT)) {
+ struct btrie_node* new_tree = vzalloc(sizeof(struct btrie_node));
+ new_tree->index = i;
+ new_tree->parent = tree;
+ llist_init_head(&new_tree->children);
+
+ llist_append(&tree->children, &new_tree->siblings);
+ llist_append(&root->btrie_root->nodes, &new_tree->nodes);
+ tree = new_tree;
+ } else {
+ tree = subtree;
+ }
+ bitmask = bitmask >> BTRIE_BITS;
+ lz -= BTRIE_BITS;
+ }
+
+ return tree;
+}
+
+void
+btrie_init(struct btrie* btrie, uint32_t trunc_bits)
+{
+ btrie->btrie_root = vzalloc(sizeof(struct btrie_node));
+ llist_init_head(&btrie->btrie_root->nodes);
+ llist_init_head(&btrie->btrie_root->children);
+ btrie->truncated = trunc_bits;
+}
+
+void*
+btrie_get(struct btrie* root, uint32_t index)
+{
+ struct btrie_node* node = __btrie_traversal(root, index, 0);
+ if (!node) {
+ return NULL;
+ }
+ return node->data;
+}
+
+void
+btrie_set(struct btrie* root, uint32_t index, void* data)
+{
+ struct btrie_node* node = __btrie_traversal(root, index, BTRIE_INSERT);
+ node->data = data;
+}
+
+void
+__btrie_remove(struct btrie_node* node)
+{
+ struct btrie_node* parent = node->parent;
+ if (parent) {
+ llist_delete(&node->siblings);
+ llist_delete(&node->nodes);
+ vfree(node);
+ if (llist_empty(&parent->children)) {
+ __btrie_remove(parent);
+ }
+ }
+}
+
+void*
+btrie_remove(struct btrie* root, uint32_t index)
+{
+ struct btrie_node* node = __btrie_traversal(root, index, 0);
+ if (!node) {
+ return 0;
+ }
+ void* data = node->data;
+ __btrie_remove(node);
+ return data;
+}
+
+void
+btrie_release(struct btrie* tree)
+{
+ struct btrie_node *pos, *n;
+ llist_for_each(pos, n, &tree->btrie_root->nodes, nodes)
+ {
+ vfree(pos);
+ }
+
+ vfree(tree->btrie_root);
+}
\ No newline at end of file
--- /dev/null
+#include <klibc/string.h>
+#include <lunaix/ds/fifo.h>
+#include <lunaix/ds/mutex.h>
+#include <lunaix/spike.h>
+
+void
+fifo_init(struct fifo_buf* buf, void* data_buffer, size_t buf_size, int flags)
+{
+ *buf = (struct fifo_buf){ .data = data_buffer,
+ .rd_pos = 0,
+ .wr_pos = 0,
+ .size = buf_size,
+ .flags = flags,
+ .free_len = buf_size };
+ mutex_init(&buf->lock);
+}
+
+int
+fifo_backone(struct fifo_buf* fbuf)
+{
+ mutex_lock(&fbuf->lock);
+
+ if (fbuf->free_len == fbuf->size) {
+ mutex_unlock(&fbuf->lock);
+ return 0;
+ }
+
+ fbuf->wr_pos = (fbuf->wr_pos ? fbuf->wr_pos : fbuf->size) - 1;
+ fbuf->free_len++;
+
+ mutex_unlock(&fbuf->lock);
+
+ return 1;
+}
+
+size_t
+fifo_putone(struct fifo_buf* fbuf, uint8_t data)
+{
+ mutex_lock(&fbuf->lock);
+
+ if (!fbuf->free_len) {
+ mutex_unlock(&fbuf->lock);
+ return 0;
+ }
+
+ uint8_t* dest = fbuf->data;
+ dest[fbuf->wr_pos] = data;
+ fbuf->wr_pos = (fbuf->wr_pos + 1) % fbuf->size;
+ fbuf->free_len--;
+
+ mutex_unlock(&fbuf->lock);
+
+ return 1;
+}
+
+size_t
+fifo_write(struct fifo_buf* fbuf, void* data, size_t count)
+{
+ size_t wr_count = 0, wr_pos = fbuf->wr_pos;
+
+ mutex_lock(&fbuf->lock);
+
+ if (!fbuf->free_len) {
+ mutex_unlock(&fbuf->lock);
+ return 0;
+ }
+
+ if (wr_pos >= fbuf->rd_pos) {
+ // case 1
+ size_t cplen_tail = MIN(fbuf->size - wr_pos, count);
+ size_t cplen_head = MIN(fbuf->rd_pos, count - cplen_tail);
+ memcpy(fbuf->data + wr_pos, data, cplen_tail);
+ memcpy(fbuf->data, data + cplen_tail, cplen_head);
+
+ wr_count = cplen_head + cplen_tail;
+ } else {
+ // case 2
+ wr_count = MIN(fbuf->rd_pos - wr_pos, count);
+ memcpy(fbuf->data + wr_pos, data, wr_count);
+ }
+
+ fbuf->wr_pos = (wr_pos + wr_count) % fbuf->size;
+ fbuf->free_len -= wr_count;
+
+ mutex_unlock(&fbuf->lock);
+
+ return wr_count;
+}
+
+size_t
+fifo_read(struct fifo_buf* fbuf, void* buf, size_t count)
+{
+ size_t rd_count = 0, rd_pos = fbuf->rd_pos;
+ mutex_lock(&fbuf->lock);
+
+ if (fbuf->free_len == fbuf->size) {
+ mutex_unlock(&fbuf->lock);
+ return 0;
+ }
+
+ if (rd_pos >= fbuf->wr_pos) {
+ size_t cplen_tail = MIN(fbuf->size - rd_pos, count);
+ size_t cplen_head = MIN(fbuf->wr_pos, count - cplen_tail);
+ memcpy(buf, fbuf->data + rd_pos, cplen_tail);
+ memcpy(buf + cplen_tail, fbuf->data, cplen_head);
+
+ rd_count = cplen_head + cplen_tail;
+ } else {
+ rd_count = MIN(fbuf->wr_pos - rd_pos, count);
+ memcpy(buf, fbuf->data + rd_pos, rd_count);
+ }
+
+ fbuf->rd_pos = (rd_pos + rd_count) % fbuf->size;
+ fbuf->free_len += rd_count;
+
+ mutex_unlock(&fbuf->lock);
+
+ return rd_count;
+}
\ No newline at end of file
--- /dev/null
+/**
+ * @file fsm.c File system manager
+ * @author Lunaixsky (zelong56@gmail.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-07-19
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+#include <klibc/string.h>
+#include <lunaix/ds/hashtable.h>
+#include <lunaix/fs.h>
+
+#define HASH_BUCKET_BITS 4
+#define HASH_BUCKET_NUM (1 << HASH_BUCKET_BITS)
+
+DECLARE_HASHTABLE(fs_registry, HASH_BUCKET_NUM);
+
+void
+fsm_init()
+{
+ hashtable_init(fs_registry);
+}
+
+void
+fsm_register(struct filesystem* fs)
+{
+ hstr_rehash(&fs->fs_name, HSTR_FULL_HASH);
+ hashtable_hash_in(fs_registry, &fs->fs_list, fs->fs_name.hash);
+}
+
+struct filesystem*
+fsm_get(const char* fs_name)
+{
+ struct filesystem *pos, *next;
+ struct hstr str = HSTR(fs_name, 0);
+ hstr_rehash(&str, HSTR_FULL_HASH);
+
+ hashtable_hash_foreach(fs_registry, str.hash, pos, next, fs_list)
+ {
+ if (pos->fs_name.hash == str.hash) {
+ return pos;
+ }
+ }
+
+ return NULL;
+}
\ No newline at end of file
--- /dev/null
+#include <klibc/string.h>
+#include <lunaix/ds/btrie.h>
+#include <lunaix/fs.h>
+#include <lunaix/mm/page.h>
+#include <lunaix/mm/pmm.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/mm/vmm.h>
+#include <lunaix/spike.h>
+
+#define PCACHE_DIRTY 0x1
+
+void
+pcache_init(struct pcache* pcache)
+{
+ btrie_init(&pcache->tree, PG_SIZE_BITS);
+ llist_init_head(&pcache->dirty);
+ llist_init_head(&pcache->pages);
+}
+
+void
+pcache_release_page(struct pcache* pcache, struct pcache_pg* page)
+{
+ pmm_free_page(KERNEL_PID, page->pg);
+ vmm_del_mapping(PD_REFERENCED, page->pg);
+
+ llist_delete(&page->pg_list);
+
+ vfree(page);
+
+ pcache->n_pages--;
+}
+
+struct pcache_pg*
+pcache_new_page(struct pcache* pcache, uint32_t index)
+{
+ void* pg = pmm_alloc_page(KERNEL_PID, 0);
+ void* pg_v = vmm_vmap(pg, PG_SIZE, PG_PREM_URW);
+ struct pcache_pg* ppg = vzalloc(sizeof(struct pcache_pg));
+ ppg->pg = pg_v;
+
+ llist_append(&pcache->pages, &ppg->pg_list);
+ btrie_set(&pcache->tree, index, ppg);
+
+ return ppg;
+}
+
+void
+pcache_set_dirty(struct pcache* pcache, struct pcache_pg* pg)
+{
+ if (!(pg->flags & PCACHE_DIRTY)) {
+ pg->flags |= PCACHE_DIRTY;
+ pcache->n_dirty++;
+ llist_append(&pcache->dirty, &pg->dirty_list);
+ }
+}
+
+struct pcache_pg*
+pcache_get_page(struct pcache* pcache,
+ uint32_t index,
+ uint32_t* offset,
+ struct pcache_pg** page)
+{
+ struct pcache_pg* pg = btrie_get(&pcache->tree, index);
+ int is_new = 0;
+ *offset = index & ((1 << pcache->tree.truncated) - 1);
+ if (!pg) {
+ pg = pcache_new_page(pcache, index);
+ pg->fpos = index - *offset;
+ pcache->n_pages++;
+ is_new = 1;
+ }
+ *page = pg;
+ return is_new;
+}
+
+int
+pcache_write(struct v_file* file, void* data, uint32_t len, uint32_t fpos)
+{
+ uint32_t pg_off, buf_off = 0;
+ struct pcache* pcache = file->inode->pg_cache;
+ struct pcache_pg* pg;
+
+ while (buf_off < len) {
+ pcache_get_page(pcache, fpos, &pg_off, &pg);
+ uint32_t wr_bytes = MIN(PG_SIZE - pg_off, len - buf_off);
+ memcpy(pg->pg + pg_off, (data + buf_off), wr_bytes);
+
+ pcache_set_dirty(pcache, pg);
+
+ buf_off += wr_bytes;
+ fpos += wr_bytes;
+ }
+
+ return buf_off;
+}
+
+int
+pcache_read(struct v_file* file, void* data, uint32_t len, uint32_t fpos)
+{
+ uint32_t pg_off, buf_off = 0, new_pg = 0;
+ int errno = 0;
+ struct pcache* pcache = file->inode->pg_cache;
+ struct pcache_pg* pg;
+ struct v_inode* inode = file->inode;
+
+ while (buf_off < len) {
+ if (pcache_get_page(pcache, fpos, &pg_off, &pg)) {
+ // Filling up the page
+ errno = inode->default_fops.read(file, pg->pg, PG_SIZE, pg->fpos);
+ if (errno >= 0 && errno < PG_SIZE) {
+ // EOF
+ len = buf_off + errno;
+ } else if (errno < 0) {
+ break;
+ }
+ }
+ uint32_t rd_bytes = MIN(PG_SIZE - pg_off, len - buf_off);
+ memcpy((data + buf_off), pg->pg + pg_off, rd_bytes);
+
+ buf_off += rd_bytes;
+ fpos += rd_bytes;
+ }
+
+ return errno < 0 ? errno : buf_off;
+}
+
+void
+pcache_release(struct pcache* pcache)
+{
+ struct pcache_pg *pos, *n;
+ llist_for_each(pos, n, &pcache->pages, pg_list)
+ {
+ vfree(pos);
+ }
+
+ btrie_release(&pcache->tree);
+}
+
+int
+pcache_commit(struct v_file* file, struct pcache_pg* page)
+{
+ if (!(page->flags & PCACHE_DIRTY)) {
+ return;
+ }
+
+ struct v_inode* inode = file->inode;
+ int errno = inode->default_fops.write(file, page->pg, PG_SIZE, page->fpos);
+
+ if (!errno) {
+ page->flags &= ~PCACHE_DIRTY;
+ llist_delete(&page->dirty_list);
+ file->inode->pg_cache->n_dirty--;
+ }
+
+ return errno;
+}
+
+void
+pcache_commit_all(struct v_file* file)
+{
+ struct pcache* cache = file->inode->pg_cache;
+ struct pcache_pg *pos, *n;
+ llist_for_each(pos, n, &cache->dirty, dirty_list)
+ {
+ pcache_commit(file, pos);
+ }
+}
+
+void
+pcache_invalidate(struct v_file* file, struct pcache_pg* page)
+{
+ pcache_commit(file, page);
+ pcache_release_page(&file->inode->pg_cache, page);
+}
\ No newline at end of file
--- /dev/null
+/**
+ * @file twifs.c
+ * @author Lunaixsky (zelong56@gmail.com)
+ * @brief TwiFS - A pseudo file system for kernel state exposure.
+ * @version 0.1
+ * @date 2022-07-21
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+#include <klibc/string.h>
+#include <lunaix/clock.h>
+#include <lunaix/fs.h>
+#include <lunaix/fs/twifs.h>
+#include <lunaix/mm/cake.h>
+#include <lunaix/mm/valloc.h>
+
+static struct twifs_node* fs_root;
+
+static struct cake_pile* twi_pile;
+
+int
+__twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode);
+
+int
+__twifs_openfile(struct v_inode* inode, struct v_file* file);
+
+struct twifs_node*
+__twifs_get_node(struct twifs_node* parent, struct hstr* name);
+
+struct v_inode*
+__twifs_create_inode(struct twifs_node* twi_node);
+
+int
+__twifs_iterate_dir(struct v_file* file, struct dir_context* dctx);
+
+int
+__twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point);
+
+int
+__twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode);
+
+int
+__twifs_rmstuff(struct v_inode* inode);
+
+int
+__twifs_fwrite(struct v_file* file, void* buffer, size_t len, size_t fpos);
+
+int
+__twifs_fread(struct v_file* file, void* buffer, size_t len, size_t fpos);
+
+void
+twifs_init()
+{
+ twi_pile = cake_new_pile("twifs_node", sizeof(struct twifs_node), 1, 0);
+
+ struct filesystem* twifs = vzalloc(sizeof(struct filesystem));
+ twifs->fs_name = HSTR("twifs", 5);
+ twifs->mount = __twifs_mount;
+ twifs->types = FSTYPE_ROFS;
+
+ fsm_register(twifs);
+
+ fs_root = twifs_dir_node(NULL, NULL, 0, 0);
+}
+
+struct twifs_node*
+__twifs_new_node(struct twifs_node* parent,
+ const char* name,
+ int name_len,
+ uint32_t itype)
+{
+ struct twifs_node* node = cake_grab(twi_pile);
+ memset(node, 0, sizeof(*node));
+
+ node->name = HSTR(name, name_len);
+ node->itype = itype;
+ hstr_rehash(&node->name, HSTR_FULL_HASH);
+ llist_init_head(&node->children);
+
+ if (parent) {
+ llist_append(&parent->children, &node->siblings);
+ }
+
+ return node;
+}
+
+int
+twifs_rm_node(struct twifs_node* node)
+{
+ if ((node->itype & VFS_IFDIR) && !llist_empty(&node->children)) {
+ return ENOTEMPTY;
+ }
+ llist_delete(&node->siblings);
+ vfs_i_free(node->inode);
+ cake_release(twi_pile, node);
+ return 0;
+}
+
+struct twifs_node*
+twifs_file_node(struct twifs_node* parent,
+ const char* name,
+ int name_len,
+ uint32_t itype)
+{
+ struct twifs_node* twi_node =
+ __twifs_new_node(parent, name, name_len, VFS_IFFILE | itype);
+
+ struct v_inode* twi_inode = __twifs_create_inode(twi_node);
+ twi_node->inode = twi_inode;
+
+ return twi_node;
+}
+
+struct twifs_node*
+twifs_dir_node(struct twifs_node* parent,
+ const char* name,
+ int name_len,
+ uint32_t itype)
+{
+ struct hstr hname = HSTR(name, name_len);
+ hstr_rehash(&hname, HSTR_FULL_HASH);
+ struct twifs_node* node = __twifs_get_node(parent, &hname);
+ if (node) {
+ return node;
+ }
+
+ struct twifs_node* twi_node =
+ __twifs_new_node(parent, name, name_len, VFS_IFDIR | itype);
+
+ struct v_inode* twi_inode = __twifs_create_inode(twi_node);
+ twi_node->inode = twi_inode;
+
+ return twi_node;
+}
+
+struct twifs_node*
+twifs_toplevel_node(const char* name, int name_len, uint32_t itype)
+{
+ return twifs_dir_node(fs_root, name, name_len, itype);
+}
+
+int
+__twifs_mkdir(struct v_inode* inode, struct v_dnode* dnode)
+{
+ struct twifs_node* parent_node = (struct twifs_node*)inode->data;
+ if (!(parent_node->itype & VFS_IFDIR)) {
+ return ENOTDIR;
+ }
+ struct twifs_node* new_node =
+ twifs_dir_node(parent_node, dnode->name.value, dnode->name.len, 0);
+ dnode->inode = new_node->inode;
+
+ return 0;
+}
+
+int
+__twifs_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
+{
+ mount_point->inode = fs_root->inode;
+ return 0;
+}
+
+struct v_inode*
+__twifs_create_inode(struct twifs_node* twi_node)
+{
+ struct v_inode* inode = vfs_i_alloc();
+ *inode = (struct v_inode){ .ctime = 0,
+ .itype = twi_node->itype,
+ .lb_addr = 0,
+ .lb_usage = 0,
+ .data = twi_node,
+ .mtime = 0,
+ .open_count = 0 };
+ inode->ops.dir_lookup = __twifs_dirlookup;
+ inode->ops.mkdir = __twifs_mkdir;
+ inode->ops.unlink = __twifs_rmstuff;
+ inode->ops.rmdir = __twifs_rmstuff;
+ inode->ops.open = __twifs_openfile;
+
+ inode->default_fops = (struct v_file_ops){ .read = __twifs_fread,
+ .write = __twifs_fwrite,
+ .readdir = __twifs_iterate_dir };
+
+ return inode;
+}
+
+int
+__twifs_fwrite(struct v_file* file, void* buffer, size_t len, size_t fpos)
+{
+ struct twifs_node* twi_node = (struct twifs_node*)file->inode->data;
+ if (!twi_node || !twi_node->ops.write) {
+ return ENOTSUP;
+ }
+ return twi_node->ops.write(file, buffer, len, fpos);
+}
+
+int
+__twifs_fread(struct v_file* file, void* buffer, size_t len, size_t fpos)
+{
+ struct twifs_node* twi_node = (struct twifs_node*)file->inode->data;
+ if (!twi_node || !twi_node->ops.read) {
+ return ENOTSUP;
+ }
+ return twi_node->ops.read(file, buffer, len, fpos);
+}
+
+struct twifs_node*
+__twifs_get_node(struct twifs_node* parent, struct hstr* name)
+{
+ if (!parent)
+ return NULL;
+
+ struct twifs_node *pos, *n;
+ llist_for_each(pos, n, &parent->children, siblings)
+ {
+ if (HSTR_EQ(&pos->name, name)) {
+ return pos;
+ }
+ }
+ return NULL;
+}
+
+int
+__twifs_rmstuff(struct v_inode* inode)
+{
+ struct twifs_node* twi_node = (struct twifs_node*)inode->data;
+ return twifs_rm_node(twi_node);
+}
+
+int
+__twifs_dirlookup(struct v_inode* inode, struct v_dnode* dnode)
+{
+ struct twifs_node* twi_node = (struct twifs_node*)inode->data;
+
+ if (!(twi_node->itype & VFS_IFDIR)) {
+ return ENOTDIR;
+ }
+
+ struct twifs_node* child_node = __twifs_get_node(twi_node, &dnode->name);
+ if (child_node) {
+ dnode->inode = child_node->inode;
+ return 0;
+ }
+ return ENOENT;
+}
+
+int
+__twifs_iterate_dir(struct v_file* file, struct dir_context* dctx)
+{
+ struct twifs_node* twi_node = (struct twifs_node*)(file->inode->data);
+ int counter = 0;
+ struct twifs_node *pos, *n;
+
+ llist_for_each(pos, n, &twi_node->children, siblings)
+ {
+ if (counter++ >= dctx->index) {
+ dctx->index = counter;
+ dctx->read_complete_callback(
+ dctx, pos->name.value, pos->name.len, pos->itype);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int
+__twifs_openfile(struct v_inode* inode, struct v_file* file)
+{
+ struct twifs_node* twi_node = (struct twifs_node*)inode->data;
+ if (twi_node) {
+ return 0;
+ }
+ return ENOTSUP;
+}
--- /dev/null
+/**
+ * @file vfs.c
+ * @author Lunaixsky (zelong56@gmail.com)
+ * @brief Lunaix virtual file system - an abstraction layer for all file system.
+ * @version 0.1
+ * @date 2022-07-24
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+
+#include <klibc/string.h>
+#include <lunaix/dirent.h>
+#include <lunaix/foptions.h>
+#include <lunaix/fs.h>
+#include <lunaix/mm/cake.h>
+#include <lunaix/mm/page.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/process.h>
+#include <lunaix/spike.h>
+#include <lunaix/syscall.h>
+
+#define PATH_DELIM '/'
+#define DNODE_HASHTABLE_BITS 10
+#define DNODE_HASHTABLE_SIZE (1 << DNODE_HASHTABLE_BITS)
+#define DNODE_HASH_MASK (DNODE_HASHTABLE_SIZE - 1)
+#define DNODE_HASHBITS (32 - DNODE_HASHTABLE_BITS)
+
+static struct cake_pile* dnode_pile;
+static struct cake_pile* inode_pile;
+static struct cake_pile* file_pile;
+static struct cake_pile* superblock_pile;
+static struct cake_pile* fd_pile;
+
+static struct v_superblock* root_sb;
+static struct hbucket* dnode_cache;
+
+static int fs_id = 0;
+
+struct hstr vfs_ddot = HSTR("..", 2);
+struct hstr vfs_dot = HSTR(".", 1);
+struct hstr vfs_empty = HSTR("", 0);
+
+struct v_dnode*
+vfs_d_alloc();
+
+void
+vfs_d_free(struct v_dnode* dnode);
+
+struct v_superblock*
+vfs_sb_alloc();
+
+void
+vfs_sb_free(struct v_superblock* sb);
+
+void
+vfs_init()
+{
+ // 为他们专门创建一个蛋糕堆,而不使用valloc,这样我们可以最小化内碎片的产生
+ dnode_pile = cake_new_pile("dnode_cache", sizeof(struct v_dnode), 1, 0);
+ inode_pile = cake_new_pile("inode_cache", sizeof(struct v_inode), 1, 0);
+ file_pile = cake_new_pile("file_cache", sizeof(struct v_file), 1, 0);
+ fd_pile = cake_new_pile("fd_cache", sizeof(struct v_fd), 1, 0);
+ superblock_pile =
+ cake_new_pile("sb_cache", sizeof(struct v_superblock), 1, 0);
+
+ dnode_cache = vzalloc(DNODE_HASHTABLE_SIZE * sizeof(struct hbucket));
+
+ hstr_rehash(&vfs_ddot, HSTR_FULL_HASH);
+ hstr_rehash(&vfs_dot, HSTR_FULL_HASH);
+
+ // 创建一个根superblock,用来蕴含我们的根目录。
+ root_sb = vfs_sb_alloc();
+ root_sb->root = vfs_d_alloc();
+ root_sb->root->inode = vfs_i_alloc();
+}
+
+inline struct hbucket*
+__dcache_get_bucket(struct v_dnode* parent, unsigned int hash)
+{
+ // 与parent的指针值做加法,来减小碰撞的可能性。
+ hash += (uint32_t)parent;
+ // 确保低位更加随机
+ hash = hash ^ (hash >> DNODE_HASHBITS);
+ return &dnode_cache[hash & DNODE_HASH_MASK];
+}
+
+struct v_dnode*
+vfs_dcache_lookup(struct v_dnode* parent, struct hstr* str)
+{
+ if (!str->len || HSTR_EQ(str, &vfs_dot))
+ return parent;
+
+ if (HSTR_EQ(str, &vfs_ddot)) {
+ return parent->parent ? parent->parent : parent;
+ }
+
+ struct hbucket* slot = __dcache_get_bucket(parent, str->hash);
+
+ struct v_dnode *pos, *n;
+ hashtable_bucket_foreach(slot, pos, n, hash_list)
+ {
+ if (pos->name.hash == str->hash) {
+ return pos;
+ }
+ }
+ return NULL;
+}
+
+void
+vfs_dcache_add(struct v_dnode* parent, struct v_dnode* dnode)
+{
+ struct hbucket* bucket = __dcache_get_bucket(parent, dnode->name.hash);
+ hlist_add(&bucket->head, &dnode->hash_list);
+}
+
+int
+__vfs_walk(struct v_dnode* start,
+ const char* path,
+ struct v_dnode** dentry,
+ struct hstr* component,
+ int walk_options)
+{
+ int errno = 0;
+ int i = 0, j = 0;
+
+ if (path[0] == PATH_DELIM || !start) {
+ if ((walk_options & VFS_WALK_FSRELATIVE) && start) {
+ start = start->super_block->root;
+ } else {
+ start = root_sb->root;
+ }
+ i++;
+ }
+
+ struct v_dnode* dnode;
+ struct v_dnode* current_level = start;
+
+ char name_content[VFS_NAME_MAXLEN];
+ struct hstr name = HSTR(name_content, 0);
+
+ char current = path[i++], lookahead;
+ while (current) {
+ lookahead = path[i++];
+ if (current != PATH_DELIM) {
+ if (j >= VFS_NAME_MAXLEN - 1) {
+ return ENAMETOOLONG;
+ }
+ if (!VFS_VALID_CHAR(current)) {
+ return EINVAL;
+ }
+ name_content[j++] = current;
+ if (lookahead) {
+ goto cont;
+ }
+ }
+
+ // handling cases like /^.*(\/+).*$/
+ if (lookahead == PATH_DELIM) {
+ goto cont;
+ }
+
+ name_content[j] = 0;
+ name.len = j;
+ hstr_rehash(&name, HSTR_FULL_HASH);
+
+ if (!lookahead && (walk_options & VFS_WALK_PARENT)) {
+ if (component) {
+ component->hash = name.hash;
+ component->len = j;
+ strcpy(component->value, name_content);
+ }
+ break;
+ }
+
+ dnode = vfs_dcache_lookup(current_level, &name);
+
+ if (!dnode) {
+ dnode = vfs_d_alloc();
+ dnode->name = HHSTR(valloc(VFS_NAME_MAXLEN), j, name.hash);
+
+ strcpy(dnode->name.value, name_content);
+
+ errno =
+ current_level->inode->ops.dir_lookup(current_level->inode, dnode);
+
+ if (errno == ENOENT && (walk_options & VFS_WALK_MKPARENT)) {
+ if (!current_level->inode->ops.mkdir) {
+ errno = ENOTSUP;
+ } else {
+ errno = current_level->inode->ops.mkdir(
+ current_level->inode, dnode);
+ }
+ }
+
+ if (errno) {
+ goto error;
+ }
+
+ vfs_dcache_add(current_level, dnode);
+
+ dnode->parent = current_level;
+ llist_append(¤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;
+ char* pathname = path;
+ int errno = __vfs_walk(start, path, &interim, component, options);
+ int counter = 0;
+
+ while (!errno) {
+ if (counter >= VFS_MAX_SYMLINK) {
+ errno = ELOOP;
+ continue;
+ }
+ if ((interim->inode->itype & VFS_IFSYMLINK) &&
+ !(options & VFS_WALK_NOFOLLOW) &&
+ interim->inode->ops.read_symlink) {
+ errno = interim->inode->ops.read_symlink(interim->inode, &pathname);
+ if (errno) {
+ break;
+ }
+ } else {
+ break;
+ }
+ errno = __vfs_walk(start, pathname, &interim, component, options);
+ counter++;
+ }
+
+ *dentry = errno ? 0 : interim;
+
+ return errno;
+}
+
+int
+vfs_mount(const char* target, const char* fs_name, bdev_t device)
+{
+ int errno;
+ struct v_dnode* mnt;
+
+ if (!(errno = vfs_walk(NULL, target, &mnt, NULL, 0))) {
+ errno = vfs_mount_at(fs_name, device, mnt);
+ }
+
+ return errno;
+}
+
+int
+vfs_unmount(const char* target)
+{
+ int errno;
+ struct v_dnode* mnt;
+
+ if (!(errno = vfs_walk(NULL, target, &mnt, NULL, 0))) {
+ errno = vfs_unmount_at(mnt);
+ }
+
+ return errno;
+}
+
+int
+vfs_mount_at(const char* fs_name, bdev_t device, struct v_dnode* mnt_point)
+{
+ struct filesystem* fs = fsm_get(fs_name);
+ if (!fs)
+ return ENODEV;
+ struct v_superblock* sb = vfs_sb_alloc();
+ sb->dev = device;
+ sb->fs_id = fs_id++;
+
+ int errno = 0;
+ if (!(errno = fs->mount(sb, mnt_point))) {
+ sb->fs = fs;
+ sb->root = mnt_point;
+ mnt_point->super_block = sb;
+ llist_append(&root_sb->sb_list, &sb->sb_list);
+ }
+
+ return errno;
+}
+
+int
+vfs_unmount_at(struct v_dnode* mnt_point)
+{
+ int errno = 0;
+ struct v_superblock* sb = mnt_point->super_block;
+ if (!sb) {
+ return EINVAL;
+ }
+ if (!(errno = sb->fs->unmount(sb))) {
+ struct v_dnode* fs_root = sb->root;
+ llist_delete(&fs_root->siblings);
+ llist_delete(&sb->sb_list);
+ vfs_sb_free(sb);
+ }
+ return errno;
+}
+
+int
+vfs_open(struct v_dnode* dnode, struct v_file** file)
+{
+ if (!dnode->inode || !dnode->inode->ops.open) {
+ return ENOTSUP;
+ }
+
+ struct v_inode* inode = dnode->inode;
+ struct v_file* vfile = cake_grab(file_pile);
+ memset(vfile, 0, sizeof(*vfile));
+
+ vfile->dnode = dnode;
+ vfile->inode = inode;
+ vfile->ref_count = 1;
+ vfile->ops = inode->default_fops;
+ inode->open_count++;
+
+ if ((inode->itype & VFS_IFFILE) && !inode->pg_cache) {
+ struct pcache* pcache = vzalloc(sizeof(struct pcache));
+ pcache_init(pcache);
+ inode->pg_cache = pcache;
+ }
+
+ int errno = inode->ops.open(inode, vfile);
+ if (errno) {
+ cake_release(file_pile, vfile);
+ } else {
+ *file = vfile;
+ }
+ return errno;
+}
+
+int
+vfs_link(struct v_dnode* to_link, struct v_dnode* name)
+{
+ int errno;
+ if (to_link->super_block->root != name->super_block->root) {
+ errno = EXDEV;
+ } else if (!to_link->inode->ops.link) {
+ errno = ENOTSUP;
+ } else if (!(errno = to_link->inode->ops.link(to_link->inode, name))) {
+ name->inode = to_link->inode;
+ to_link->inode->link_count++;
+ }
+
+ return errno;
+}
+
+int
+vfs_close(struct v_file* file)
+{
+ int errno = 0;
+ if (!file->ops.close || !(errno = file->ops.close(file))) {
+ if (file->inode->open_count) {
+ file->inode->open_count--;
+ }
+ pcache_commit_all(file);
+ cake_release(file_pile, file);
+ }
+ return errno;
+}
+
+int
+vfs_fsync(struct v_file* file)
+{
+ int errno = ENOTSUP;
+ pcache_commit_all(file);
+ if (file->ops.sync) {
+ errno = file->ops.sync(file);
+ }
+ if (!errno && file->inode->ops.sync) {
+ return file->inode->ops.sync(file->inode);
+ }
+ return errno;
+}
+
+int
+vfs_alloc_fdslot(int* fd)
+{
+ for (size_t i = 0; i < VFS_MAX_FD; i++) {
+ if (!__current->fdtable->fds[i]) {
+ *fd = i;
+ return 0;
+ }
+ }
+ return EMFILE;
+}
+
+struct v_superblock*
+vfs_sb_alloc()
+{
+ struct v_superblock* sb = cake_grab(superblock_pile);
+ memset(sb, 0, sizeof(*sb));
+ llist_init_head(&sb->sb_list);
+ return sb;
+}
+
+void
+vfs_sb_free(struct v_superblock* sb)
+{
+ cake_release(superblock_pile, sb);
+}
+
+struct v_dnode*
+vfs_d_alloc()
+{
+ struct v_dnode* dnode = cake_grab(dnode_pile);
+ memset(dnode, 0, sizeof(*dnode));
+ llist_init_head(&dnode->children);
+ dnode->name = vfs_empty;
+ return dnode;
+}
+
+void
+vfs_d_free(struct v_dnode* dnode)
+{
+ if (dnode->ops.destruct) {
+ dnode->ops.destruct(dnode);
+ }
+ cake_release(dnode_pile, dnode);
+}
+
+struct v_inode*
+vfs_i_alloc()
+{
+ struct v_inode* inode = cake_grab(inode_pile);
+ memset(inode, 0, sizeof(*inode));
+ return inode;
+}
+
+void
+vfs_i_free(struct v_inode* inode)
+{
+ cake_release(inode_pile, inode);
+}
+
+/* ---- System call definition and support ---- */
+
+#define FLOCATE_CREATE_EMPTY 1
+
+#define DO_STATUS(errno) SYSCALL_ESTATUS(__current->k_status = errno)
+#define DO_STATUS_OR_RETURN(errno) ({ errno < 0 ? DO_STATUS(errno) : errno; })
+
+int
+__vfs_try_locate_file(const char* path,
+ struct v_dnode** fdir,
+ struct v_dnode** file,
+ int options)
+{
+ char name_str[VFS_NAME_MAXLEN];
+ struct hstr name = HSTR(name_str, 0);
+ int errno;
+ if ((errno = vfs_walk(NULL, path, fdir, &name, VFS_WALK_PARENT))) {
+ return errno;
+ }
+
+ errno = vfs_walk(*fdir, name.value, file, NULL, 0);
+ if (errno != ENOENT || !(options & FLOCATE_CREATE_EMPTY)) {
+ return errno;
+ }
+
+ if (!(errno = (*fdir)->inode->ops.create((*fdir)->inode))) {
+ struct v_dnode* file_new;
+ file_new = vfs_d_alloc();
+ file_new->name = HHSTR(valloc(VFS_NAME_MAXLEN), name.len, name.hash);
+ strcpy(file_new->name.value, name_str);
+ *file = file_new;
+
+ llist_append(&(*fdir)->children, &file_new->siblings);
+ }
+
+ return errno;
+}
+
+int
+__file_cached_read(struct v_file* file, void* buf, size_t len, size_t fpos)
+{
+ return pcache_read(file, buf, len, fpos);
+}
+
+int
+vfs_do_open(const char* path, int options)
+{
+ int errno, fd;
+ struct v_dnode *dentry, *file;
+ struct v_file* ofile = 0;
+
+ errno = __vfs_try_locate_file(path, &dentry, &file, 0);
+
+ if (errno != ENOENT && (options & FO_CREATE)) {
+ errno = dentry->inode->ops.create(dentry->inode);
+ }
+
+ if (!errno && (errno = vfs_open(file, &ofile))) {
+ return errno;
+ }
+
+ struct v_inode* o_inode = ofile->inode;
+ if (!(o_inode->itype & VFS_IFSEQDEV) && !(options & FO_DIRECT)) {
+ // XXX Change here accordingly when signature of pcache_r/w changed.
+ ofile->ops.read = pcache_read;
+ ofile->ops.write = pcache_write;
+ }
+
+ if (!errno && !(errno = vfs_alloc_fdslot(&fd))) {
+ struct v_fd* fd_s = vzalloc(sizeof(*fd_s));
+ ofile->f_pos = ofile->inode->fsize & -((options & FO_APPEND) != 0);
+ fd_s->file = ofile;
+ fd_s->flags = options;
+ __current->fdtable->fds[fd] = fd_s;
+ return fd;
+ }
+
+ return errno;
+}
+
+__DEFINE_LXSYSCALL2(int, open, const char*, path, int, options)
+{
+ int errno = vfs_do_open(path, options);
+ return DO_STATUS_OR_RETURN(errno);
+}
+
+#define TEST_FD(fd) (fd >= 0 && fd < VFS_MAX_FD)
+#define GET_FD(fd, fd_s) (TEST_FD(fd) && (fd_s = __current->fdtable->fds[fd]))
+
+__DEFINE_LXSYSCALL1(int, close, int, fd)
+{
+ struct v_fd* fd_s;
+ int errno = 0;
+ if (!GET_FD(fd, fd_s)) {
+ errno = EBADF;
+ goto done_err;
+ }
+
+ if (fd_s->file->ref_count > 1) {
+ fd_s->file->ref_count--;
+ } else if ((errno = vfs_close(fd_s->file))) {
+ goto done_err;
+ }
+
+ vfree(fd_s);
+ __current->fdtable->fds[fd] = 0;
+
+done_err:
+ return DO_STATUS(errno);
+}
+
+void
+__vfs_readdir_callback(struct dir_context* dctx,
+ const char* name,
+ const int len,
+ const int dtype)
+{
+ struct dirent* dent = (struct dirent*)dctx->cb_data;
+ strncpy(dent->d_name, name, DIRENT_NAME_MAX_LEN);
+ dent->d_nlen = len;
+ dent->d_type = dtype;
+}
+
+__DEFINE_LXSYSCALL2(int, readdir, int, fd, struct dirent*, dent)
+{
+ struct v_fd* fd_s;
+ int errno;
+ if (!GET_FD(fd, fd_s)) {
+ errno = EBADF;
+ } else if (!(fd_s->file->inode->itype & VFS_IFDIR)) {
+ errno = ENOTDIR;
+ } else {
+ struct dir_context dctx =
+ (struct dir_context){ .cb_data = dent,
+ .index = dent->d_offset,
+ .read_complete_callback =
+ __vfs_readdir_callback };
+ if (dent->d_offset == 0) {
+ __vfs_readdir_callback(&dctx, vfs_dot.value, vfs_dot.len, 0);
+ } else if (dent->d_offset == 1) {
+ __vfs_readdir_callback(&dctx, vfs_ddot.value, vfs_ddot.len, 0);
+ } else {
+ dctx.index -= 2;
+ if ((errno = fd_s->file->ops.readdir(fd_s->file, &dctx))) {
+ goto done;
+ }
+ }
+ errno = 0;
+ dent->d_offset++;
+ }
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL1(int, mkdir, const char*, path)
+{
+ struct v_dnode *parent, *dir;
+ struct hstr component = HSTR(valloc(VFS_NAME_MAXLEN), 0);
+ int errno = vfs_walk(NULL, path, &parent, &component, VFS_WALK_PARENT);
+ if (errno) {
+ goto done;
+ }
+
+ if ((parent->super_block->fs->types & FSTYPE_ROFS)) {
+ errno = ENOTSUP;
+ } else if (!parent->inode->ops.mkdir) {
+ errno = ENOTSUP;
+ } else if (!(parent->inode->itype & VFS_IFDIR)) {
+ errno = ENOTDIR;
+ } else {
+ dir = vfs_d_alloc();
+ dir->name = component;
+ if (!(errno = parent->inode->ops.mkdir(parent->inode, dir))) {
+ llist_append(&parent->children, &dir->siblings);
+ } else {
+ vfs_d_free(dir);
+ vfree(component.value);
+ }
+ }
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL3(int, read, int, fd, void*, buf, size_t, count)
+{
+ int errno = 0;
+ struct v_fd* fd_s;
+ if (!GET_FD(fd, fd_s)) {
+ errno = EBADF;
+ goto done;
+ }
+
+ struct v_file* file = fd_s->file;
+ if ((file->inode->itype & VFS_IFDIR)) {
+ errno = EISDIR;
+ goto done;
+ }
+
+ cpu_enable_interrupt();
+ errno = file->ops.read(file, buf, count, file->f_pos);
+ cpu_disable_interrupt();
+
+ if (errno > 0) {
+ file->f_pos += errno;
+ return errno;
+ }
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL3(int, write, int, fd, void*, buf, size_t, count)
+{
+ int errno = 0;
+ struct v_fd* fd_s;
+ if (!GET_FD(fd, fd_s)) {
+ errno = EBADF;
+ goto done;
+ }
+
+ struct v_file* file = fd_s->file;
+ if ((file->inode->itype & VFS_IFDIR)) {
+ errno = EISDIR;
+ goto done;
+ }
+
+ cpu_enable_interrupt();
+ errno = file->ops.write(file, buf, count, file->f_pos);
+ cpu_disable_interrupt();
+
+ if (errno > 0) {
+ file->f_pos += errno;
+ return errno;
+ }
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL3(int, lseek, int, fd, int, offset, int, options)
+{
+ int errno = 0;
+ struct v_fd* fd_s;
+ if (!GET_FD(fd, fd_s)) {
+ errno = EBADF;
+ } else {
+ struct v_file* file = fd_s->file;
+ size_t fpos = file->f_pos;
+ switch (options) {
+ case FSEEK_CUR:
+ fpos = (size_t)((int)file->f_pos + offset);
+ break;
+ case FSEEK_END:
+ fpos = (size_t)((int)file->inode->fsize + offset);
+ break;
+ case FSEEK_SET:
+ fpos = offset;
+ break;
+ }
+ if (!file->ops.seek || !(errno = file->ops.seek(file, fpos))) {
+ file->f_pos = fpos;
+ }
+ }
+
+ return DO_STATUS(errno);
+}
+
+int
+vfs_get_path(struct v_dnode* dnode, char* buf, size_t size, int depth)
+{
+ if (!dnode) {
+ return 0;
+ }
+
+ if (depth > 64) {
+ return ELOOP;
+ }
+
+ size_t len = vfs_get_path(dnode->parent, buf, size, depth + 1);
+
+ if (len >= size) {
+ return len;
+ }
+
+ size_t cpy_size = MIN(dnode->name.len, size - len);
+ strncpy(buf + len, dnode->name.value, cpy_size);
+ len += cpy_size;
+
+ if (len < size) {
+ buf[len++] = PATH_DELIM;
+ }
+
+ return len;
+}
+
+int
+vfs_readlink(struct v_dnode* dnode, char* buf, size_t size)
+{
+ char* link;
+ if (dnode->inode->ops.read_symlink) {
+ int errno = dnode->inode->ops.read_symlink(dnode->inode, &link);
+ strncpy(buf, link, size);
+ return errno;
+ }
+ return 0;
+}
+
+__DEFINE_LXSYSCALL3(int, realpathat, int, fd, char*, buf, size_t, size)
+{
+ int errno;
+ struct v_fd* fd_s;
+ if (!GET_FD(fd, fd_s)) {
+ errno = EBADF;
+ } else {
+ struct v_dnode* dnode;
+ errno = vfs_get_path(fd_s->file->dnode, buf, size, 0);
+ }
+
+ if (errno >= 0) {
+ return errno;
+ }
+
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL3(int, readlink, const char*, path, char*, buf, size_t, size)
+{
+ int errno;
+ struct v_dnode* dnode;
+ if (!(errno = vfs_walk(NULL, path, &dnode, NULL, VFS_WALK_NOFOLLOW))) {
+ errno = vfs_readlink(dnode, buf, size);
+ }
+
+ if (errno >= 0) {
+ return errno;
+ }
+
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL4(int,
+ readlinkat,
+ int,
+ dirfd,
+ const char*,
+ pathname,
+ char*,
+ buf,
+ size_t,
+ size)
+{
+ int errno;
+ struct v_fd* fd_s;
+ if (!GET_FD(dirfd, fd_s)) {
+ errno = EBADF;
+ } else {
+ struct v_dnode* dnode;
+ if (!(errno = vfs_walk(fd_s->file->dnode,
+ pathname,
+ &dnode,
+ NULL,
+ VFS_WALK_NOFOLLOW))) {
+ errno = vfs_readlink(fd_s->file->dnode, buf, size);
+ }
+ }
+
+ if (errno >= 0) {
+ return errno;
+ }
+
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL1(int, rmdir, const char*, pathname)
+{
+ int errno;
+ struct v_dnode* dnode;
+ if ((errno = vfs_walk(NULL, pathname, &dnode, NULL, 0))) {
+ goto done;
+ }
+ if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
+ errno = EROFS;
+ goto done;
+ }
+
+ if (dnode->inode->open_count) {
+ errno = EBUSY;
+ goto done;
+ }
+
+ if ((dnode->inode->itype & VFS_IFDIR)) {
+ errno = dnode->inode->ops.rmdir(dnode->inode);
+ } else {
+ errno = ENOTDIR;
+ }
+
+done:
+ return DO_STATUS(errno);
+}
+
+int
+__vfs_do_unlink(struct v_inode* inode)
+{
+ int errno;
+ if (inode->open_count) {
+ errno = EBUSY;
+ } else if (!(inode->itype & VFS_IFDIR)) {
+ // TODO handle symbolic link and type other than regular file
+ errno = inode->ops.unlink(inode);
+ if (!errno) {
+ inode->link_count--;
+ }
+ } else {
+ errno = EISDIR;
+ }
+
+ return errno;
+}
+
+__DEFINE_LXSYSCALL1(int, unlink, const char*, pathname)
+{
+ int errno;
+ struct v_dnode* dnode;
+ if ((errno = vfs_walk(NULL, pathname, &dnode, NULL, 0))) {
+ goto done;
+ }
+ if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
+ errno = EROFS;
+ goto done;
+ }
+
+ errno = __vfs_do_unlink(dnode->inode);
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL2(int, unlinkat, int, fd, const char*, pathname)
+{
+ int errno;
+ struct v_fd* fd_s;
+ if (!GET_FD(fd, fd_s)) {
+ errno = EBADF;
+ } else {
+ struct v_dnode* dnode;
+ if (!(errno = vfs_walk(fd_s->file->dnode, pathname, &dnode, NULL, 0))) {
+ errno = __vfs_do_unlink(dnode->inode);
+ }
+ }
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL2(int, link, const char*, oldpath, const char*, newpath)
+{
+ int errno;
+ struct v_dnode *dentry, *to_link, *name_dentry, *name_file;
+
+ errno = __vfs_try_locate_file(oldpath, &dentry, &to_link, 0);
+ if (!errno) {
+ errno = __vfs_try_locate_file(
+ newpath, &name_dentry, &name_file, FLOCATE_CREATE_EMPTY);
+ if (!errno) {
+ errno = EEXIST;
+ } else if (name_file) {
+ errno = vfs_link(to_link, name_file);
+ }
+ }
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL1(int, fsync, int, fildes)
+{
+ int errno;
+ struct v_fd* fd_s;
+ if (!GET_FD(fildes, fd_s)) {
+ errno = EBADF;
+ } else {
+ errno = vfs_fsync(fd_s->file);
+ }
+
+ return DO_STATUS(errno);
+}
+
+int
+vfs_dup_fd(struct v_fd* old, struct v_fd** new)
+{
+ int errno = 0;
+ struct v_fd* copied = cake_grab(fd_pile);
+
+ memcpy(copied, old, sizeof(struct v_fd));
+ old->file->ref_count++;
+
+ *new = copied;
+
+ return errno;
+}
+
+int
+vfs_dup2(int oldfd, int newfd)
+{
+ if (newfd == oldfd) {
+ return newfd;
+ }
+
+ int errno;
+ struct v_fd *oldfd_s, *newfd_s;
+ if (!GET_FD(oldfd, oldfd_s) || !TEST_FD(newfd)) {
+ errno = EBADF;
+ goto done;
+ }
+ newfd_s = __current->fdtable->fds[newfd];
+ if (newfd_s && (errno = vfs_close(newfd_s))) {
+ goto done;
+ }
+
+ if (!(errno = vfs_dup_fd(oldfd_s, &newfd_s))) {
+ __current->fdtable->fds[newfd] = newfd_s;
+ return newfd;
+ }
+
+done:
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL2(int, dup2, int, oldfd, int, newfd)
+{
+ return vfs_dup2(oldfd, newfd);
+}
+
+__DEFINE_LXSYSCALL1(int, dup, int, oldfd)
+{
+ int errno, newfd;
+ struct v_fd *oldfd_s, *newfd_s;
+ if (!GET_FD(oldfd, oldfd_s)) {
+ errno = EBADF;
+ } else if (!(errno = vfs_alloc_fdslot(&newfd)) &&
+ !(errno = vfs_dup_fd(oldfd_s, &newfd_s))) {
+ __current->fdtable->fds[newfd] = newfd_s;
+ return newfd;
+ }
+
+ return DO_STATUS(errno);
+}
+
+__DEFINE_LXSYSCALL2(int,
+ symlink,
+ const char*,
+ pathname,
+ const char*,
+ link_target)
+{
+ int errno;
+ struct v_dnode* dnode;
+ if ((errno = vfs_walk(NULL, pathname, &dnode, NULL, 0))) {
+ goto done;
+ }
+ if ((dnode->super_block->fs->types & FSTYPE_ROFS)) {
+ errno = EROFS;
+ goto done;
+ }
+ if (!dnode->inode->ops.symlink) {
+ errno = ENOTSUP;
+ goto done;
+ }
+
+ errno = dnode->inode->ops.symlink(dnode->inode, link_target);
+
+done:
+ return DO_STATUS(errno);
+}
\ No newline at end of file
#include <lunaix/tty/tty.h>
#include <lunaix/clock.h>
+#include <lunaix/device.h>
#include <lunaix/lxconsole.h>
#include <lunaix/mm/kalloc.h>
#include <lunaix/mm/page.h>
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();
#include <klibc/string.h>
+#include <lunaix/device.h>
+#include <lunaix/keyboard.h>
#include <lunaix/lxconsole.h>
#include <lunaix/mm/pmm.h>
+#include <lunaix/mm/valloc.h>
#include <lunaix/mm/vmm.h>
+#include <lunaix/sched.h>
#include <lunaix/tty/console.h>
#include <lunaix/tty/tty.h>
static struct console lx_console;
+int
+__tty_write(struct device* dev, void* buf, size_t offset, size_t len);
+
+int
+__tty_read(struct device* dev, void* buf, size_t offset, size_t len);
+
void
lxconsole_init()
{
memset(&lx_console, 0, sizeof(lx_console));
- lx_console.buffer.data = VGA_BUFFER_VADDR + 0x1000;
- lx_console.buffer.size = 8192;
- mutex_init(&lx_console.buffer.lock);
+ fifo_init(&lx_console.output, VGA_BUFFER_VADDR + 0x1000, 8192, 0);
+ fifo_init(&lx_console.input, valloc(4096), 4096, 0);
+
+ // FIXME use valloc to allocate console buffer.
+ // In doing this, the console buffer can only be accessed from kernel mode
+ // any direct write to this buffer from user land should be purged!
// 分配控制台缓存
- for (size_t i = 0; i < PG_ALIGN(lx_console.buffer.size); i += PG_SIZE) {
+ for (size_t i = 0; i < PG_ALIGN(lx_console.output.size); i += PG_SIZE) {
uintptr_t pa = pmm_alloc_page(KERNEL_PID, 0);
vmm_set_mapping(PD_REFERENCED,
- (uintptr_t)lx_console.buffer.data + i,
+ (uintptr_t)lx_console.output.data + i,
pa,
PG_PREM_URW,
0);
}
- memset(lx_console.buffer.data, 0, lx_console.buffer.size);
-
lx_console.flush_timer = NULL;
+
+ struct device* tty_dev = device_addseq(NULL, &lx_console, "tty");
+ tty_dev->write = __tty_write;
+ tty_dev->read = __tty_read;
+}
+
+int
+__tty_write(struct device* dev, void* buf, size_t offset, size_t len)
+{
+ struct console* console = (struct console*)dev->underlay;
+ console_write(console, buf, len);
+}
+
+int
+__tty_read(struct device* dev, void* buf, size_t offset, size_t len)
+{
+ struct kdb_keyinfo_pkt keyevent;
+ struct console* console = (struct console*)dev->underlay;
+
+ size_t count = fifo_read(&console->input, buf, len);
+ if (count > 0 && ((char*)buf)[count - 1] == '\n') {
+ return count;
+ }
+
+ while (count < len) {
+ // FIXME RACE!
+ // Consider two process that is polling the input key simultaneously.
+ // When a key is arrived, one of the processes will win the race and
+ // swallow it (advancing the key buffer pointer)
+ if (!kbd_recv_key(&keyevent)) {
+ sched_yield();
+ continue;
+ }
+ if (!(keyevent.state & KBD_KEY_FPRESSED)) {
+ continue;
+ }
+ if ((keyevent.keycode & 0xff00) > KEYPAD) {
+ continue;
+ }
+
+ char c = (char)(keyevent.keycode & 0x00ff);
+ if (c == 0x08) {
+ if (fifo_backone(&console->input)) {
+ console_write_char(c);
+ }
+ continue;
+ }
+ console_write_char(c);
+ if (!fifo_putone(&console->input, c) || c == '\n') {
+ break;
+ }
+ }
+ return count + fifo_read(&console->input, buf + count, len - count);
}
void
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 &&
__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;
}
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);
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
(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);
pos = list_entry(pile->free.next, typeof(*pos), cakes);
}
-found:
piece_index_t found_index = pos->next_free;
pos->next_free = pos->free_list[found_index];
pos->used_pieces++;
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 };
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;
}
}
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--;
-#include <lunaix/mm/kalloc.h>
#include <lunaix/mm/region.h>
+#include <lunaix/mm/valloc.h>
void
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 };
#include <klibc/string.h>
#include <lunaix/mm/cake.h>
#include <lunaix/mm/valloc.h>
+#include <lunaix/spike.h>
-#define MAX_CLASS 6
+#define CLASS_LEN(class) (sizeof(class) / sizeof(class[0]))
-static char piles_names[MAX_CLASS][PILE_NAME_MAXLEN] = {
- "valloc_16", "valloc_32", "valloc_64",
- "valloc_128", "valloc_256", "valloc_512"
+static char piles_names[][PILE_NAME_MAXLEN] = {
+ "valloc_8", "valloc_16", "valloc_32", "valloc_64",
+ "valloc_128", "valloc_256", "valloc_512", "valloc_1k",
+ "valloc_2k", "valloc_4k", "valloc_8k"
};
-static char piles_names_dma[MAX_CLASS][PILE_NAME_MAXLEN] = {
+static char piles_names_dma[][PILE_NAME_MAXLEN] = {
"valloc_dma_128", "valloc_dma_256", "valloc_dma_512",
"valloc_dma_1k", "valloc_dma_2k", "valloc_dma_4k"
};
-static struct cake_pile* piles[MAX_CLASS];
-static struct cake_pile* piles_dma[MAX_CLASS];
+static struct cake_pile* piles[CLASS_LEN(piles_names)];
+static struct cake_pile* piles_dma[CLASS_LEN(piles_names_dma)];
void
valloc_init()
{
- for (size_t i = 0; i < MAX_CLASS; i++) {
- int size = 1 << (i + 4);
- piles[i] = cake_new_pile(&piles_names[i], size, 1, 0);
+ for (size_t i = 0; i < CLASS_LEN(piles_names); i++) {
+ int size = 1 << (i + 3);
+ piles[i] = cake_new_pile(&piles_names[i], size, size > 1024 ? 8 : 1, 0);
}
// DMA 内存保证128字节对齐
- for (size_t i = 0; i < MAX_CLASS; i++) {
+ for (size_t i = 0; i < CLASS_LEN(piles_names_dma); i++) {
int size = 1 << (i + 7);
piles_dma[i] = cake_new_pile(
- &piles_names_dma[i], size, size > 1024 ? 8 : 1, PILE_CACHELINE);
+ &piles_names_dma[i], size, size > 1024 ? 4 : 1, PILE_CACHELINE);
}
}
void*
-__valloc(unsigned int size, struct cake_pile** segregate_list)
+__valloc(unsigned int size,
+ struct cake_pile** segregate_list,
+ size_t len,
+ size_t boffset)
{
- size_t i = 0;
- for (; i < MAX_CLASS; i++) {
- if (segregate_list[i]->piece_size >= size) {
- goto found_class;
- }
- }
+ size_t i = ILOG2(size);
+ i += (size - (1 << i) != 0);
+ i -= boffset;
- return NULL;
+ if (i >= len)
+ return NULL;
-found_class:
return cake_grab(segregate_list[i]);
}
void
-__vfree(void* ptr, struct cake_pile** segregate_list)
+__vfree(void* ptr, struct cake_pile** segregate_list, size_t len)
{
size_t i = 0;
- for (; i < MAX_CLASS; i++) {
+ for (; i < len; i++) {
if (cake_release(segregate_list[i], ptr)) {
return;
}
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;
}
void
vfree_dma(void* ptr)
{
- __vfree(ptr, &piles_dma);
+ __vfree(ptr, &piles_dma, CLASS_LEN(piles_names_dma));
}
\ No newline at end of file
} 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) {
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;
#include <arch/x86/boot/multiboot.h>
+#include <lunaix/block.h>
#include <lunaix/common.h>
+#include <lunaix/fctrl.h>
+#include <lunaix/fs.h>
+#include <lunaix/fs/twifs.h>
#include <lunaix/lunistd.h>
#include <lunaix/lxconsole.h>
#include <lunaix/mm/cake.h>
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();
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();
_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
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();
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();
#include <lunaix/common.h>
#include <lunaix/mm/pmm.h>
#include <lunaix/mm/region.h>
+#include <lunaix/mm/valloc.h>
#include <lunaix/mm/vmm.h>
#include <lunaix/process.h>
#include <lunaix/spike.h>
struct proc_info* proc = pid ? get_process(pid) : __current;
if (!proc) {
- __current->k_status = LXINVL;
+ __current->k_status = EINVAL;
return -1;
}
struct proc_info* gruppenfuhrer = get_process(pgid);
if (!gruppenfuhrer || proc->pgid == proc->pid) {
- __current->k_status = LXINVL;
+ __current->k_status = EINVAL;
return -1;
}
}
}
+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()
{
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);
#include <lunaix/mm/kalloc.h>
#include <lunaix/mm/pmm.h>
+#include <lunaix/mm/valloc.h>
#include <lunaix/mm/vmm.h>
#include <lunaix/process.h>
#include <lunaix/sched.h>
return _wait(pid, status, options);
}
+__DEFINE_LXSYSCALL(int, geterrno)
+{
+ return __current->k_status;
+}
+
pid_t
_wait(pid_t wpid, int* status, int options)
{
proc->pid = i;
proc->created = clock_systime();
proc->pgid = proc->pid;
+ proc->fdtable = vzalloc(sizeof(struct v_fdtable));
llist_init_head(&proc->mm.regions);
llist_init_head(&proc->children);
assert(process == &sched_ctx._procs[process->pid]);
if (process->state != PS_CREATED) {
- __current->k_status = LXINVL;
+ __current->k_status = EINVAL;
return;
}
{
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)
{
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();
signal_send(pid_t pid, int signum)
{
if (signum < 0 || signum >= _SIG_NUM) {
- __current->k_status = LXINVL;
+ __current->k_status = EINVAL;
return -1;
}
} 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;
}
send_single:
if (PROC_TERMINATED(proc->state)) {
- __current->k_status = LXINVL;
+ __current->k_status = EINVAL;
return -1;
}
__SIGSET(proc->sig_pending, signum);
-#include <lunaix/clock.h>
-#include <lunaix/timer.h>
#include <hal/rtc.h>
+#include <lunaix/clock.h>
#include <lunaix/spike.h>
+#include <lunaix/timer.h>
static volatile time_t sys_time;
-void clock_systime_counter(void* arg);
+void
+clock_systime_counter(void* arg);
void
-clock_init() {
+clock_init()
+{
if (!timer_context()) {
panick("Systimer not initialized");
}
-
+
// 系统计时器每毫秒累加。
timer_run_ms(1, clock_systime_counter, NULL, TIMER_MODE_PERIODIC);
}
-void clock_systime_counter(void* arg) {
+void
+clock_systime_counter(void* arg)
+{
sys_time++;
}
int
-clock_datatime_eq(datetime_t* a, datetime_t* b) {
- return a->year == b->year &&
- a->month == b->month &&
- a->day == b->day &&
- a->weekday == b->weekday &&
- a->minute == b->minute &&
+clock_datatime_eq(datetime_t* a, datetime_t* b)
+{
+ return a->year == b->year && a->month == b->month && a->day == b->day &&
+ a->weekday == b->weekday && a->minute == b->minute &&
a->second == b->second;
}
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);
datetime->second = bcd2dec(datetime->second);
}
-
// To 24 hour format
if (!RTC_24HRS_ENCODED(regbv) && (datetime->hour >> 7)) {
datetime->hour = (12 + datetime->hour & 0x80);
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
#include <hal/apic.h>
#include <hal/rtc.h>
-#include <lunaix/mm/kalloc.h>
+#include <lunaix/mm/cake.h>
+#include <lunaix/mm/valloc.h>
#include <lunaix/sched.h>
#include <lunaix/spike.h>
#include <lunaix/syslog.h>
static volatile uint32_t sched_ticks = 0;
static volatile uint32_t sched_ticks_counter = 0;
+static struct cake_pile* timer_pile;
+
#define APIC_CALIBRATION_CONST 0x100000
void
timer_init_context()
{
+ timer_pile = cake_new_pile("timer", sizeof(struct lx_timer), 1, 0);
timer_ctx =
- (struct lx_timer_context*)lxmalloc(sizeof(struct lx_timer_context));
+ (struct lx_timer_context*)valloc(sizeof(struct lx_timer_context));
assert_msg(timer_ctx, "Fail to initialize timer contex");
- timer_ctx->active_timers =
- (struct lx_timer*)lxmalloc(sizeof(struct lx_timer));
+ timer_ctx->active_timers = (struct lx_timer*)cake_grab(timer_pile);
llist_init_head(timer_ctx->active_timers);
}
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;
pos->counter = pos->deadline;
} else {
llist_delete(&pos->link);
- lxfree(pos);
+ cake_release(timer_pile, pos);
}
}
--- /dev/null
+#include <lib/crc.h>
+
+// crc32 lookup table. (https://web.mit.edu/freebsd/head/sys/libkern/crc32.c)
+const unsigned int crc32_tab[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+/**
+ * @brief CRC32 checksum
+ * ref: https://en.wikipedia.org/wiki/Cyclic_redundancy_check#CRC-32_algorithm
+ * @param data
+ * @param size
+ * @return unsigned int
+ */
+unsigned int
+crc32b(unsigned char* data, unsigned int size)
+{
+ unsigned int crc = (unsigned int)-1, i = 0;
+
+ while (i < size) {
+ crc = (crc >> 8) ^ crc32_tab[(crc ^ data[i]) & 0xff];
+ i = i + 1;
+ }
+
+ return ~crc;
+}
\ No newline at end of file
--- /dev/null
+#include <lib/hash.h>
+
+/**
+ * @brief Simple string hash function
+ *
+ * ref: https://stackoverflow.com/a/7666577
+ *
+ * @param str
+ * @return unsigned int
+ */
+uint32_t
+strhash_32(unsigned char* str, uint32_t truncate_to)
+{
+ if (!str)
+ return 0;
+
+ uint32_t hash = 5381;
+ int c;
+
+ while ((c = *str++))
+ hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+ return hash >> (HASH_SIZE_BITS - truncate_to);
+}
\ No newline at end of file
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.
if (max_len && ptr >= max_len - 1) {
break;
}
-
+
if (*fmt != '%') {
buffer[ptr++] = *fmt;
continue;
// 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 == '*') {
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 == '*') {
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++;
}
} 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";
}
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;
}
}
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
--- /dev/null
+#include <klibc/string.h>
+
+int
+streq(const char* a, const char* b)
+{
+ while (*a == *b) {
+ if (!(*a)) {
+ return 1;
+ }
+ a++;
+ b++;
+ }
+ return 0;
+}
\ No newline at end of file