summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/drivers/uart.cc100
-rw-r--r--src/fs/fat32.cc475
-rw-r--r--src/fs/file.cc137
-rw-r--r--src/fs/fs.cc52
-rw-r--r--src/kernel/cxx.cc6
-rw-r--r--src/kernel/proc/proc.cc32
-rw-r--r--src/kernel/sbi.cc14
-rw-r--r--src/kernel/syscall.cc297
-rw-r--r--src/kernel/timer.cc38
-rw-r--r--src/kernel/trap/handler.cc3
-rw-r--r--src/user/echo.cc22
-rw-r--r--src/user/entry.S3
-rw-r--r--src/user/init.cc4
-rw-r--r--src/user/ls.cc112
-rw-r--r--src/user/mkdir.cc21
-rw-r--r--src/user/sh.cc53
-rw-r--r--src/user/usys.S3
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