diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/drivers/uart.cc | 100 | ||||
| -rw-r--r-- | src/fs/fat32.cc | 475 | ||||
| -rw-r--r-- | src/fs/file.cc | 137 | ||||
| -rw-r--r-- | src/fs/fs.cc | 52 | ||||
| -rw-r--r-- | src/kernel/cxx.cc | 6 | ||||
| -rw-r--r-- | src/kernel/proc/proc.cc | 32 | ||||
| -rw-r--r-- | src/kernel/sbi.cc | 14 | ||||
| -rw-r--r-- | src/kernel/syscall.cc | 297 | ||||
| -rw-r--r-- | src/kernel/timer.cc | 38 | ||||
| -rw-r--r-- | src/kernel/trap/handler.cc | 3 | ||||
| -rw-r--r-- | src/user/echo.cc | 22 | ||||
| -rw-r--r-- | src/user/entry.S | 3 | ||||
| -rw-r--r-- | src/user/init.cc | 4 | ||||
| -rw-r--r-- | src/user/ls.cc | 112 | ||||
| -rw-r--r-- | src/user/mkdir.cc | 21 | ||||
| -rw-r--r-- | src/user/sh.cc | 53 | ||||
| -rw-r--r-- | src/user/usys.S | 3 |
17 files changed, 1260 insertions, 112 deletions
diff --git a/src/drivers/uart.cc b/src/drivers/uart.cc index 4064b16..55609ba 100644 --- a/src/drivers/uart.cc +++ b/src/drivers/uart.cc @@ -7,6 +7,15 @@ namespace Drivers { + struct + { + Spinlock lock; + char buf[128]; // Line buffer + uint32 r; // Read pointer (position taken by the user) + uint32 w; // Write pointer (position confirmed by Enter) + uint32 e; // Editing cursor (current typing position) + } cons; + // Circular buffer structure struct { @@ -21,6 +30,7 @@ namespace Drivers void uart_init() { uart_rx.lock.init("uart_rx"); + cons.lock.init("console"); uart_tx_lock.init("uart_tx"); uart_rx.r = 0; uart_rx.w = 0; @@ -119,88 +129,72 @@ namespace Drivers struct Proc *p = myproc(); int target_idx = 0; - uart_rx.lock.acquire(); + cons.lock.acquire(); while (target_idx < len) { + while (cons.r < cons.w) + { + char c = cons.buf[cons.r++ % sizeof(cons.buf)]; + cons.lock.release(); + + if (VM::copyout(p->pagetable, target + target_idx, &c, 1) < 0) + return -1; + + target_idx++; + if (c == '\n') + return target_idx; + if (target_idx == len) + return target_idx; + + cons.lock.acquire(); + } + + uart_rx.lock.acquire(); while (uart_rx.r == uart_rx.w) { - if (p->xstate != 0) + if (p->xstate) { uart_rx.lock.release(); + cons.lock.release(); return -1; } + cons.lock.release(); ProcManager::sleep(&uart_rx, &uart_rx.lock); + cons.lock.acquire(); } - char c = uart_rx.buf[uart_rx.r % UART_RX_BUF_SIZE]; - uart_rx.r++; - + char c = uart_rx.buf[uart_rx.r++ % UART_RX_BUF_SIZE]; uart_rx.lock.release(); - // 1. Handle Backspace (127 or \b) if (c == 127 || c == '\b') { - if (target_idx > 0) - { - // Erase character from screen: Backspace, Space, Backspace - uart_putc('\b'); - uart_putc(' '); - uart_putc('\b'); - target_idx--; - } - uart_rx.lock.acquire(); - continue; - } - - // 2. Handle Ctrl+U (Kill Line) - if (c == 0x15) - { - while (target_idx > 0) + if (cons.e != cons.w) { + cons.e--; uart_putc('\b'); uart_putc(' '); uart_putc('\b'); - target_idx--; } - uart_rx.lock.acquire(); - continue; } - - // 3. Handle Ctrl+L (Clear Screen) - if (c == 0x0C) + else { - uart_puts(ANSI_CLEAR); - uart_puts("$ "); - uart_rx.lock.acquire(); - continue; - } - - // 4. Handle Return (CR -> LF) - if (c == '\r') - { - c = '\n'; - } + if (c == '\r') + c = '\n'; - // Echo back to user - // uart_putc(c); + uart_putc(c); - if (VM::copyout(p->pagetable, target + target_idx, &c, 1) < 0) - { - return -1; - } - - target_idx++; + cons.buf[cons.e++ % sizeof(cons.buf)] = c; - if (c == '\n') - { - return target_idx; + if (c == '\n' || cons.e == cons.w + sizeof(cons.buf)) + { + cons.w = cons.e; + ProcManager::wakeup(&cons); + } } - - uart_rx.lock.acquire(); } - uart_rx.lock.release(); + cons.lock.release(); return target_idx; } }
\ No newline at end of file diff --git a/src/fs/fat32.cc b/src/fs/fat32.cc index 7ef829a..5c70f5a 100644 --- a/src/fs/fat32.cc +++ b/src/fs/fat32.cc @@ -6,6 +6,35 @@ FAT32FileSystem fat32_fs; +// Helper function +static void generate_short_name(char *dst, const char *src) +{ + memset(dst, ' ', 11); + + int i = 0; + for (; *src && *src != '.' && i < 8; src++) + { + char c = *src; + if (c >= 'a' && c <= 'z') + c -= 32; + dst[i++] = c; + } + + while (*src && *src != '.') + src++; + if (*src == '.') + src++; + + i = 8; + for (; *src && i < 11; src++) + { + char c = *src; + if (c >= 'a' && c <= 'z') + c -= 32; + dst[i++] = c; + } +} + // FAT32 FileSystem Implementation void FAT32FileSystem::init() @@ -59,6 +88,7 @@ void FAT32FileSystem::init() } uint32 fat_sz = bpb->FATSz32; + this->fat_sz = fat_sz; uint32 reserved_sec = bpb->reservedSecCnt; uint8 num_fats = bpb->numFATs; @@ -69,10 +99,12 @@ void FAT32FileSystem::init() fat_start_sector = partition_lba + reserved_sec; data_start_sector = partition_lba + reserved_sec + (fat_sz * num_fats); + Drivers::uart_puts(ANSI_GREEN); 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(ANSI_RESET); Drivers::uart_puts("\n"); BufferCache::brelse(b); @@ -216,7 +248,7 @@ Inode *FAT32Inode::lookup(const char *name) { uint32 sec = fs->cluster_to_sector(clus); - for (int i = 0; i < fs->sectors_per_cluster; i++) + for (uint32 i = 0; i < fs->sectors_per_cluster; i++) { uint32 current_sec = sec + i; struct Buf *b = BufferCache::bread(dev, current_sec / 2); @@ -248,6 +280,8 @@ Inode *FAT32Inode::lookup(const char *name) ip->nlink = 1; ip->ref_cnt = 1; ip->valid = 1; + ip->ent_sec = current_sec; // Log Sector + ip->ent_off = off; // Log Setoff BufferCache::brelse(b); return ip; @@ -261,11 +295,440 @@ Inode *FAT32Inode::lookup(const char *name) } // 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; } +uint32 FAT32FileSystem::alloc_cluster() +{ + uint32 fat_entries_per_sector = 512 / 4; + for (uint32 i = 0; i < fat_sz; i++) + { + uint32 current_fat_sec = fat_start_sector + i; + struct Buf *b = BufferCache::bread(0, current_fat_sec / 2); + uint32 *table = (uint32 *)(b->data + (current_fat_sec % 2) * 512); + for(uint32 j = 0; j < fat_entries_per_sector; j++) + { + if (i == 0 && j < 2) + continue; + + if ((table[j] & 0x0FFFFFFF) == 0) + { + // Find the free cluster and mark it as EOF (0x0FFFFFFF) + table[j] = 0x0FFFFFFF; + BufferCache::bwrite(b); // Write back to disk + BufferCache::brelse(b); + + uint32 cluster_idx = i * fat_entries_per_sector + j; + + // Clear the data content of the new cluster + uint32 data_sec = cluster_to_sector(cluster_idx); + for (uint32 k = 0; k < sectors_per_cluster; k++) + { + struct Buf *db = BufferCache::bread(0, (data_sec + k) / 2); + memset(db->data + ((data_sec + k) % 2) * 512, 0, 512); + BufferCache::bwrite(db); + BufferCache::brelse(db); + } + + return cluster_idx; + } + } + BufferCache::brelse(b); + } + Drivers::uart_puts("[FAT32] Out of space!\n"); + return 0; +} + +void FAT32FileSystem::free_cluster_chain(uint32 cluster) +{ + while (cluster >= 2 && cluster < 0x0FFFFFF8) + { + uint32 next = next_cluster(cluster); + + // Calculate the current cluster's position in the FAT table + uint32 fat_offset = cluster * 4; + uint32 fat_sector = fat_start_sector + (fat_offset / 512); + uint32 ent_offset = fat_offset % 512; + + // Read FAT sector + struct Buf *b = BufferCache::bread(0, fat_sector / 2); + + // Marked as idle (0x00000000) + uint32 *entry = (uint32 *)(b->data + (fat_sector % 2) * 512 + ent_offset); + *entry = 0; + + BufferCache::bwrite(b); + BufferCache::brelse(b); + + cluster = next; + } + +} + +void FAT32Inode::update() +{ + struct Buf *b = BufferCache::bread(dev, ent_sec / 2); + uint32 offset = (ent_sec % 2) * 512 + ent_off; + + struct FAT32_DirEnt *de = (struct FAT32_DirEnt *)(b->data + offset); + + // Update file size and starting cluster + de->fileSize = size; + de->fstClusHI = (uint16)((first_clus >> 16) & 0xFFFF); + de->fstClusLO = (uint16)(first_clus & 0xFFFF); + + BufferCache::bwrite(b); + BufferCache::brelse(b); +} + +int FAT32Inode::write(const char *src, uint32 off, uint32 n, int isUser) +{ + if (off > size) + { + return -1; + } + + uint32 tot = 0; + uint32 clus = first_clus; + uint32 clus_sz = fs->bytes_per_cluster; + uint32 prev_clus = 0; + + if (clus == 0) + { + clus = fs->alloc_cluster(); + if (clus == 0) + return -1; + first_clus = clus; + // Update the metadata immediately to prevent data loss in case of a power outage. + update(); + } + + uint32 skip = off / clus_sz; + uint32 current_off = off % clus_sz; + + while (skip > 0) + { + prev_clus = clus; + clus = fs->next_cluster(clus); + if (clus >= 0x0FFFFFF8) + { + return -1; + } + skip--; + } + while (tot < n) + { + if (current_off == clus_sz) + { + uint32 next = fs->next_cluster(clus); + if (next >= 0x0FFFFFF8) + { + uint32 new_clus = fs->alloc_cluster(); + if (new_clus == 0) + break; + + // Point the current cluster to the new cluster (update the FAT table) + uint32 fat_offset = clus * 4; + uint32 fat_sec = fs->fat_start_sector + (fat_offset / 512); + struct Buf *fat_b = BufferCache::bread(dev, fat_sec / 2); + uint32 *entry = (uint32 *)(fat_b->data + (fat_sec % 2) * 512 + (fat_offset % 512)); + *entry = new_clus; // Link + BufferCache::bwrite(fat_b); + BufferCache::brelse(fat_b); + + clus = new_clus; + } + else + { + clus = next; + } + current_off = 0; + } + + // Calculate the physical sector to write + uint32 sec_in_clus = current_off / 512; + uint32 sec = fs->cluster_to_sector(clus) + sec_in_clus; + uint32 off_in_sec = current_off % 512; + + // Calculate how many bytes can be written this time + 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::copyin(myproc()->pagetable, (char *)(b->data + block_offset), (uint64)src, m) < 0) + { + BufferCache::brelse(b); + return -1; + } + } + else + { + memmove(b->data + block_offset, src, m); + } + + BufferCache::bwrite(b); + BufferCache::brelse(b); + + tot += m; + src += m; + current_off += m; + } + if (off + n > size) + { + size = off + n; + update(); + } + + return tot; +} + +Inode *FAT32Inode::create(const char *name, short type, short major, short minor) +{ + Inode *exist = lookup(name); + if (exist) + { + return exist; + } + + struct FAT32_DirEnt de; + memset(&de, 0, sizeof(de)); + generate_short_name(de.name, name); + de.attr = (type == T_DIR) ? ATTR_DIRECTORY : ATTR_ARCHIVE; + + uint32 new_dir_clus = 0; + if (type == T_DIR) + { + new_dir_clus = fs->alloc_cluster(); + if (new_dir_clus == 0) + return nullptr; + + de.fstClusHI = (uint16)((new_dir_clus >> 16) & 0xFFFF); + de.fstClusLO = (uint16)(new_dir_clus & 0xFFFF); + } + else + { + de.fileSize = 0; + } + + uint32 clus = first_clus; + bool written = false; + + while (true) + { + uint32 sec = fs->cluster_to_sector(clus); + + for (uint32 i = 0; i < fs->sectors_per_cluster; i++) + { + struct Buf *b = BufferCache::bread(dev, (sec + i) / 2); + uint8 *data = (uint8 *)b->data + ((sec + i) % 2) * 512; + + for (int off = 0; off < 512; off += 32) + { + if (data[off] == 0x00 || data[off] == 0xE5) + { + memmove(data + off, &de, 32); + BufferCache::bwrite(b); + BufferCache::brelse(b); + written = true; + break; + } + } + + if (written) + break; + BufferCache::brelse(b); + } + + if (written) + break; + + uint32 next = fs->next_cluster(clus); + if (next >= 0x0FFFFFF8) + { + uint32 new_parent_clus = fs->alloc_cluster(); + if (new_parent_clus == 0) + return nullptr; + + uint32 fat_off = clus * 4; + uint32 fat_sec = fs->fat_start_sector + (fat_off / 512); + struct Buf *fb = BufferCache::bread(dev, fat_sec / 2); + *(uint32 *)(fb->data + (fat_sec % 2) * 512 + (fat_off % 512)) = new_parent_clus; + BufferCache::bwrite(fb); + BufferCache::brelse(fb); + + uint32 s = fs->cluster_to_sector(new_parent_clus); + for (uint32 k = 0; k < fs->sectors_per_cluster; k++) + { + struct Buf *zb = BufferCache::bread(dev, (s + k) / 2); + uint8 *zdata = (uint8 *)zb->data + ((s + k) % 2) * 512; + memset(zdata, 0, 512); + + if (k == 0) + { + memmove(zdata, &de, 32); + } + + BufferCache::bwrite(zb); + BufferCache::brelse(zb); + } + + written = true; + break; + } + clus = next; + } + + if (written && type == T_DIR) + { + struct FAT32_DirEnt dot; + memset(&dot, 0, 32); + memset(dot.name, ' ', 11); + dot.name[0] = '.'; + dot.attr = ATTR_DIRECTORY; + dot.fstClusHI = (uint16)((new_dir_clus >> 16) & 0xFFFF); + dot.fstClusLO = (uint16)(new_dir_clus & 0xFFFF); + + struct FAT32_DirEnt dotdot; + memset(&dotdot, 0, 32); + memset(dotdot.name, ' ', 11); + dotdot.name[0] = '.'; + dotdot.name[1] = '.'; + dotdot.attr = ATTR_DIRECTORY; + + uint32 parent_clus_num = this->first_clus; + if (parent_clus_num == fs->root_cluster) + { + parent_clus_num = 0; + } + dotdot.fstClusHI = (uint16)((parent_clus_num >> 16) & 0xFFFF); + dotdot.fstClusLO = (uint16)(parent_clus_num & 0xFFFF); + + uint32 s = fs->cluster_to_sector(new_dir_clus); + + struct Buf *zb = BufferCache::bread(dev, s / 2); + uint8 *zdata = (uint8 *)zb->data + (s % 2) * 512; + + memmove(zdata, &dot, 32); // Offset 0 + memmove(zdata + 32, &dotdot, 32); // Offset 32 + + BufferCache::bwrite(zb); + BufferCache::brelse(zb); + } + + if (written) + { + return lookup(name); + } + + return nullptr; +} + +void FAT32Inode::truncate() +{ + if (first_clus == 0) + { + if (size != 0) + { + size = 0; + update(); + } + return; + } + + fs->free_cluster_chain(first_clus); + + size = 0; + first_clus = 0; + + update(); +} + +int FAT32Inode::unlink(const char *name) +{ + if (type != T_DIR) + return -1; + if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) + return -1; + + uint32_t clus = first_clus; + bool found = false; + struct Buf *target_buf = nullptr; + uint32_t target_offset = 0; + struct FAT32_DirEnt de; + + while (true) + { + uint32_t sec = fs->cluster_to_sector(clus); + for (uint32 i = 0; i < fs->sectors_per_cluster; ++i) + { + struct Buf *b = BufferCache::bread(dev, (sec + i) / 2); + uint8_t *data = (uint8_t *)b->data + ((sec + i) % 2) * 512; + + for (int off = 0; off < 512; off += 32) + { + memmove(&de, data + off, 32); + if (de.name[0] == 0x00) // end of dir + { + BufferCache::brelse(b); + return -1; // Not found + } + if (de.name[0] == 0xE5) + continue; // have been unlink + if (de.attr & ATTR_LONG_NAME) + continue; + + if (match_name(de.name, name)) + { + target_buf = b; + target_offset = ((sec + i) % 2) * 512 + off; + found = true; + break; + } + } + + if (found) + break; + BufferCache::brelse(b); + } + + if (found) + break; + + clus = fs->next_cluster(clus); + if (clus >= 0x0FFFFFF8) + return -1; + } + + if (found && target_buf) + { + Inode *target_ip = lookup(name); + if (target_ip) + { + VFS::ilock(target_ip); + if (target_ip->type == T_DIR) + { + VFS::iunlockput(target_ip); + BufferCache::brelse(target_buf); + return -1; + } + + target_ip->nlink--; + target_ip->update(); + VFS::iunlockput(target_ip); + } + + uint8_t *ptr = (uint8_t *)target_buf->data + target_offset; + *ptr = 0xE5; + + BufferCache::bwrite(target_buf); + BufferCache::brelse(target_buf); + return 0; + } + + return -1; +} // Test Function void fat32_test() diff --git a/src/fs/file.cc b/src/fs/file.cc index 99bb65d..623b535 100644 --- a/src/fs/file.cc +++ b/src/fs/file.cc @@ -3,12 +3,135 @@ #include "kernel/mm.h" #include "drivers/uart.h" #include "kernel/proc.h" +#include "kernel/slab.h" #define NFILE 100 #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 +extern void *operator new(unsigned long, void *p); + +int Pipe::create_pair(file** f0, file** f1) +{ + void *mem = Slab::kmalloc(sizeof(Pipe)); + if (!mem) + return -1; + Pipe *pi = new (mem) Pipe(); + + *f0 = FileTable::alloc(); + *f1 = FileTable::alloc(); + + if (*f0 == nullptr || *f1 == nullptr) + { + if (*f0) + FileTable::close(*f0); + if (*f1) + FileTable::close(*f1); + pi->~Pipe(); + Slab::kfree(pi); + return -1; + } + + (*f0)->type = FD_PIPE; + (*f0)->readable = 1; + (*f0)->writable = 0; + (*f0)->pipe = pi; + + (*f1)->type = FD_PIPE; + (*f1)->readable = 0; + (*f1)->writable = 1; + (*f1)->pipe = pi; + + return 0; +} + +void Pipe::close(bool is_writer) +{ + lock.acquire(); + if (is_writer) + { + write_open = false; + ProcManager::wakeup(&nread); // Wake up the process that is currently reading + } + else + { + read_open = false; + ProcManager::wakeup(&nwrite); // Wake up the process that is writing + } + + bool empty = !read_open && !write_open; + lock.release(); + + if (empty) + { + this->~Pipe(); + Slab::kfree(this); + } +} + +int Pipe::write(uint64_t addr, int n) +{ + int i = 0; + struct Proc *p = myproc(); + + lock.acquire(); + while (i < n) + { + if (!read_open || p->xstate) // The read end is closed or the process is abnormal + { + lock.release(); + return -1; + } + + if (nwrite == nread + SIZE) // buffer is full + { + ProcManager::wakeup(&nread); + ProcManager::sleep(&nwrite, &lock); + } + else + { + char ch; + if (VM::copyin(p->pagetable, &ch, addr + i, 1) < 0) + break; + data[nwrite++ % SIZE] = ch; + i++; + } + } + ProcManager::wakeup(&nread); + lock.release(); + return i; +} + +int Pipe::read(uint64_t addr, int n) +{ + int i = 0; + struct Proc *p = myproc(); + + lock.acquire(); + while (nread == nwrite && write_open) // The buffer is empty and the write end is not closed + { + if (p->xstate) + { + lock.release(); + return -1; + } + ProcManager::sleep(&nread, &lock); + } + + for (i = 0; i < n; ++i) + { + if (nread == nwrite) + break; + char ch = data[nread++ % SIZE]; + if (VM::copyout(p->pagetable, addr + i, &ch, 1) < 0) + break; + } + ProcManager::wakeup(&nwrite); + lock.release(); + return i; +} + namespace FileTable { struct @@ -82,7 +205,8 @@ namespace FileTable } else if (ff.type == FD_PIPE) { - // pipeclose(ff.pipe, ff.writable); + if (ff.pipe) + ff.pipe->close(ff.writable); } } @@ -101,6 +225,11 @@ namespace FileTable VFS::iunlock(f->ip); return r; } + else if (f->type == FD_PIPE) + { + if (f->pipe) + return f->pipe->read(addr, n); + } return -1; } @@ -119,7 +248,11 @@ namespace FileTable VFS::iunlock(f->ip); return r; } - // else if (f->type == FD_PIPE) ... + else if (f->type == FD_PIPE) + { + if (f->pipe) + return f->pipe->write(addr, n); + } return -1; } diff --git a/src/fs/fs.cc b/src/fs/fs.cc index c5a34ee..9e3d50e 100644 --- a/src/fs/fs.cc +++ b/src/fs/fs.cc @@ -149,6 +149,7 @@ namespace VFS Inode *ip, *next; struct Proc *p = myproc(); + // 1. 确定起点 if (*path == '/') { ip = get_root(); @@ -170,6 +171,23 @@ namespace VFS while ((path = skipelem(path, name)) != nullptr) { + if (strcmp(name, ".") == 0) + { + continue; + } + + if (strcmp(name, "..") == 0) + { + Inode *root = get_root(); + bool is_root = (ip->inum == root->inum); + iput(root); + + if (is_root) + { + continue; + } + } + ilock(ip); if (ip->type != T_DIR) @@ -189,4 +207,38 @@ namespace VFS return ip; } + Inode *nameiparent(const char* path, char* name) + { + Inode* ip; + Inode* next; + + if (*path == '/') + ip = get_root(); + else + ip = idup(myproc()->cwd ? myproc()->cwd : get_root()); + + while ((path = skipelem(path, name)) != nullptr) + { + if (*path == 0) + { + return ip; + } + + ilock(ip); + if (ip->type != T_DIR) + { + iunlockput(ip); + return nullptr; + } + + next = ip->lookup(name); + iunlockput(ip); + + ip = next; + if (!ip) + return nullptr; + } + iput(ip); + return nullptr; + } } // namespace VFS diff --git a/src/kernel/cxx.cc b/src/kernel/cxx.cc index f9541b5..14bfe68 100644 --- a/src/kernel/cxx.cc +++ b/src/kernel/cxx.cc @@ -65,4 +65,10 @@ void operator delete[](void *p, unsigned long size) (void)size; if (p) PMM::free_page(p); +} + +void *operator new(unsigned long size, void *ptr) +{ + (void)size; + return ptr; }
\ No newline at end of file diff --git a/src/kernel/proc/proc.cc b/src/kernel/proc/proc.cc index 5db5f7a..6940a3e 100644 --- a/src/kernel/proc/proc.cc +++ b/src/kernel/proc/proc.cc @@ -152,7 +152,8 @@ void forkret() struct cpu *c = mycpu(); c->runqueue->lock.release(); - Drivers::uart_puts("[Proc] forkret: jumping to user.\n"); + // Debug + // Drivers::uart_puts("[Proc] forkret: jumping to user.\n"); // Enter user mode usertrapret(); @@ -185,6 +186,7 @@ static Proc *allocproc() p->state = USED; p->pid = nextpid++; p->priority = 0; + p->killed = 0; p->cpu = mycpu(); p->cwd = nullptr; for (int i = 0; i < NOFILE; i++) @@ -587,6 +589,34 @@ namespace ProcManager } } + int kill(int pid) + { + Proc* p; + proc_mem_lock.acquire(); + for (p = proc_list_head; p != nullptr; p = p->all_next) + { + if (p->pid == pid) + { + p->killed = 1; + + if (p->state == SLEEPING) + { + p->state = RUNNABLE; + + struct cpu *c = mycpu(); + c->runqueue->lock.acquire(); + c->runqueue->enqueue(p); + c->runqueue->lock.release(); + } + + proc_mem_lock.release(); + return 0; + } + } + proc_mem_lock.release(); + return -1; + } + int growproc(int n) { uint64 sz; diff --git a/src/kernel/sbi.cc b/src/kernel/sbi.cc index 442d219..9570d74 100644 --- a/src/kernel/sbi.cc +++ b/src/kernel/sbi.cc @@ -1,4 +1,5 @@ #include "common/types.h" +#include "kernel/sbi.h" namespace SBI { @@ -31,4 +32,17 @@ namespace SBI { sbi_call(0x54494D45, 0, stime_value, 0, 0); } + + void sbi_shutdown() + { + sbi_call(0x53525354, 0, 0, 0, 0); + sbi_call(0x08, 0, 0, 0, 0); + while (1) + ; + } + + void sbi_reboot() + { + sbi_call(SBI_EID_SRST, SBI_FID_SRST_RESET, SBI_SRST_TYPE_COLD_REBOOT, SBI_SRST_REASON_NONE, 0); + } }
\ No newline at end of file diff --git a/src/kernel/syscall.cc b/src/kernel/syscall.cc index 6af7730..259a5e6 100644 --- a/src/kernel/syscall.cc +++ b/src/kernel/syscall.cc @@ -9,6 +9,7 @@ #include "kernel/mm.h" #include "kernel/trap.h" #include "kernel/slab.h" +#include "kernel/sbi.h" #include "fs/fat32.h" #include "fs/file.h" #include "lib/string.h" @@ -113,12 +114,38 @@ static uint64 sys_open() if (argstr(0, path, 128) < 0 || argint(1, &omode) < 0) return -1; - ip = VFS::namei(path); + if (omode & O_CREATE) + { + ip = VFS::namei(path); + if (ip == nullptr) + { + char name[128]; + Inode *dp = VFS::nameiparent(path, name); + if (dp) + { + VFS::ilock(dp); + ip = dp->create(name, T_FILE, 0, 0); + VFS::iunlockput(dp); + } + } + } + else + { + ip = VFS::namei(path); + } + if (ip == nullptr) { return -1; } + VFS::ilock(ip); + if ((omode & O_TRUNC) && ip->type == T_FILE) + { + ip->truncate(); + } + VFS::iunlock(ip); + f = FileTable::alloc(); if (f == nullptr) { @@ -144,6 +171,128 @@ static uint64 sys_open() return fd; } +static uint64 sys_mkdir() +{ + char path[128]; + if (argstr(0, path, 128) < 0) + return -1; + + Inode *ip = VFS::namei(path); + if (ip != nullptr) + { + VFS::iput(ip); + return -1; // the dir is exist + } + + char name[128]; + Inode *dp = VFS::nameiparent(path, name); + if (dp == nullptr) + return -1; + + VFS::ilock(dp); + ip = dp->create(name, T_DIR, 0, 0); + VFS::iunlockput(dp); + + if (ip == nullptr) + return -1; + + VFS::iput(ip); + return 0; +} + +static uint64 sys_chdir() +{ + char path[128]; + if (argstr(0, path, 128) < 0) + return -1; + + Inode *ip = VFS::namei(path); + if (ip == nullptr) + return -1; + + VFS::ilock(ip); + if (ip->type != T_DIR) + { + VFS::iunlockput(ip); + return -1; + } + VFS::iunlock(ip); + + struct Proc *p = myproc(); + VFS::iput(p->cwd); // release old cwd + p->cwd = ip; // switch to new cwd + + return 0; +} + +static uint64 sys_dup() +{ + int oldfd; + if (argint(0, &oldfd) < 0) + return -1; + + struct Proc *p = myproc(); + if (oldfd < 0 || oldfd >= NOFILE || p->ofile[oldfd] == nullptr) + return -1; + + struct file *f = FileTable::dup(p->ofile[oldfd]); + int newfd = fdalloc(f); + if (newfd < 0) + { + FileTable::close(f); // fdalloc failed + return -1; + } + return newfd; +} + +static uint64 sys_fstat() +{ + int fd; + uint64 stat_addr; + + if (argint(0, &fd) < 0 || argint(1, (int *)&stat_addr) < 0) + return -1; + + struct Proc *p = myproc(); + if (fd < 0 || fd >= NOFILE || p->ofile[fd] == nullptr) + return -1; + + return FileTable::stat(p->ofile[fd], stat_addr); +} + +static uint64 sys_mknod() +{ + char path[128]; + int major, minor; + + if (argstr(0, path, 128) < 0 || argint(1, &major) < 0 || argint(2, &minor) < 0) + return -1; + + Inode *ip = VFS::namei(path); + if (ip != nullptr) + { + VFS::iput(ip); + return -1; + } + + char name[128]; + Inode *dp = VFS::nameiparent(path, name); + if (dp == nullptr) + return -1; + + VFS::ilock(dp); + ip = dp->create(name, T_DEVICE, major, minor); + VFS::iunlockput(dp); + + if (ip == nullptr) + return -1; + + VFS::iput(ip); + return 0; +} + + + static uint64 sys_close() { int fd; @@ -159,6 +308,63 @@ static uint64 sys_close() return 0; } +static uint64 sys_pipe() +{ + uint64 fdarray; // int fd[2] + struct file *rf, *wf; + int fd0, fd1; + struct Proc *p = myproc(); + + if (argint(0, (int *)&fdarray) < 0) + return -1; + + if(Pipe::create_pair(&rf, &wf) < 0) + return -1; + + if ((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0) + { + if (fd0 >= 0) + p->ofile[fd0] = nullptr; + FileTable::close(rf); + FileTable::close(wf); + return -1; + } + + if (VM::copyout(p->pagetable, fdarray, (char *)&fd0, sizeof(int)) < 0 || + VM::copyout(p->pagetable, fdarray + sizeof(int), (char *)&fd1, sizeof(int)) < 0) + { + p->ofile[fd0] = nullptr; + p->ofile[fd1] = nullptr; + FileTable::close(rf); + FileTable::close(wf); + return -1; + } + return 0; +} + +static uint64 sys_link() +{ + Drivers::uart_puts("Not supported now"); + return -1; +} + +static uint64 sys_unlink() +{ + char path[128], name[128]; + if (argstr(0, path, 128) < 0) + return -1; + + Inode *dp = VFS::nameiparent(path, name); + if (!dp) + return -1; + + VFS::ilock(dp); + int ret = dp->unlink(name); + VFS::iunlockput(dp); + + return ret; +} + static uint64 sys_exec() { char path[128]; @@ -169,10 +375,7 @@ static uint64 sys_exec() return -1; } - if (argint(1, (int *)&uargv_ptr) < 0) - { - return -1; - } + uargv_ptr = argraw(1); KernelArgv kargv; @@ -328,6 +531,48 @@ static uint64 sys_sbrk() return addr; } +static uint64 sys_uptime() +{ + return Timer::get_ticks(); +} + +static uint64 sys_kill() +{ + int pid; + if (argint(0, &pid) < 0) + return -1; + + return ProcManager::kill(pid); +} + +static uint64 sys_sleep() +{ + int n; + uint64 ticks0; + + if (argint(0, &n) < 0) + return -1; + + Spinlock *lk = Timer::get_lock(); + lk->acquire(); + + ticks0 = Timer::get_ticks(); + + while (Timer::get_ticks() - ticks0 < (uint64)n) + { + if (myproc()->killed) + { + lk->release(); + return -1; + } + + ProcManager::sleep(Timer::get_tick_chan(), lk); + } + + lk->release(); + return 0; +} + static uint64 sys_disk_test() { // VirtIO::test_rw(); @@ -349,6 +594,14 @@ static uint64 sys_lseek() return FileTable::lseek(p->ofile[fd], offset, whence); } +static uint64 sys_shutdown() +{ + SBI::sbi_shutdown(); + while (1) + ; + return 0; +} + void syscall() { Proc *p = myproc(); @@ -383,9 +636,7 @@ void syscall() case SYS_exec: ret = sys_exec(); if (ret != static_cast<uint64>(-1)) - { return; - } break; case SYS_exit: ret = sys_exit(); @@ -405,16 +656,42 @@ void syscall() case SYS_lseek: ret = sys_lseek(); break; - case SYS_pipe: case SYS_dup: - case SYS_chdir: + ret = sys_dup(); + break; case SYS_fstat: + ret = sys_fstat(); + break; + case SYS_chdir: + ret = sys_chdir(); + break; case SYS_mkdir: + ret = sys_mkdir(); + break; case SYS_mknod: + ret = sys_mknod(); + break; + case SYS_pipe: + ret = sys_pipe(); + break; case SYS_unlink: + ret = sys_unlink(); + break; case SYS_link: Drivers::uart_puts("Unimplemented syscall\n"); - ret = static_cast<uint64>(-1); + ret = sys_link(); + break; + case SYS_uptime: + ret = sys_uptime(); + break; + case SYS_sleep: + ret = sys_sleep(); + break; + case SYS_kill: + ret = sys_kill(); + break; + case SYS_shutdown: + ret = sys_shutdown(); break; default: Drivers::uart_puts("Unknown Syscall ID: "); diff --git a/src/kernel/timer.cc b/src/kernel/timer.cc index fb871d5..3cbf11e 100644 --- a/src/kernel/timer.cc +++ b/src/kernel/timer.cc @@ -1,15 +1,16 @@ #include "common/types.h" #include "kernel/config.h" - -namespace SBI -{ - void set_timer(uint64 stime_value); -} +#include "kernel/spinlock.h" +#include "kernel/proc.h" +#include "kernel/sbi.h" #define INTERVAL 1000000 namespace Timer { + uint64 ticks; + Spinlock tickslock; + uint64 get_time() { uint64 time; @@ -31,4 +32,31 @@ namespace Timer sie |= (1L << 5); asm volatile("csrw sie, %0" : : "r"(sie)); } + + void tick() + { + tickslock.acquire(); + ticks++; + ProcManager::wakeup(&ticks); + tickslock.release(); + set_next_trigger(); + } + + uint64 get_ticks() + { + tickslock.acquire(); + uint64 t = ticks; + tickslock.release(); + return t; + } + + Spinlock *get_lock() + { + return &tickslock; + } + + void *get_tick_chan() + { + return &ticks; + } }
\ No newline at end of file diff --git a/src/kernel/trap/handler.cc b/src/kernel/trap/handler.cc index 3fb772e..7e4d11e 100644 --- a/src/kernel/trap/handler.cc +++ b/src/kernel/trap/handler.cc @@ -85,7 +85,8 @@ namespace Trap else if (is_interrupt && code == 5) { // Supervisor Timer Interrupt (IRQ 5) - Timer::set_next_trigger(); + // Timer::set_next_trigger(); + Timer::tick(); // w_sip(r_sip() & ~2); return 2; } diff --git a/src/user/echo.cc b/src/user/echo.cc new file mode 100644 index 0000000..ff4b8be --- /dev/null +++ b/src/user/echo.cc @@ -0,0 +1,22 @@ +#include "user/user.h" +#include "ulib/stdio.h" +#include "ulib/string.h" + +int main(int argc, char* argv[]) +{ + int i; + + for (i = 1; i < argc; i++) + { + write(1, argv[i], strlen(argv[i])); + if (i + 1 < argc) + { + write(1, " ", 1); + } + else + { + write(1, "\n", 1); + } + } + exit(0); +}
\ No newline at end of file diff --git a/src/user/entry.S b/src/user/entry.S index 110ebbf..432211c 100644 --- a/src/user/entry.S +++ b/src/user/entry.S @@ -2,9 +2,6 @@ .global _start _start: - li a0, 0 - li a1, 0 - call main call exit diff --git a/src/user/init.cc b/src/user/init.cc index 827a21e..07ed97e 100644 --- a/src/user/init.cc +++ b/src/user/init.cc @@ -2,12 +2,14 @@ #include "ulib/stdlib.h" #include "ulib/string.h" #include "user/user.h" +#include "drivers/uart_color.h" int main() { char *argv[] = {(char *)"sh", 0}; - printf("[Init] Starting Lume OS Shell...\n"); + printf(ANSI_BLUE"\n[Init] Starting Lume OS Shell..."ANSI_RESET); + printf("\n"); while (1) { diff --git a/src/user/ls.cc b/src/user/ls.cc new file mode 100644 index 0000000..e472578 --- /dev/null +++ b/src/user/ls.cc @@ -0,0 +1,112 @@ +#include "ulib/stdio.h" +#include "ulib/stdlib.h" +#include "ulib/string.h" +#include "user/user.h" +#include "common/fcntl.h" + + +struct FAT32_DirEnt +{ + char name[11]; + uint8 attr; + uint8 lcase; + uint8 ctime_cs; + uint16 ctime; + uint16 cdate; + uint16 adate; + uint16 fstClusHI; + uint16 wtime; + uint16 wdate; + uint16 fstClusLO; + uint32 fileSize; +} __attribute__((packed)); + +#define ATTR_DIRECTORY 0x10 +#define ATTR_LONG_NAME 0x0F + +void fmt_name(char *dst, const char *src) +{ + int i; + char *d = dst; + + for (i = 0; i < 8; i++) + { + if (src[i] == ' ') + break; + *d++ = src[i]; + } + + if (src[8] != ' ') + { + *d++ = '.'; + for (i = 8; i < 11; i++) + { + if (src[i] == ' ') + break; + *d++ = src[i]; + } + } + *d = 0; + + for (d = dst; *d; d++) + { + if (*d >= 'A' && *d <= 'Z') + *d += 32; + } +} + +void ls(const char *path) +{ + int fd; + struct FAT32_DirEnt de; + char name_buf[16]; + + if ((fd = open(path, O_RDONLY)) < 0) + { + printf("ls: cannot open %s\n", path); + return; + } + + while (read(fd, &de, sizeof(de)) == sizeof(de)) + { + if (de.name[0] == 0) + { + break; + } + + if ((unsigned char)de.name[0] == 0xE5) + { + continue; + } + + if ((de.attr & ATTR_LONG_NAME) == ATTR_LONG_NAME) + { + continue; + } + + fmt_name(name_buf, de.name); + + printf("%s %d\t%s\n", + (de.attr & ATTR_DIRECTORY) ? "<DIR>" : " ", + de.fileSize, + name_buf); + } + + close(fd); +} + +int main(int argc, char *argv[]) +{ + if (argc < 2) + { + ls("."); + } + else + { + for (int i = 1; i < argc; i++) + { + ls(argv[i]); + } + } + exit(0); +}
\ No newline at end of file diff --git a/src/user/mkdir.cc b/src/user/mkdir.cc new file mode 100644 index 0000000..8219109 --- /dev/null +++ b/src/user/mkdir.cc @@ -0,0 +1,21 @@ +#include "ulib/stdio.h" +#include "user/user.h" + +int main(int argc, char* argv[]) +{ + if (argc < 2) + { + printf("Usage: mkdir <dirname> ...\n"); + exit(1); + } + + for (int i = 1; i < argc; i++) + { + if (mkdir(argv[i]) < 0) + { + printf("mkdir: cannot create directory '%s'\n", argv[i]); + } + } + + exit(0); +}
\ No newline at end of file diff --git a/src/user/sh.cc b/src/user/sh.cc index 1f2e950..b4122f7 100644 --- a/src/user/sh.cc +++ b/src/user/sh.cc @@ -3,6 +3,7 @@ #include "ulib/string.h" #include "user/user.h" #include "common/fcntl.h" +#include "drivers/uart_color.h" constexpr int MAX_ARGS = 10; const char *WHITESPACE = " \t\r\n\v"; @@ -334,35 +335,13 @@ int getcmd(char *buf, int nbuf) write(1, "$ ", 2); memset(buf, 0, nbuf); - int i = 0; - while (i < nbuf - 1) - { - char c; - int n = read(0, &c, 1); - if (n <= 0) - return -1; + int n = read(0, buf, nbuf - 1); - if (c == '\b' || c == 127) - { - if (i > 0) - { - write(1, "\b \b", 3); - i--; - } - } - else if (c == '\n' || c == '\r') - { - write(1, "\n", 1); - buf[i] = 0; - return 0; - } - else - { - write(1, &c, 1); - buf[i++] = c; - } - } - return -1; + if (n < 0) + return -1; + + buf[n] = 0; + return 0; } int main() @@ -379,10 +358,18 @@ int main() // } // } - printf("\n[Lume Shell] Initialized! \n"); + printf(ANSI_GREEN"\n[Lume Shell] Welcome! \n"ANSI_RESET); + printf(ANSI_YELLOW "[Lume Shell] Start your journey of exploration!"ANSI_RESET); + printf("\n"); while (getcmd(buf, sizeof(buf)) >= 0) { + int len = strlen(buf); + if (len > 0 && buf[len - 1] == '\n') + { + buf[len - 1] = 0; + } + if (buf[0] == 'c' && buf[1] == 'd' && (buf[2] == ' ' || buf[2] == '\n' || buf[2] == 0)) { if (buf[strlen(buf) - 1] == '\n') @@ -401,6 +388,14 @@ int main() } continue; } + if (strcmp(buf, "shutdown") == 0 || strcmp(buf, "poweroff") == 0) + { + printf(ANSI_BLUE"System shutting down..."ANSI_RESET); + printf("\n"); + shutdown(); + + continue; + } if (fork_or_panic() == 0) { diff --git a/src/user/usys.S b/src/user/usys.S index f85917e..56cbb22 100644 --- a/src/user/usys.S +++ b/src/user/usys.S @@ -38,4 +38,5 @@ SYSCALL(sleep) SYSCALL(uptime) SYSCALL(putc) SYSCALL(disk_test) -SYSCALL(lseek)
\ No newline at end of file +SYSCALL(lseek) +SYSCALL(shutdown)
\ No newline at end of file |
