diff --git a/xv6-os/.gitignore b/xv6-os/.gitignore index c19de7ba..23c9fdf7 100644 --- a/xv6-os/.gitignore +++ b/xv6-os/.gitignore @@ -11,7 +11,7 @@ entryother initcode initcode.out kernelmemfs -mkfs +mkfs/mkfs kernel/kernel user/usys.S .gdbinit diff --git a/xv6-os/Makefile b/xv6-os/Makefile index 218d080e..23cb304c 100644 --- a/xv6-os/Makefile +++ b/xv6-os/Makefile @@ -156,6 +156,8 @@ UPROGS=\ $U/_alloctest\ $U/_cowtest\ $U/_lazytests\ + $U/_pingpong\ + $U/_sysinfo\ fs.img: mkfs/mkfs README $(UPROGS) mkfs/mkfs fs.img README $(UPROGS) diff --git a/xv6-os/kernel/defs.h b/xv6-os/kernel/defs.h index f947e244..c0dce576 100644 --- a/xv6-os/kernel/defs.h +++ b/xv6-os/kernel/defs.h @@ -107,6 +107,9 @@ void yield(void); int either_copyout(int user_dst, uint64 dst, void *src, uint64 len); int either_copyin(void *dst, int user_src, uint64 src, uint64 len); void procdump(void); +int dump(void); +int dump2(int pid, int reg, uint64 return_value_user); +int get_sysinfo(uint64 user_addr); // swtch.S void swtch(struct context*, struct context*); diff --git a/xv6-os/kernel/file.c b/xv6-os/kernel/file.c index 25fa2263..01d955c8 100644 --- a/xv6-os/kernel/file.c +++ b/xv6-os/kernel/file.c @@ -19,6 +19,19 @@ struct { struct file file[NFILE]; } ftable; +int count_open_files(void) { + int count = 0; + acquire(&ftable.lock); + for (int i = 0; i < NFILE; i++) { + if (ftable.file[i].ref > 0) { + count++; + } + } + release(&ftable.lock); + + return count; +} + void fileinit(void) { diff --git a/xv6-os/kernel/file.h b/xv6-os/kernel/file.h index b076d1d8..fdd2e0c3 100644 --- a/xv6-os/kernel/file.h +++ b/xv6-os/kernel/file.h @@ -1,4 +1,6 @@ +#define NDIRECT 12 struct file { + struct spinlock lock; enum { FD_NONE, FD_PIPE, FD_INODE, FD_DEVICE } type; int ref; // reference count char readable; @@ -36,5 +38,6 @@ struct devsw { }; extern struct devsw devsw[]; +int count_open_files(void); #define CONSOLE 1 diff --git a/xv6-os/kernel/proc.c b/xv6-os/kernel/proc.c index 130d9ce3..1ef4b892 100644 --- a/xv6-os/kernel/proc.c +++ b/xv6-os/kernel/proc.c @@ -3,13 +3,15 @@ #include "memlayout.h" #include "riscv.h" #include "spinlock.h" +#include "sleeplock.h" #include "proc.h" #include "defs.h" +#include "file.h" +#include "sysinfo.h" struct cpu cpus[NCPU]; struct proc proc[NPROC]; - struct proc *initproc; int nextpid = 1; @@ -693,3 +695,96 @@ procdump(void) printf("\n"); } } + +int dump(void) { + struct proc *p = myproc(); + struct trapframe *tf = p->trapframe; + + uint64 regs[10]; + + regs[0] = tf->s2; + regs[1] = tf->s3; + regs[2] = tf->s4; + regs[3] = tf->s5; + regs[4] = tf->s6; + regs[5] = tf->s7; + regs[6] = tf->s8; + regs[7] = tf->s9; + regs[8] = tf->s10; + regs[9] = tf->s11; + + for (int i = 0; i < 10; i++) { + printf("s%d = %d\n", i + 2, (uint32)regs[i]); + } + + return 0; +} + +int dump2(int pid, int reg, uint64 return_value_user) { + struct proc *p = myproc(); + struct proc *target_proc = 0; + + // check for reg num (only s2..s11 are dumpable) + if (reg < 2 || reg > 11) { + return -3; // incorrect reg num + } + + for (struct proc *proc_entry = proc; proc_entry < &proc[NPROC]; proc_entry++) { + acquire(&proc_entry->lock); // spinlock + + if (proc_entry->pid == pid) { + target_proc = proc_entry; + // check for access rights + if (target_proc != p && target_proc->parent != p) { + release(&target_proc->lock); + return -1; // don't have enough access rights + } + + uint64 reg_value; + if (reg >= 2 && reg <= 11) { + reg_value = *(&target_proc->trapframe->s2 + (reg - 2)); + } + + release(&target_proc->lock); + + if (copyout(p->pagetable, return_value_user, (char *)®_value, sizeof(uint64)) < 0) { + return -4; // data write fail + } + + return 0; + } + + release(&proc_entry->lock); + } + + return -2; // no process found with this pid +} + +int +get_sysinfo(uint64 user_addr) { + struct proc *p = myproc(); + struct sysinfo info; + + info.procs_cnt=0; + info.open_files=0; + info.free_ram=0; + info.used_ram=0; + + // count procs + for (struct proc *proc_entry = proc; proc_entry < &proc[NPROC]; proc_entry++) { + acquire(&proc_entry->lock); + if (proc_entry->state != UNUSED) { + info.procs_cnt++; + } + release(&proc_entry->lock); + } + + // count open files + info.open_files=count_open_files(); + + if (copyout(p->pagetable, user_addr, (char *)&info, sizeof(info)) < 0) { + return -1; // data write fail + } + + return 0; //Success +} diff --git a/xv6-os/kernel/proc.h b/xv6-os/kernel/proc.h index d021857a..27d58726 100644 --- a/xv6-os/kernel/proc.h +++ b/xv6-os/kernel/proc.h @@ -15,10 +15,7 @@ struct context { uint64 s8; uint64 s9; uint64 s10; - uint64 s11; -}; - -// Per-CPU state. + uint64 s11; }; // Per-CPU state. struct cpu { struct proc *proc; // The process running on this cpu, or null. struct context context; // swtch() here to enter scheduler(). diff --git a/xv6-os/kernel/spinlock.h b/xv6-os/kernel/spinlock.h index 4392820d..8cb00b54 100644 --- a/xv6-os/kernel/spinlock.h +++ b/xv6-os/kernel/spinlock.h @@ -1,4 +1,6 @@ // Mutual exclusion lock. +#ifndef _SYS_SPINLOCK_H_ +#define _SYS_SPINLOCK_H_ struct spinlock { uint locked; // Is the lock held? @@ -7,3 +9,4 @@ struct spinlock { struct cpu *cpu; // The cpu holding the lock. }; +#endif // _SYS_SPINLOCK_H_ diff --git a/xv6-os/kernel/syscall.c b/xv6-os/kernel/syscall.c index ed654094..fdf9bd43 100644 --- a/xv6-os/kernel/syscall.c +++ b/xv6-os/kernel/syscall.c @@ -9,8 +9,7 @@ // Fetch the uint64 at addr from the current process. int -fetchaddr(uint64 addr, uint64 *ip) -{ +fetchaddr(uint64 addr, uint64 *ip) { struct proc *p = myproc(); if(addr >= p->sz || addr+sizeof(uint64) > p->sz) // both tests needed, in case of overflow return -1; @@ -101,6 +100,9 @@ extern uint64 sys_unlink(void); extern uint64 sys_link(void); extern uint64 sys_mkdir(void); extern uint64 sys_close(void); +extern uint64 sys_dump(void); +extern uint64 sys_dump2(void); +extern uint64 sys_info(void); // An array mapping syscall numbers from syscall.h // to the function that handles the system call. @@ -126,6 +128,9 @@ static uint64 (*syscalls[])(void) = { [SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [SYS_close] sys_close, +[SYS_dump] sys_dump, +[SYS_dump2] sys_dump2, +[SYS_info] sys_info, }; void diff --git a/xv6-os/kernel/syscall.h b/xv6-os/kernel/syscall.h index bc5f3565..cb94bf1f 100644 --- a/xv6-os/kernel/syscall.h +++ b/xv6-os/kernel/syscall.h @@ -20,3 +20,6 @@ #define SYS_link 19 #define SYS_mkdir 20 #define SYS_close 21 +#define SYS_dump 22 +#define SYS_dump2 23 +#define SYS_info 24 diff --git a/xv6-os/kernel/sysinfo.h b/xv6-os/kernel/sysinfo.h new file mode 100644 index 00000000..77a620d5 --- /dev/null +++ b/xv6-os/kernel/sysinfo.h @@ -0,0 +1,11 @@ +#ifndef _SYSINFO_H_ +#define _SYSINFO_H_ + +struct sysinfo { + int procs_cnt; + int open_files; + int used_ram; + int free_ram; +}; + +#endif // _SYSINFO_H_ diff --git a/xv6-os/kernel/sysproc.c b/xv6-os/kernel/sysproc.c index 3b4d5bd8..d8d219ae 100644 --- a/xv6-os/kernel/sysproc.c +++ b/xv6-os/kernel/sysproc.c @@ -91,3 +91,33 @@ sys_uptime(void) release(&tickslock); return xticks; } + +uint64 +sys_dump(void) +{ + return dump(); +} + +uint64 +sys_dump2(void) +{ + int pid; + int reg; + uint64 ret_val; + + argint(0, &pid); + argint(1, ®); + argaddr(2, &ret_val); + + return dump2(pid, reg, ret_val); +} + +uint64 +sys_info(void) +{ + uint64 user_addr; + + argaddr(0, &user_addr); + + return get_sysinfo(user_addr); +} diff --git a/xv6-os/mkfs/mkfs.c b/xv6-os/mkfs/mkfs.c new file mode 100644 index 00000000..f39983d7 --- /dev/null +++ b/xv6-os/mkfs/mkfs.c @@ -0,0 +1,303 @@ +#include +#include +#include +#include +#include +#include + +#define stat xv6_stat // avoid clash with host struct stat +#include "kernel/types.h" +#include "kernel/fs.h" +#include "kernel/stat.h" +#include "kernel/param.h" + +#ifndef static_assert +#define static_assert(a, b) do { switch (0) case 0: case (a): ; } while (0) +#endif + +#define NINODES 200 + +// Disk layout: +// [ boot block | sb block | log | inode blocks | free bit map | data blocks ] + +int nbitmap = FSSIZE/BPB + 1; +int ninodeblocks = NINODES / IPB + 1; +int nlog = LOGSIZE; +int nmeta; // Number of meta blocks (boot, sb, nlog, inode, bitmap) +int nblocks; // Number of data blocks + +int fsfd; +struct superblock sb; +char zeroes[BSIZE]; +uint freeinode = 1; +uint freeblock; + + +void balloc(int); +void wsect(uint, void*); +void winode(uint, struct dinode*); +void rinode(uint inum, struct dinode *ip); +void rsect(uint sec, void *buf); +uint ialloc(ushort type); +void iappend(uint inum, void *p, int n); +void die(const char *); + +// convert to riscv byte order +ushort +xshort(ushort x) +{ + ushort y; + uchar *a = (uchar*)&y; + a[0] = x; + a[1] = x >> 8; + return y; +} + +uint +xint(uint x) +{ + uint y; + uchar *a = (uchar*)&y; + a[0] = x; + a[1] = x >> 8; + a[2] = x >> 16; + a[3] = x >> 24; + return y; +} + +int +main(int argc, char *argv[]) +{ + int i, cc, fd; + uint rootino, inum, off; + struct dirent de; + char buf[BSIZE]; + struct dinode din; + + + static_assert(sizeof(int) == 4, "Integers must be 4 bytes!"); + + if(argc < 2){ + fprintf(stderr, "Usage: mkfs fs.img files...\n"); + exit(1); + } + + assert((BSIZE % sizeof(struct dinode)) == 0); + assert((BSIZE % sizeof(struct dirent)) == 0); + + fsfd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666); + if(fsfd < 0) + die(argv[1]); + + // 1 fs block = 1 disk sector + nmeta = 2 + nlog + ninodeblocks + nbitmap; + nblocks = FSSIZE - nmeta; + + sb.magic = FSMAGIC; + sb.size = xint(FSSIZE); + sb.nblocks = xint(nblocks); + sb.ninodes = xint(NINODES); + sb.nlog = xint(nlog); + sb.logstart = xint(2); + sb.inodestart = xint(2+nlog); + sb.bmapstart = xint(2+nlog+ninodeblocks); + + printf("nmeta %d (boot, super, log blocks %u inode blocks %u, bitmap blocks %u) blocks %d total %d\n", + nmeta, nlog, ninodeblocks, nbitmap, nblocks, FSSIZE); + + freeblock = nmeta; // the first free block that we can allocate + + for(i = 0; i < FSSIZE; i++) + wsect(i, zeroes); + + memset(buf, 0, sizeof(buf)); + memmove(buf, &sb, sizeof(sb)); + wsect(1, buf); + + rootino = ialloc(T_DIR); + assert(rootino == ROOTINO); + + bzero(&de, sizeof(de)); + de.inum = xshort(rootino); + strcpy(de.name, "."); + iappend(rootino, &de, sizeof(de)); + + bzero(&de, sizeof(de)); + de.inum = xshort(rootino); + strcpy(de.name, ".."); + iappend(rootino, &de, sizeof(de)); + + for(i = 2; i < argc; i++){ + // get rid of "user/" + char *shortname; + if(strncmp(argv[i], "user/", 5) == 0) + shortname = argv[i] + 5; + else + shortname = argv[i]; + + assert(index(shortname, '/') == 0); + + if((fd = open(argv[i], 0)) < 0) + die(argv[i]); + + // Skip leading _ in name when writing to file system. + // The binaries are named _rm, _cat, etc. to keep the + // build operating system from trying to execute them + // in place of system binaries like rm and cat. + if(shortname[0] == '_') + shortname += 1; + + assert(strlen(shortname) <= DIRSIZ); + + inum = ialloc(T_FILE); + + bzero(&de, sizeof(de)); + de.inum = xshort(inum); + strncpy(de.name, shortname, DIRSIZ); + iappend(rootino, &de, sizeof(de)); + + while((cc = read(fd, buf, sizeof(buf))) > 0) + iappend(inum, buf, cc); + + close(fd); + } + + // fix size of root inode dir + rinode(rootino, &din); + off = xint(din.size); + off = ((off/BSIZE) + 1) * BSIZE; + din.size = xint(off); + winode(rootino, &din); + + balloc(freeblock); + + exit(0); +} + +void +wsect(uint sec, void *buf) +{ + if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE) + die("lseek"); + if(write(fsfd, buf, BSIZE) != BSIZE) + die("write"); +} + +void +winode(uint inum, struct dinode *ip) +{ + char buf[BSIZE]; + uint bn; + struct dinode *dip; + + bn = IBLOCK(inum, sb); + rsect(bn, buf); + dip = ((struct dinode*)buf) + (inum % IPB); + *dip = *ip; + wsect(bn, buf); +} + +void +rinode(uint inum, struct dinode *ip) +{ + char buf[BSIZE]; + uint bn; + struct dinode *dip; + + bn = IBLOCK(inum, sb); + rsect(bn, buf); + dip = ((struct dinode*)buf) + (inum % IPB); + *ip = *dip; +} + +void +rsect(uint sec, void *buf) +{ + if(lseek(fsfd, sec * BSIZE, 0) != sec * BSIZE) + die("lseek"); + if(read(fsfd, buf, BSIZE) != BSIZE) + die("read"); +} + +uint +ialloc(ushort type) +{ + uint inum = freeinode++; + struct dinode din; + + bzero(&din, sizeof(din)); + din.type = xshort(type); + din.nlink = xshort(1); + din.size = xint(0); + winode(inum, &din); + return inum; +} + +void +balloc(int used) +{ + uchar buf[BSIZE]; + int i; + + printf("balloc: first %d blocks have been allocated\n", used); + assert(used < BPB); + bzero(buf, BSIZE); + for(i = 0; i < used; i++){ + buf[i/8] = buf[i/8] | (0x1 << (i%8)); + } + printf("balloc: write bitmap block at sector %d\n", sb.bmapstart); + wsect(sb.bmapstart, buf); +} + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +void +iappend(uint inum, void *xp, int n) +{ + char *p = (char*)xp; + uint fbn, off, n1; + struct dinode din; + char buf[BSIZE]; + uint indirect[NINDIRECT]; + uint x; + + rinode(inum, &din); + off = xint(din.size); + // printf("append inum %d at off %d sz %d\n", inum, off, n); + while(n > 0){ + fbn = off / BSIZE; + assert(fbn < MAXFILE); + if(fbn < NDIRECT){ + if(xint(din.addrs[fbn]) == 0){ + din.addrs[fbn] = xint(freeblock++); + } + x = xint(din.addrs[fbn]); + } else { + if(xint(din.addrs[NDIRECT]) == 0){ + din.addrs[NDIRECT] = xint(freeblock++); + } + rsect(xint(din.addrs[NDIRECT]), (char*)indirect); + if(indirect[fbn - NDIRECT] == 0){ + indirect[fbn - NDIRECT] = xint(freeblock++); + wsect(xint(din.addrs[NDIRECT]), (char*)indirect); + } + x = xint(indirect[fbn-NDIRECT]); + } + n1 = min(n, (fbn + 1) * BSIZE - off); + rsect(x, buf); + bcopy(p, buf + off - (fbn * BSIZE), n1); + wsect(x, buf); + n -= n1; + off += n1; + p += n1; + } + din.size = xint(off); + winode(inum, &din); +} + +void +die(const char *s) +{ + perror(s); + exit(1); +} diff --git a/xv6-os/user/pingpong.c b/xv6-os/user/pingpong.c new file mode 100644 index 00000000..51962d74 --- /dev/null +++ b/xv6-os/user/pingpong.c @@ -0,0 +1,52 @@ +#include "user.h" + +// +1. create pipe +// +2. create child proc +// +3. send "ping" from parent proc to child +// 4. read this msg in child proc, output ": got " and send +// "pong" back +// +5. read response in parent proc, output ": got " +// +// +// +// PS: WOW, YOU CAN ACTUALLY USE wait() AND GET AWAY WITH ONLY ONE PIPE :fire: + +int main() { + int pipefd[2]; // pipe, 0 for red, 1 for write + char buf[10]; + int pid; + + if (pipe(pipefd) < 0) { + printf("Ошибка при создании пайпа\n"); + exit(1); + } + + if ((pid = fork()) < 0) { + printf("Ошибка при создании процесса\n"); + exit(1); + } + + if (pid > 0) { + // parent proc => send "ping", receive "pong" + write(pipefd[1], "ping", 4); + + wait(0); + + if (read(pipefd[0], buf, sizeof(buf)) > 0) { + printf("%d: got %s\n", getpid(), buf); + } + close(pipefd[1]); + close(pipefd[0]); + } else { + // child proc => receive "ping", send "pong" + if (read(pipefd[0], buf, sizeof(buf)) > 0) { + printf("%d: got %s\n", getpid(), buf); + + write(pipefd[1], "pong", 4); + } + close(pipefd[0]); + close(pipefd[1]); + } + + exit(0); +} diff --git a/xv6-os/user/sysinfo.c b/xv6-os/user/sysinfo.c new file mode 100644 index 00000000..dde0ef3b --- /dev/null +++ b/xv6-os/user/sysinfo.c @@ -0,0 +1,17 @@ +#include "user.h" +#include "sysinfo.h" + +int main() { + struct sysinfo sysinfo; + + if (info(&sysinfo) < 0) { + printf("Error bro, better luck next time"); + exit(0); + } + + printf("System info:\n"); + printf(" Number of procs: %d\n", sysinfo.procs_cnt); + printf(" Number of open files: %d\n", sysinfo.open_files); + + exit(0); +} diff --git a/xv6-os/user/sysinfo.h b/xv6-os/user/sysinfo.h new file mode 100644 index 00000000..77a620d5 --- /dev/null +++ b/xv6-os/user/sysinfo.h @@ -0,0 +1,11 @@ +#ifndef _SYSINFO_H_ +#define _SYSINFO_H_ + +struct sysinfo { + int procs_cnt; + int open_files; + int used_ram; + int free_ram; +}; + +#endif // _SYSINFO_H_ diff --git a/xv6-os/user/user.h b/xv6-os/user/user.h index f16fe278..1d38867f 100644 --- a/xv6-os/user/user.h +++ b/xv6-os/user/user.h @@ -1,3 +1,5 @@ +#include "kernel/types.h" +#include "sysinfo.h" struct stat; // system calls @@ -22,6 +24,9 @@ int getpid(void); char* sbrk(int); int sleep(int); int uptime(void); +int dump(void); +int dump2(int pid, int register_num, uint64 *return_value); +int info(struct sysinfo *info); // ulib.c int stat(const char*, struct stat*); diff --git a/xv6-os/user/usys.pl b/xv6-os/user/usys.pl index 01e426e6..92263a80 100755 --- a/xv6-os/user/usys.pl +++ b/xv6-os/user/usys.pl @@ -15,6 +15,9 @@ sub entry { print " ret\n"; } +entry("dump"); +entry("dump2"); +entry("info"); entry("fork"); entry("exit"); entry("wait");