diff --git a/xv6-riscv/.gitignore b/xv6-riscv/.gitignore new file mode 100644 index 0000000..07216f3 --- /dev/null +++ b/xv6-riscv/.gitignore @@ -0,0 +1,17 @@ +*~ +_* +*.o +*.d +*.asm +*.sym +*.img +vectors.S +bootblock +entryother +initcode +initcode.out +kernelmemfs +mkfs +kernel/kernel +user/usys.S +.gdbinit diff --git a/xv6-riscv/.vscode/settings.json b/xv6-riscv/.vscode/settings.json new file mode 100644 index 0000000..64c7ab7 --- /dev/null +++ b/xv6-riscv/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "stat.h": "c" + } +} \ No newline at end of file diff --git a/xv6-riscv/Makefile b/xv6-riscv/Makefile index f8c820e..1528618 100644 --- a/xv6-riscv/Makefile +++ b/xv6-riscv/Makefile @@ -26,6 +26,7 @@ OBJS = \ $K/pipe.o \ $K/exec.o \ $K/sysfile.o \ + $K/socket.o \ $K/kernelvec.o \ $K/plic.o \ $K/virtio_disk.o @@ -139,6 +140,7 @@ UPROGS=\ $U/_grind\ $U/_wc\ $U/_zombie\ + $U/_sockettest\ fs.img: mkfs/mkfs README $(UPROGS) mkfs/mkfs fs.img README $(UPROGS) diff --git a/xv6-riscv/kernel/defs.h b/xv6-riscv/kernel/defs.h index d1b6bb9..7317350 100644 --- a/xv6-riscv/kernel/defs.h +++ b/xv6-riscv/kernel/defs.h @@ -185,5 +185,16 @@ void virtio_disk_init(void); void virtio_disk_rw(struct buf *, int); void virtio_disk_intr(void); + +//socket + +struct file; +struct socket; +struct file* socketalloc(void); +int socketread(struct file*, uint64, int); +int socketwrite(struct file*, uint64, int); +void socketclose(struct file*); + + // number of elements in fixed-size array #define NELEM(x) (sizeof(x)/sizeof((x)[0])) diff --git a/xv6-riscv/kernel/file.h b/xv6-riscv/kernel/file.h index b076d1d..863de0e 100644 --- a/xv6-riscv/kernel/file.h +++ b/xv6-riscv/kernel/file.h @@ -1,12 +1,13 @@ struct file { - enum { FD_NONE, FD_PIPE, FD_INODE, FD_DEVICE } type; - int ref; // reference count + enum { FD_NONE, FD_PIPE, FD_INODE, FD_DEVICE, FD_SOCKET } type; + int ref; char readable; char writable; struct pipe *pipe; // FD_PIPE struct inode *ip; // FD_INODE and FD_DEVICE - uint off; // FD_INODE - short major; // FD_DEVICE + uint off; // FD_INODE + short major; // FD_DEVICE + struct socket *sock; // FD_SOCKET }; #define major(dev) ((dev) >> 16 & 0xFFFF) @@ -38,3 +39,6 @@ struct devsw { extern struct devsw devsw[]; #define CONSOLE 1 + +// Add a new file type for sockets +#define T_SOCKET 4 diff --git a/xv6-riscv/kernel/socket.c b/xv6-riscv/kernel/socket.c new file mode 100644 index 0000000..7f6f69b --- /dev/null +++ b/xv6-riscv/kernel/socket.c @@ -0,0 +1,129 @@ +#include "types.h" +#include "riscv.h" +#include "defs.h" +#include "param.h" +#include "spinlock.h" +#include "proc.h" +#include "fs.h" +#include "sleeplock.h" +#include "file.h" +#include "socket.h" + +struct file* +socketalloc(void) +{ + struct file *f; + struct socket *s; + + f = filealloc(); + if(f == 0) + return 0; + + s = kalloc(); + if(s == 0){ + fileclose(f); + return 0; + } + + initlock(&s->lock, "socket"); + s->refs = 1; + s->read_ptr = 0; + s->write_ptr = 0; + s->connected = 0; + + f->type = FD_SOCKET; + f->readable = 1; + f->writable = 1; + f->sock = s; + f->ref = 1; + + return f; +} + +int +socketread(struct file *f, uint64 addr, int n) +{ + struct socket *s = f->sock; + int r; + + if(n < 0) + return -1; + + acquire(&s->lock); + + while(s->read_ptr == s->write_ptr && s->connected){ + if(myproc()->killed){ + release(&s->lock); + return -1; + } + sleep(&s->read_ptr, &s->lock); + } + + r = 0; + while(r < n && s->read_ptr != s->write_ptr){ + if(copyout(myproc()->pagetable, addr + r, &s->data[s->read_ptr], 1) == -1) + break; + s->read_ptr = (s->read_ptr + 1) % sizeof(s->data); + r++; + } + + if(r > 0) + wakeup(&s->write_ptr); + + release(&s->lock); + return r; +} + +int +socketwrite(struct file *f, uint64 addr, int n) +{ + struct socket *s = f->sock; + int w; + + if(n < 0) + return -1; + + acquire(&s->lock); + + w = 0; + while(w < n){ + while(((s->write_ptr + 1) % sizeof(s->data)) == s->read_ptr){ + if(myproc()->killed){ + release(&s->lock); + return -1; + } + wakeup(&s->read_ptr); + sleep(&s->write_ptr, &s->lock); + } + + if(copyin(myproc()->pagetable, &s->data[s->write_ptr], addr + w, 1) == -1) + break; + + s->write_ptr = (s->write_ptr + 1) % sizeof(s->data); + w++; + } + + if(w > 0) + wakeup(&s->read_ptr); + + release(&s->lock); + return w; +} + +void +socketclose(struct file *f) +{ + struct socket *s = f->sock; + + acquire(&s->lock); + s->refs--; + if(s->refs == 0){ + s->connected = 0; + wakeup(&s->read_ptr); + wakeup(&s->write_ptr); + release(&s->lock); + kfree(s); + } else { + release(&s->lock); + } +} \ No newline at end of file diff --git a/xv6-riscv/kernel/socket.h b/xv6-riscv/kernel/socket.h new file mode 100644 index 0000000..a37c293 --- /dev/null +++ b/xv6-riscv/kernel/socket.h @@ -0,0 +1,8 @@ +struct socket { + struct spinlock lock; + int refs; // reference count + char data[512]; // socket buffer + uint read_ptr; // read pointer + uint write_ptr; // write pointer + int connected; // connection status +}; \ No newline at end of file diff --git a/xv6-riscv/kernel/syscall.c b/xv6-riscv/kernel/syscall.c index ed65409..a1c0ce8 100644 --- a/xv6-riscv/kernel/syscall.c +++ b/xv6-riscv/kernel/syscall.c @@ -7,6 +7,12 @@ #include "syscall.h" #include "defs.h" +// Add the system call number +#define SYS_socket 22 + + + + // Fetch the uint64 at addr from the current process. int fetchaddr(uint64 addr, uint64 *ip) @@ -101,6 +107,12 @@ extern uint64 sys_unlink(void); extern uint64 sys_link(void); extern uint64 sys_mkdir(void); extern uint64 sys_close(void); +extern uint64 sys_socketalloc(void); +extern uint64 sys_socketread(void); +extern uint64 sys_socketwrite(void); +extern uint64 sys_socketclose(void); + + // An array mapping syscall numbers from syscall.h // to the function that handles the system call. @@ -126,6 +138,10 @@ static uint64 (*syscalls[])(void) = { [SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [SYS_close] sys_close, +[SYS_socketalloc] sys_socketalloc, +[SYS_socketread] sys_socketread, +[SYS_socketwrite] sys_socketwrite, +[SYS_socketclose] sys_socketclose, }; void @@ -145,3 +161,4 @@ syscall(void) p->trapframe->a0 = -1; } } + diff --git a/xv6-riscv/kernel/syscall.h b/xv6-riscv/kernel/syscall.h index bc5f356..e2e69a3 100644 --- a/xv6-riscv/kernel/syscall.h +++ b/xv6-riscv/kernel/syscall.h @@ -20,3 +20,7 @@ #define SYS_link 19 #define SYS_mkdir 20 #define SYS_close 21 +#define SYS_socketalloc 22 +#define SYS_socketread 23 +#define SYS_socketwrite 24 +#define SYS_socketclose 25 \ No newline at end of file diff --git a/xv6-riscv/kernel/sysfile.c b/xv6-riscv/kernel/sysfile.c index 16b668c..46877ac 100644 --- a/xv6-riscv/kernel/sysfile.c +++ b/xv6-riscv/kernel/sysfile.c @@ -503,3 +503,67 @@ sys_pipe(void) } return 0; } + + + +uint64 +sys_socketalloc(void) +{ + struct file *f; + int fd; + + f = socketalloc(); + if(f == 0) + return -1; + + if((fd = fdalloc(f)) < 0){ + fileclose(f); + return -1; + } + + return fd; +} + +uint64 sys_socketread(void) { + int fd; + struct file* f; + uint64 addr; + int n; + + if (argfd(0, &fd, &f) < 0) { + return -1; + } + + argaddr(1, &addr); + argint(2, &n); + + return socketread(f, addr, n); +} + +uint64 sys_socketwrite(void) { + int fd; + struct file* f; + uint64 addr; + int n; + + if (argfd(0, &fd, &f) < 0) { + return -1; + } + + argaddr(1, &addr); + argint(2, &n); + + return socketwrite(f, addr, n); +} + +uint64 sys_socketclose(void) { + int fd; + struct file* f; + + if (argfd(0, &fd, &f) < 0) { + return -1; + } + + socketclose(f); + return 0; +} \ No newline at end of file diff --git a/xv6-riscv/user/sockettest.c b/xv6-riscv/user/sockettest.c new file mode 100644 index 0000000..1e8b162 --- /dev/null +++ b/xv6-riscv/user/sockettest.c @@ -0,0 +1,49 @@ +#include "kernel/types.h" +#include "kernel/stat.h" +#include "user.h" + +#define BUFFER_SIZE 64 + +int +main(int argc, char *argv[]) +{ + int sockfd; + char buf[BUFFER_SIZE]; + int n; + + // Create a socket + sockfd = socketalloc(); + if(sockfd < 0){ + printf("socketalloc failed\n"); + exit(1); + } + printf("Socket created: fd=%d\n", sockfd); + + // Write some data to the socket + const char* msg = "Hello from sockettest!"; + if(socketwrite(sockfd, msg, strlen(msg)) < 0){ + printf("socketwrite failed\n"); + socketclose(sockfd); + exit(1); + } + printf("Wrote data to socket\n"); + + // Read data from the socket + n = socketread(sockfd, buf, BUFFER_SIZE-1); + if(n < 0){ + printf("socketread failed\n"); + socketclose(sockfd); + exit(1); + } + buf[n] = '\0'; + printf("Read from socket: %s\n", buf); + + // Close the socket + if(socketclose(sockfd) < 0){ + printf("socketclose failed\n"); + exit(1); + } + printf("Socket closed\n"); + + exit(0); +} \ No newline at end of file diff --git a/xv6-riscv/user/user.h b/xv6-riscv/user/user.h index f16fe27..f2663d8 100644 --- a/xv6-riscv/user/user.h +++ b/xv6-riscv/user/user.h @@ -22,6 +22,10 @@ int getpid(void); char* sbrk(int); int sleep(int); int uptime(void); +int socketalloc(void); +int socketread(int, void*, int); +int socketwrite(int, const void*, int); +int socketclose(int); // ulib.c int stat(const char*, struct stat*); @@ -32,12 +36,12 @@ int strcmp(const char*, const char*); void fprintf(int, const char*, ...) __attribute__ ((format (printf, 2, 3))); void printf(const char*, ...) __attribute__ ((format (printf, 1, 2))); char* gets(char*, int max); -uint strlen(const char*); -void* memset(void*, int, uint); +unsigned int strlen(const char*); +void* memset(void*, int, unsigned int); int atoi(const char*); -int memcmp(const void *, const void *, uint); -void *memcpy(void *, const void *, uint); +int memcmp(const void *, const void *, unsigned int); +void *memcpy(void *, const void *, unsigned int); // umalloc.c -void* malloc(uint); +void* malloc(unsigned int); void free(void*); diff --git a/xv6-riscv/user/usys.pl b/xv6-riscv/user/usys.pl index 01e426e..f14d4fa 100755 --- a/xv6-riscv/user/usys.pl +++ b/xv6-riscv/user/usys.pl @@ -36,3 +36,7 @@ sub entry { entry("sbrk"); entry("sleep"); entry("uptime"); +entry("socketalloc"); +entry("socketread"); +entry("socketwrite"); +entry("socketclose"); \ No newline at end of file