diff options
| author | Richard Qin <richard.qin.x@gmail.com> | 2026-01-02 00:47:16 +0800 |
|---|---|---|
| committer | Richard Qin <richard.qin.x@gmail.com> | 2026-01-02 00:58:45 +0800 |
| commit | d8eaa13f2efc1eeca4e5f230d5a2d535aaf27338 (patch) | |
| tree | 6ca02e2a2d1b1121620431059e322724a3c94a33 /src | |
| parent | 2dde56422dcfb94affee2baffc8d240ad16ad4b2 (diff) | |
| download | lume-d8eaa13f2efc1eeca4e5f230d5a2d535aaf27338.tar.gz lume-d8eaa13f2efc1eeca4e5f230d5a2d535aaf27338.tar.xz | |
dev(file-system): establish VFS and Read-only FAT32 File System
Diffstat (limited to 'src')
| -rw-r--r-- | src/drivers/virtio_dist.cc | 36 | ||||
| -rw-r--r-- | src/fs/fat32.cc | 325 | ||||
| -rw-r--r-- | src/fs/file.cc | 140 | ||||
| -rw-r--r-- | src/fs/fs.cc | 190 | ||||
| -rw-r--r-- | src/kernel/bio.cc | 135 | ||||
| -rw-r--r-- | src/kernel/cxx.cc | 68 | ||||
| -rw-r--r-- | src/kernel/main.cc | 8 | ||||
| -rw-r--r-- | src/kernel/mm/vm.cc | 47 | ||||
| -rw-r--r-- | src/kernel/proc/proc.cc | 33 | ||||
| -rw-r--r-- | src/kernel/syscall.cc | 165 | ||||
| -rw-r--r-- | src/lib/string.cc | 13 | ||||
| -rw-r--r-- | src/user/init.cc | 36 |
12 files changed, 1162 insertions, 34 deletions
diff --git a/src/drivers/virtio_dist.cc b/src/drivers/virtio_dist.cc index 99d100f..9c981d4 100644 --- a/src/drivers/virtio_dist.cc +++ b/src/drivers/virtio_dist.cc @@ -5,6 +5,7 @@ #include "lib/string.h" #include "drivers/uart.h" #include "kernel/proc.h" +#include "kernel/buf.h" static uint64 virtio_base = 0x10001000; @@ -335,4 +336,39 @@ namespace VirtIO PMM::free_page(buf); } + + void test_bio() + { + Drivers::uart_puts(ANSI_BLUE "[Bio] Starting Buffer Cache Test...\n" ANSI_RESET); + + struct Buf *b = BufferCache::bread(0, 100); + + Drivers::uart_puts("[Bio] Bread block 100 (1st time).\n"); + + b->data[0] = 'L'; + b->data[1] = 'u'; + b->data[2] = 'm'; + b->data[3] = 'e'; + b->data[4] = '\0'; + + BufferCache::bwrite(b); + Drivers::uart_puts("[Bio] Bwrite block 100.\n"); + + BufferCache::brelse(b); + Drivers::uart_puts("[Bio] Brelease block 100.\n"); + + struct Buf *b2 = BufferCache::bread(0, 100); + Drivers::uart_puts("[Bio] Bread block 100 (2nd time).\n"); + + if (b2->data[0] == 'L' && b2->data[1] == 'u' && b2->data[3] == 'e') + { + Drivers::uart_puts(ANSI_GREEN "[Bio] Data verification PASSED.\n" ANSI_RESET); + } + else + { + Drivers::uart_puts(ANSI_RED "[Bio] Data verification FAILED.\n" ANSI_RESET); + } + + BufferCache::brelse(b2); + } }
\ No newline at end of file diff --git a/src/fs/fat32.cc b/src/fs/fat32.cc new file mode 100644 index 0000000..7ef829a --- /dev/null +++ b/src/fs/fat32.cc @@ -0,0 +1,325 @@ +#include "fs/fat32.h" +#include "lib/string.h" +#include "drivers/uart.h" +#include "kernel/mm.h" +#include "kernel/proc.h" + +FAT32FileSystem fat32_fs; + +// FAT32 FileSystem Implementation + +void FAT32FileSystem::init() +{ + struct Buf *b = BufferCache::bread(0, 0); + uint8 *data = (uint8 *)b->data; + struct FAT32_BPB *bpb = (struct FAT32_BPB *)data; + + uint32 partition_lba = 0; + + bool is_valid_bpb = (bpb->bytesPerSector == 512) && (bpb->rootClus != 0); + + if (!is_valid_bpb) + { + Drivers::uart_puts("[FAT32] Sector 0 is not a valid BPB. Checking MBR...\n"); + + if (data[510] != 0x55 || data[511] != 0xAA) + { + Drivers::uart_puts("[FAT32] Panic: Invalid Disk Signature!\n"); + while (1) + ; + } + + uint32 lba = *(uint32 *)(data + 446 + 8); + + if (lba > 0) + { + Drivers::uart_puts("[FAT32] MBR Partition 1 found @ Sector "); + Drivers::uart_put_int(lba); + Drivers::uart_puts("\n"); + partition_lba = lba; + } + else + { + Drivers::uart_puts("[FAT32] Panic: No partition found.\n"); + while (1) + ; + } + + BufferCache::brelse(b); + + b = BufferCache::bread(0, partition_lba / 2); + bpb = (struct FAT32_BPB *)b->data; + } + + if (bpb->bytesPerSector != 512) + { + Drivers::uart_puts("[FAT32] Panic: Invalid FAT32 BPB in partition.\n"); + while (1) + ; + } + + uint32 fat_sz = bpb->FATSz32; + uint32 reserved_sec = bpb->reservedSecCnt; + uint8 num_fats = bpb->numFATs; + + sectors_per_cluster = bpb->secPerClus; + bytes_per_cluster = sectors_per_cluster * 512; + root_cluster = bpb->rootClus; + + fat_start_sector = partition_lba + reserved_sec; + data_start_sector = partition_lba + reserved_sec + (fat_sz * num_fats); + + Drivers::uart_puts("[FAT32] Init Success: RootClus="); + Drivers::uart_put_int(root_cluster); + Drivers::uart_puts(", DataStart="); + Drivers::uart_put_int(data_start_sector); + Drivers::uart_puts("\n"); + + BufferCache::brelse(b); +} + +Inode *FAT32FileSystem::root() +{ + FAT32Inode *ip = new FAT32Inode(); + + ip->fs = this; + ip->dev = 0; + ip->inum = root_cluster; + ip->ref_cnt = 1; + ip->valid = 1; + ip->type = T_DIR; + ip->size = 0; + ip->nlink = 1; + + ip->first_clus = root_cluster; + ip->parent_clus = 0; + + return ip; +} + +uint32 FAT32FileSystem::cluster_to_sector(uint32 cluster) +{ + return data_start_sector + (cluster - 2) * sectors_per_cluster; +} + +uint32 FAT32FileSystem::next_cluster(uint32 cluster) +{ + uint32 fat_offset = cluster * 4; + uint32 fat_sector = fat_start_sector + (fat_offset / 512); + uint32 ent_offset = fat_offset % 512; + + // block = sector / 2 + // offset in block = (sector % 2) * 512 + ent_offset + + struct Buf *b = BufferCache::bread(0, fat_sector / 2); + + uint32 block_offset = (fat_sector % 2) * 512 + ent_offset; + uint32 next = *(uint32 *)(b->data + block_offset); + + BufferCache::brelse(b); + + return next & 0x0FFFFFFF; +} + +// FAT32 Inode Implementation + +static bool match_name(const char *disk_name, const char *target) +{ + char temp[13]; + int i, j; + + for (i = 0; i < 8 && disk_name[i] != ' '; i++) + temp[i] = disk_name[i]; + if (disk_name[8] != ' ') + { + temp[i++] = '.'; + for (j = 0; j < 3 && disk_name[8 + j] != ' '; j++) + temp[i++] = disk_name[8 + j]; + } + temp[i] = 0; + return strcasecmp(temp, target) == 0; +} + +int FAT32Inode::read(char *dst, uint32 off, uint32 n, int isUser) +{ + if (first_clus == 0) + return 0; + + uint32 tot = 0; + uint32 clus = first_clus; + uint32 clus_sz = fs->bytes_per_cluster; + + uint32 skip = off / clus_sz; + uint32 current_off = off % clus_sz; + + while (skip > 0) + { + clus = fs->next_cluster(clus); + if (clus >= 0x0FFFFFF8) + return 0; + skip--; + } + + while (tot < n) + { + uint32 sec_in_clus = current_off / 512; + + if (sec_in_clus >= fs->sectors_per_cluster) + { + clus = fs->next_cluster(clus); + if (clus >= 0x0FFFFFF8) + break; + current_off = 0; + continue; + } + + uint32 sec = fs->cluster_to_sector(clus) + sec_in_clus; + uint32 off_in_sec = current_off % 512; + + uint32 m = 512 - off_in_sec; + if (n - tot < m) + m = n - tot; + + struct Buf *b = BufferCache::bread(dev, sec / 2); + uint32 block_offset = (sec % 2) * 512 + off_in_sec; + + if (isUser) + { + if (VM::copyout(myproc()->pagetable, (uint64)dst, (char *)(b->data + block_offset), m) < 0) + { + BufferCache::brelse(b); + return -1; + } + } + else + { + memmove(dst, b->data + block_offset, m); + } + BufferCache::brelse(b); + + tot += m; + dst += m; + current_off += m; + } + return tot; +} + +Inode *FAT32Inode::lookup(const char *name) +{ + if (type != T_DIR) + return nullptr; + + uint32 clus = first_clus; + struct FAT32_DirEnt de; + + while (clus < 0x0FFFFFF8) + { + uint32 sec = fs->cluster_to_sector(clus); + + for (int i = 0; i < fs->sectors_per_cluster; i++) + { + uint32 current_sec = sec + i; + struct Buf *b = BufferCache::bread(dev, current_sec / 2); + uint32 block_base = (current_sec % 2) * 512; + + for (int off = 0; off < 512; off += 32) + { + memmove(&de, b->data + block_base + off, 32); + + if (de.name[0] == 0x00) + { + BufferCache::brelse(b); + return nullptr; + } + if (de.name[0] == 0xE5) + continue; + if (de.attr & ATTR_LONG_NAME) + continue; + + if (match_name(de.name, name)) + { + FAT32Inode *ip = new FAT32Inode(); + ip->fs = fs; + ip->dev = dev; + ip->type = (de.attr & ATTR_DIRECTORY) ? T_DIR : T_FILE; + ip->size = de.fileSize; + ip->first_clus = (de.fstClusHI << 16) | de.fstClusLO; + ip->inum = ip->first_clus; + ip->nlink = 1; + ip->ref_cnt = 1; + ip->valid = 1; + + BufferCache::brelse(b); + return ip; + } + } + BufferCache::brelse(b); + } + clus = fs->next_cluster(clus); + } + return nullptr; +} + +// Placeholder +void FAT32Inode::update() {} +int FAT32Inode::write(const char *src, uint32 off, uint32 n, int isUser) { return -1; } +Inode *FAT32Inode::create(const char *name, short type, short major, short minor) { return nullptr; } +void FAT32Inode::truncate() {} +uint32 FAT32FileSystem::alloc_cluster() { return 0; } + +// Test Function +void fat32_test() +{ + static bool inited = false; + if (!inited) + { + fat32_fs.init(); + inited = true; + } + + Drivers::uart_puts("\n[FAT32] Starting Test via Syscall...\n"); + + Inode *root = fat32_fs.root(); + if (root) + { + Drivers::uart_puts("[FAT32] Root Inode retrieved. Inum: "); + Drivers::uart_put_int(root->inum); + Drivers::uart_puts("\n"); + + Drivers::uart_puts("[FAT32] Looking for TEST.TXT...\n"); + Inode *node = root->lookup("test.txt"); + + if (node) + { + Drivers::uart_puts("[FAT32] Found TEST.TXT! Size: "); + Drivers::uart_put_int(node->size); + Drivers::uart_puts("\n"); + + char buf[128]; + int n = node->read(buf, 0, 127, 0); + if (n > 0) + { + buf[n] = 0; + Drivers::uart_puts("[FAT32] Content:\n>> "); + Drivers::uart_puts(buf); + Drivers::uart_puts("\n"); + } + else + { + Drivers::uart_puts("[FAT32] Read returned 0.\n"); + } + VFS::iput(node); + } + else + { + Drivers::uart_puts("[FAT32] TEST.TXT not found.\n"); + } + VFS::iput(root); + } + else + { + Drivers::uart_puts("[FAT32] Failed to get root inode.\n"); + } + + Drivers::uart_puts("[FAT32] Test Finished.\n"); +}
\ No newline at end of file diff --git a/src/fs/file.cc b/src/fs/file.cc new file mode 100644 index 0000000..48af49e --- /dev/null +++ b/src/fs/file.cc @@ -0,0 +1,140 @@ +#include "fs/file.h" +#include "kernel/spinlock.h" +#include "kernel/mm.h" +#include "drivers/uart.h" +#include "kernel/proc.h" + +#define NFILE 100 + +namespace FileTable +{ + struct + { + Spinlock lock; + struct file files[NFILE]; + } ftable; + + void init() + { + ftable.lock.init("file_table"); + } + + struct file *alloc() + { + struct file *f; + ftable.lock.acquire(); + for (f = ftable.files; f < ftable.files + NFILE; f++) + { + if (f->ref == 0) + { + f->ref = 1; + ftable.lock.release(); + return f; + } + } + ftable.lock.release(); + return nullptr; + } + + struct file *dup(struct file *f) + { + ftable.lock.acquire(); + if (f->ref < 1) + { + Drivers::uart_puts("panic: file dup\n"); + while (1) + ; + } + f->ref++; + ftable.lock.release(); + return f; + } + + void close(struct file *f) + { + struct file ff; + + ftable.lock.acquire(); + if(f->ref < 1) + { + Drivers::uart_puts("panic: file close\n"); + while (1) + ; + } + f->ref--; + if (f->ref > 0) + { + ftable.lock.release(); + return; + } + + ff = *f; + f->ref = 0; + f->type = FD_NONE; + ftable.lock.release(); + if (ff.type == FD_INODE) + { + // Release the corresponding Inode + VFS::iput(ff.ip); + } + else if (ff.type == FD_PIPE) + { + // pipeclose(ff.pipe, ff.writable); + } + } + + int read(struct file *f, uint64 addr, int n) + { + if (f->readable == 0) + return -1; + if (f->type == FD_INODE) + { + VFS::ilock(f->ip); + int r = f->ip->read((char*)addr, f->off, n, 1); + if(r > 0) + { + f->off += r; + } + VFS::iunlock(f->ip); + return r; + } + return -1; + } + + int write(struct file *f, uint64 addr, int n) + { + if (f->writable == 0) + return -1; + if (f->type == FD_INODE) + { + VFS::ilock(f->ip); + int r = f->ip->write((char *)addr, f->off, n, 1); + if (r > 0) + { + f->off += r; + } + VFS::iunlock(f->ip); + return r; + } + // else if (f->type == FD_PIPE) ... + + return -1; + } + + int stat(struct file *f, uint64 addr) + { + if (f->type == FD_INODE) + { + struct kstat st; + VFS::ilock(f->ip); + f->ip->getattr(&st); + VFS::iunlock(f->ip); + + struct Proc *p = myproc(); + if (VM::copyout(p->pagetable, addr, (char *)&st, sizeof(st)) < 0) + return -1; + return 0; + } + return -1; + } +} // namespace FileTable diff --git a/src/fs/fs.cc b/src/fs/fs.cc new file mode 100644 index 0000000..b2b91c2 --- /dev/null +++ b/src/fs/fs.cc @@ -0,0 +1,190 @@ +#include "fs/fs.h" +#include "kernel/riscv.h" +#include "drivers/uart.h" +#include "kernel/spinlock.h" +#include "kernel/proc.h" +#include "fs/fat32.h" +#include "lib/string.h" + +static Inode *global_root_inode = nullptr; + +static const char *skipelem(const char *path, char *name) +{ + const char *s; + int len; + + while (*path == '/') + path++; + if (*path == 0) + return nullptr; + + s = path; + while (*path != '/' && *path != 0) + path++; + + len = path - s; + if (len >= 128) + len = 127; + + memmove(name, s, len); + name[len] = 0; + + while (*path == '/') + path++; + return path; +} + +void Inode::getattr(struct kstat *st) +{ + st->dev = dev; + st->ino = inum; + st->type = type; + st->nlink = nlink; + st->size = size; + + st->uid = 0; + st->gid = 0; + st->mode = 0; +} + +namespace VFS +{ + void init() + { + Drivers::uart_puts("[VFS] Inode subsystem initialized.\n"); + } + + void iput(Inode *ip) + { + if (ip == nullptr) + return; + + ip->lock.acquire(); + if(ip->ref_cnt < 1) + { + Drivers::uart_puts("panic: iput ref\n"); + while (1) + ; + } + ip->ref_cnt--; + int ref = ip->ref_cnt; + ip->lock.release(); + + if (ref == 0) + { + delete ip; + } + } + + Inode* idup(Inode *ip) + { + if (ip == nullptr) + return nullptr; + + ip->lock.acquire(); + ip->ref_cnt++; + ip->lock.release(); + return ip; + } + + void ilock(Inode *ip) + { + if (ip == 0 || ip->ref_cnt < 1) + { + Drivers::uart_puts("panic: ilock\n"); + while (1) + ; + } + + ip->lock.acquire(); + + } + + void iunlock(Inode *ip) + { + if (ip == 0 || !ip->lock.holding() || ip->ref_cnt < 1) + { + Drivers::uart_puts("panic: iunlock\n"); + while (1) + ; + } + ip->lock.release(); + } + + static void iunlockput(Inode *ip) + { + iunlock(ip); + iput(ip); + } + + void mount_root(Inode *root) + { + if (global_root_inode) + { + Drivers::uart_puts("VFS: Root already mounted!\n"); + return; + } + global_root_inode = root; + Drivers::uart_puts("[VFS] Root filesystem mounted.\n"); + } + + Inode *get_root() + { + if (global_root_inode == nullptr) + { + Drivers::uart_puts("[VFS] Lazy init: Mounting FAT32...\n"); + fat32_fs.init(); + mount_root(fat32_fs.root()); + } + if (!global_root_inode) + return nullptr; + return idup(global_root_inode); + } + + Inode *namei(const char *path) + { + char name[128]; + Inode *ip, *next; + struct Proc *p = myproc(); + + if (*path == '/') + { + ip = get_root(); + } + else + { + if (p->cwd == nullptr) + { + ip = get_root(); + } + else + { + ip = idup(p->cwd); + } + } + + if (ip == nullptr) + return nullptr; + + while ((path = skipelem(path, name)) != nullptr) + { + ilock(ip); + + if (ip->type != T_DIR) + { + iunlockput(ip); + return nullptr; + } + + next = ip->lookup(name); + iunlockput(ip); + + ip = next; + if (ip == nullptr) + return nullptr; + } + + return ip; + } + +} // namespace VFS diff --git a/src/kernel/bio.cc b/src/kernel/bio.cc new file mode 100644 index 0000000..6e63d60 --- /dev/null +++ b/src/kernel/bio.cc @@ -0,0 +1,135 @@ +#include "kernel/buf.h" +#include "kernel/spinlock.h" +#include "kernel/riscv.h" +#include "drivers/virtio.h" +#include "drivers/uart.h" + +namespace BufferCache +{ + struct + { + Spinlock lock; + struct Buf buf[NBUF]; + struct Buf head; + } bcache; + + void init() + { + bcache.lock.init("bcache"); + // Initialize LRU doubly circular linked list + bcache.head.prev = &bcache.head; + bcache.head.next = &bcache.head; + for (struct Buf *b = bcache.buf; b < bcache.buf + NBUF; ++b) + { + b->lock.init("buffer"); + b->next = bcache.head.next; + b->prev = &bcache.head; + bcache.head.next->prev = b; + bcache.head.next = b; + } + Drivers::uart_puts("[Bio] Buffer cache initialized.\n"); + } + + static struct Buf* bget(uint32 dev, uint32 blockno) + { + struct Buf* b; + bcache.lock.acquire(); + + // Attempt to hit the cache + for (b = bcache.head.next; b != &bcache.head; b = b->next) + { + if (b->dev == dev && b->blockno == blockno) + { + b->refcnt++; + bcache.lock.release(); + b->lock.acquire(); // Acquire Sleep Lock + return b; + } + } + + // Cache miss, evicting LRU + for (b = bcache.head.prev; b != &bcache.head; b = b->prev) + { + if (b->refcnt == 0) + { + b->dev = dev; + b->blockno = blockno; + b->valid = 0; + b->refcnt = 1; + bcache.lock.release(); + b->lock.acquire(); + return b; + } + } + + Drivers::uart_puts("panic: bget: no buffers\n"); + while (1) + ; + } + + struct Buf* bread(uint32 dev, uint32 blockno) + { + struct Buf *b = bget(dev, blockno); + + if (!b->valid) + { + VirtIO::rw(0, b->blockno, (char *)b->data); + b->valid = 1; + } + + return b; + } + + void bwrite(struct Buf *b) + { + if (!b->lock.holding()) + { + Drivers::uart_puts("panic: bwrite\n"); + while (1) + ; + } + VirtIO::rw(1, b->blockno, (char *)b->data); + } + + void brelse(struct Buf *b) + { + if (!b->lock.holding()) + { + Drivers::uart_puts("panic: brelse\n"); + while (1) + ; + } + b->lock.release(); + + bcache.lock.acquire(); + b->refcnt--; + + if (b->refcnt == 0) + { + b->next->prev = b->prev; + b->prev->next = b->next; + + b->next = bcache.head.next; + b->prev = &bcache.head; + bcache.head.next->prev = b; + bcache.head.next = b; + } + + bcache.lock.release(); + } + + void bpin(struct Buf *b) + { + bcache.lock.acquire(); + b->refcnt++; + bcache.lock.release(); + } + + void bunpin(struct Buf* b) + { + bcache.lock.acquire(); + b->refcnt --; + bcache.lock.release(); + } + +} // namespace BufferCache diff --git a/src/kernel/cxx.cc b/src/kernel/cxx.cc new file mode 100644 index 0000000..f9541b5 --- /dev/null +++ b/src/kernel/cxx.cc @@ -0,0 +1,68 @@ +#include "common/types.h" +#include "kernel/pmm.h" +#include "drivers/uart.h" + +/* + * C++ Kernel Runtime Support + * + * * Strategy: Map directly to PMM::alloc_page(). + * Pros: Simple, works immediately for VFS. + * Cons: Allocates 4KB for every object (wasteful for small objects), + * but acceptable for current stage. + */ + +void *operator new(unsigned long size) +{ + // Safety check: PMM allocates 4096 bytes max per call + if (size > 4096) + { + Drivers::uart_puts("panic: new allocation too big (max 4096)\n"); + while (1) + ; + } + + void *p = PMM::alloc_page(); + if (!p) + { + Drivers::uart_puts("panic: new out of memory\n"); + while (1) + ; + } + // PMM::alloc_page returns zeroed memory usually, + // but standard 'new' doesn't guarantee it. + // The constructor will handle initialization. + return p; +} + +void *operator new[](unsigned long size) +{ + return operator new(size); +} + +void operator delete(void *p) +{ + if (p) + PMM::free_page(p); +} + +void operator delete[](void *p) +{ + if (p) + PMM::free_page(p); +} + +// C++14 Sized Deallocation (Required by modern compilers) +// The compiler optimizes 'delete' calls to pass the size of the object +void operator delete(void *p, unsigned long size) +{ + (void)size; // We ignore size because PMM always frees a full page + if (p) + PMM::free_page(p); +} + +void operator delete[](void *p, unsigned long size) +{ + (void)size; + if (p) + PMM::free_page(p); +}
\ No newline at end of file diff --git a/src/kernel/main.cc b/src/kernel/main.cc index 6e3bdde..9654c18 100644 --- a/src/kernel/main.cc +++ b/src/kernel/main.cc @@ -9,6 +9,11 @@ #include "kernel/trap.h" #include "kernel/timer.h" #include "kernel/cpu.h" +#include "kernel/buf.h" +#include "fs/fs.h" +#include "fs/file.h" +#include "fs/fat32.h" +#include "lib/string.h" extern void fdt_init(uint64 dtb); extern uint64 g_dtb_addr; @@ -34,6 +39,9 @@ extern "C" void kernel_main(uint64 hartid, uint64 dtb) PLIC::init(); PLIC::inithart(); VirtIO::init(); + BufferCache::init(); + VFS::init(); + FileTable::init(); Timer::init(); ProcManager::init(); // Process Management ProcManager::user_init(); // Initialize first user process diff --git a/src/kernel/mm/vm.cc b/src/kernel/mm/vm.cc index 7057d88..29e9eb7 100644 --- a/src/kernel/mm/vm.cc +++ b/src/kernel/mm/vm.cc @@ -313,6 +313,53 @@ namespace VM return 0; } + int copyinstr(uint64 *pagetable, char *dst, uint64 srcva, uint64 max) + { + uint64 n, va0, pa0; + uint64 *pte; + int got_null = 0; + uint64 len = 0; + + while (len < max) + { + va0 = PGROUNDDOWN(srcva); + pte = walk(pagetable, va0, 0); + + if (pte == nullptr || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0) + return -1; + + pa0 = PTE2PA(*pte); + + n = PGSIZE - (srcva - va0); + if (n > max - len) + n = max - len; + + char *p = (char *)(pa0 + (srcva - va0)); + while (n > 0) + { + if (*p == '\0') + { + *dst = '\0'; + got_null = 1; + break; + } + *dst = *p; + n--; + srcva++; + dst++; + p++; + len++; + } + if (got_null) + break; + } + + if (got_null) + return 0; + + return -1; + } + int handle_cow_fault(uint64 *pagetable, uint64 va) { if (va >= MAXVA) diff --git a/src/kernel/proc/proc.cc b/src/kernel/proc/proc.cc index c8b6d1d..f1f1c1d 100644 --- a/src/kernel/proc/proc.cc +++ b/src/kernel/proc/proc.cc @@ -8,6 +8,8 @@ #include "kernel/trap.h" #include "kernel/riscv.h" #include "drivers/uart.h" +#include "fs/fs.h" +#include "fs/file.h" #include "lib/string.h" #define NPROC 64 @@ -172,6 +174,9 @@ found: p->pid = nextpid++; p->priority = 0; p->cpu = mycpu(); + p->cwd = nullptr; + for (int i = 0; i < NOFILE; i++) + p->ofile[i] = nullptr; if ((p->tf = (struct Trapframe *)PMM::alloc_page()) == 0) { @@ -206,6 +211,19 @@ static void freeproc(struct Proc *p) p->kstack = 0; if (p->pagetable) VM::uvmfree(p->pagetable, p->sz); + for (int i = 0; i < NOFILE; i++) + { + if (p->ofile[i]) + { + FileTable::close(p->ofile[i]); + p->ofile[i] = nullptr; + } + } + if (p->cwd) + { + VFS::iput(p->cwd); + p->cwd = nullptr; + } p->pagetable = 0; p->sz = 0; p->pid = 0; @@ -245,6 +263,19 @@ int fork() np->parent = p; np->priority = p->priority; + for (int i = 0; i < NOFILE; i++) + { + if (p->ofile[i]) + { + np->ofile[i] = FileTable::dup(p->ofile[i]); + } + } + + if (p->cwd) + { + np->cwd = VFS::idup(p->cwd); + } + proc_mem_lock.release(); struct cpu *c = mycpu(); @@ -394,6 +425,8 @@ namespace ProcManager p->sz = stack_va + PGSIZE; strcpy(p->name, "initcode"); + p->cwd = nullptr; + proc_mem_lock.release(); struct cpu *c = &cpus[0]; diff --git a/src/kernel/syscall.cc b/src/kernel/syscall.cc index 837ac2c..afa20a1 100644 --- a/src/kernel/syscall.cc +++ b/src/kernel/syscall.cc @@ -1,5 +1,6 @@ #include "kernel/syscall.h" #include "common/types.h" +#include "common/fcntl.h" #include "kernel/proc.h" #include "kernel/riscv.h" #include "drivers/uart.h" @@ -7,6 +8,8 @@ #include "kernel/timer.h" #include "kernel/mm.h" #include "kernel/trap.h" +#include "fs/fat32.h" +#include "fs/file.h" extern "C++" int fork(); @@ -45,47 +48,126 @@ static int argint(int n, int *ip) return 0; } +static int argstr(int n, char *buf, int max) +{ + uint64 addr = argraw(n); + return VM::copyinstr(myproc()->pagetable, buf, addr, max); +} + +static int fdalloc(struct file *f) +{ + struct Proc *p = myproc(); + for (int i = 0; i < NOFILE; i++) + { + if (p->ofile[i] == 0) + { + p->ofile[i] = f; + return i; + } + } + return -1; +} + +static uint64 sys_open() +{ + char path[128]; + int omode; + int fd; + struct file *f; + Inode *ip; + + if (argstr(0, path, 128) < 0 || argint(1, &omode) < 0) + return -1; + + ip = VFS::namei(path); + if (ip == nullptr) + { + return -1; + } + + f = FileTable::alloc(); + if (f == nullptr) + { + VFS::iput(ip); + return -1; + } + + fd = fdalloc(f); + if (fd < 0) + { + f->ref = 0; + f->type = FD_NONE; + VFS::iput(ip); + return -1; + } + + f->type = FD_INODE; + f->ip = ip; + f->off = 0; + f->readable = !(omode & O_WRONLY); + f->writable = (omode & O_WRONLY) || (omode & O_RDWR); -static uint64_t sys_exit() + return fd; +} + +static uint64 sys_close() +{ + int fd; + if (argint(0, &fd) < 0) + return -1; + + struct Proc *p = myproc(); + if (fd < 0 || fd >= NOFILE || p->ofile[fd] == 0) + return -1; + + FileTable::close(p->ofile[fd]); + p->ofile[fd] = 0; + return 0; +} + +static uint64 sys_exit() { int n; if (argint(0, &n) < 0) - return static_cast<uint64_t>(-1); + return static_cast<uint64>(-1); ProcManager::exit(n); return 0; } -static uint64_t sys_fork() +static uint64 sys_fork() { - return static_cast<uint64_t>(fork()); + return static_cast<uint64>(fork()); } -static uint64_t sys_wait() +static uint64 sys_wait() { - uint64_t p = argraw(0); - return static_cast<uint64_t>(ProcManager::wait(p)); + uint64 p = argraw(0); + return static_cast<uint64>(ProcManager::wait(p)); } -static uint64_t sys_getpid() +static uint64 sys_getpid() { - return static_cast<uint64_t>(myproc()->pid); + return static_cast<uint64>(myproc()->pid); } -static uint64_t sys_putc() +static uint64 sys_putc() { char c = static_cast<char>(argraw(0)); Drivers::uart_putc(c); return 0; } -static uint64_t sys_write() +static uint64 sys_write() { - int fd; + struct file *f; int n; - uint64_t p; + uint64 p; + int fd; - if (argint(0, &fd) < 0 || argint(2, &n) < 0) - return static_cast<uint64_t>(-1); + if (argint(0, &fd) < 0 || argint(2, &n) < 0 || argint(1, (int *)&p) < 0) + return -1; + + struct Proc *proc = myproc(); p = argraw(1); @@ -95,9 +177,8 @@ static uint64_t sys_write() // Drivers::uart_put_int(n); // Drivers::uart_puts("\n"); - if (fd == 1) // stdout + if (fd == 1 && proc->ofile[fd] == nullptr) // stdout { - Proc *proc = myproc(); constexpr int MAX_WRITE_BUF = 128; char buf[MAX_WRITE_BUF]; int i = 0; @@ -108,10 +189,10 @@ static uint64_t sys_write() if (len > MAX_WRITE_BUF) len = MAX_WRITE_BUF; - if (VM::copyin(proc->pagetable, buf, p + i, static_cast<uint64_t>(len)) < 0) + if (VM::copyin(proc->pagetable, buf, p + i, static_cast<uint64>(len)) < 0) { Drivers::uart_puts("sys_write: copyin failed\n"); - return static_cast<uint64_t>(-1); + return static_cast<uint64>(-1); } for (int j = 0; j < len; j++) @@ -120,45 +201,57 @@ static uint64_t sys_write() } i += len; } - return static_cast<uint64_t>(n); + return static_cast<uint64>(n); } - return static_cast<uint64_t>(-1); + if (fd < 0 || fd >= NOFILE || (f = proc->ofile[fd]) == 0) + return static_cast<uint64>(-1); + + return FileTable::write(f, p, n); } static uint64_t sys_read() { - int fd; + struct file *f; int n; - uint64_t p; + uint64 p; + int fd; // get param: fd, buf, len - if (argint(0, &fd) < 0 || argint(2, &n) < 0) + if (argint(0, &fd) < 0 || argint(2, &n) < 0 || argint(1, (int *)&p) < 0) return -1; - p = argraw(1); - - if (fd == 0) // stdin + + struct Proc* proc = myproc(); + if (fd == 0 && proc->ofile[fd] == nullptr) { return Drivers::console_read(p, n); } + + if (fd < 0 || fd >= NOFILE || (f = proc->ofile[fd]) == 0) + return -1; + + return FileTable::read(f, p, n); + return -1; } -static uint64_t sys_sbrk() +static uint64 sys_sbrk() { int n; if (argint(0, &n) < 0) return -1; - uint64_t addr = myproc()->sz; + uint64 addr = myproc()->sz; if (ProcManager::growproc(n) < 0) return -1; return addr; } -static uint64_t sys_disk_test() +static uint64 sys_disk_test() { - VirtIO::test_rw(); + // VirtIO::test_rw(); + // VirtIO::test_bio(); + fat32_test(); return 0; } @@ -166,7 +259,7 @@ void syscall() { Proc *p = myproc(); int num = p->tf->a7; - uint64_t ret = static_cast<uint64_t>(-1); + uint64 ret = static_cast<uint64>(-1); /* Just For Debug */ // Drivers::uart_puts("Syscall: "); @@ -175,6 +268,12 @@ void syscall() switch (num) { + case SYS_open: + ret = sys_open(); + break; + case SYS_close: + ret = sys_close(); + break; case SYS_write: ret = sys_write(); break; @@ -206,7 +305,7 @@ void syscall() Drivers::uart_puts("Unknown Syscall ID: "); Drivers::print_hex(num); Drivers::uart_puts("\n"); - ret = static_cast<uint64_t>(-1); + ret = static_cast<uint64>(-1); break; } diff --git a/src/lib/string.cc b/src/lib/string.cc index bbd079d..a302fc6 100644 --- a/src/lib/string.cc +++ b/src/lib/string.cc @@ -69,3 +69,16 @@ int strcmp(const char *s1, const char *s2) } return *(const unsigned char *)s1 - *(const unsigned char *)s2; } + +int strcasecmp(const char *s1, const char *s2) +{ + while (*s1) + { + if(*s1 == *s2 || *s1 + 32 == *s2 || *s1 == *s2 + 32){ + s1++; + s2++; + } + else break; + } + return *(const unsigned char *)s1 - *(const unsigned char *)s2; +}
\ No newline at end of file diff --git a/src/user/init.cc b/src/user/init.cc index 1646f6b..27c1e2f 100644 --- a/src/user/init.cc +++ b/src/user/init.cc @@ -1,4 +1,5 @@ #include "user/user.h" +#include "common/fcntl.h" int strlen(const char *s) { @@ -149,7 +150,40 @@ void test_syscalls() int main() { - print("\n[Lume Shell] Ready.\n"); + print("\n[Lume Shell] Init process started.\n"); + print("[Test] Opening test.txt...\n"); + int fd = open("test.txt", O_RDONLY); + if (fd < 0) + { + print("[Test] Open failed (Is test.txt in fs.img?)\n"); + } + else + { + print("[Test] Open success! fd="); + print_int(fd); + print("\n"); + + char buf[64]; + int n = read(fd, buf, 63); + if (n > 0) + { + buf[n] = 0; + print("[Test] Read content:\n---\n"); + print(buf); + print("\n---\n"); + } + else + { + print("[Test] Read returned "); + print_int(n); + print("\n"); + } + close(fd); + print("[Test] File closed.\n"); + } + + + print("Commands:\n"); print(" s: Run System Call Tests (fork, wait, mm)\n"); print(" t: Run Disk Driver Test (VirtIO)\n"); |
