diff options
Diffstat (limited to 'user')
| -rw-r--r-- | user/alarmtest.c | 193 | ||||
| -rw-r--r-- | user/bttest.c | 10 | ||||
| -rw-r--r-- | user/call.c | 17 | ||||
| -rw-r--r-- | user/find.c | 84 | ||||
| -rw-r--r-- | user/pgtbltest.c | 70 | ||||
| -rw-r--r-- | user/pingpong.c | 44 | ||||
| -rw-r--r-- | user/primes.c | 74 | ||||
| -rw-r--r-- | user/sh.c | 3 | ||||
| -rw-r--r-- | user/sleep.c | 22 | ||||
| -rw-r--r-- | user/sysinfotest.c | 153 | ||||
| -rw-r--r-- | user/trace.c | 27 | ||||
| -rw-r--r-- | user/ulib.c | 14 | ||||
| -rw-r--r-- | user/user.h | 14 | ||||
| -rwxr-xr-x | user/usys.pl | 6 | ||||
| -rw-r--r-- | user/xargs.c | 60 | 
15 files changed, 791 insertions, 0 deletions
| diff --git a/user/alarmtest.c b/user/alarmtest.c new file mode 100644 index 0000000..b8d85f7 --- /dev/null +++ b/user/alarmtest.c @@ -0,0 +1,193 @@ +// +// test program for the alarm lab. +// you can modify this file for testing, +// but please make sure your kernel +// modifications pass the original +// versions of these tests. +// + +#include "kernel/param.h" +#include "kernel/types.h" +#include "kernel/stat.h" +#include "kernel/riscv.h" +#include "user/user.h" + +void test0(); +void test1(); +void test2(); +void test3(); +void periodic(); +void slow_handler(); +void dummy_handler(); + +int +main(int argc, char *argv[]) +{ +  test0(); +  test1(); +  test2(); +  test3(); +  exit(0); +} + +volatile static int count; + +void +periodic() +{ +  count = count + 1; +  printf("alarm!\n"); +  sigreturn(); +} + +// tests whether the kernel calls +// the alarm handler even a single time. +void +test0() +{ +  int i; +  printf("test0 start\n"); +  count = 0; +  sigalarm(2, periodic); +  for(i = 0; i < 1000*500000; i++){ +    if((i % 1000000) == 0) +      write(2, ".", 1); +    if(count > 0) +      break; +  } +  sigalarm(0, 0); +  if(count > 0){ +    printf("test0 passed\n"); +  } else { +    printf("\ntest0 failed: the kernel never called the alarm handler\n"); +  } +} + +void __attribute__ ((noinline)) foo(int i, int *j) { +  if((i % 2500000) == 0) { +    write(2, ".", 1); +  } +  *j += 1; +} + +// +// tests that the kernel calls the handler multiple times. +// +// tests that, when the handler returns, it returns to +// the point in the program where the timer interrupt +// occurred, with all registers holding the same values they +// held when the interrupt occurred. +// +void +test1() +{ +  int i; +  int j; + +  printf("test1 start\n"); +  count = 0; +  j = 0; +  sigalarm(2, periodic); +  for(i = 0; i < 500000000; i++){ +    if(count >= 10) +      break; +    foo(i, &j); +  } +  if(count < 10){ +    printf("\ntest1 failed: too few calls to the handler\n"); +  } else if(i != j){ +    // the loop should have called foo() i times, and foo() should +    // have incremented j once per call, so j should equal i. +    // once possible source of errors is that the handler may +    // return somewhere other than where the timer interrupt +    // occurred; another is that that registers may not be +    // restored correctly, causing i or j or the address ofj +    // to get an incorrect value. +    printf("\ntest1 failed: foo() executed fewer times than it was called\n"); +  } else { +    printf("test1 passed\n"); +  } +} + +// +// tests that kernel does not allow reentrant alarm calls. +void +test2() +{ +  int i; +  int pid; +  int status; + +  printf("test2 start\n"); +  if ((pid = fork()) < 0) { +    printf("test2: fork failed\n"); +  } +  if (pid == 0) { +    count = 0; +    sigalarm(2, slow_handler); +    for(i = 0; i < 1000*500000; i++){ +      if((i % 1000000) == 0) +        write(2, ".", 1); +      if(count > 0) +        break; +    } +    if (count == 0) { +      printf("\ntest2 failed: alarm not called\n"); +      exit(1); +    } +    exit(0); +  } +  wait(&status); +  if (status == 0) { +    printf("test2 passed\n"); +  } +} + +void +slow_handler() +{ +  count++; +  printf("alarm!\n"); +  if (count > 1) { +    printf("test2 failed: alarm handler called more than once\n"); +    exit(1); +  } +  for (int i = 0; i < 1000*500000; i++) { +    asm volatile("nop"); // avoid compiler optimizing away loop +  } +  sigalarm(0, 0); +  sigreturn(); +} + +// +// dummy alarm handler; after running immediately uninstall +// itself and finish signal handling +void +dummy_handler() +{ +  sigalarm(0, 0); +  sigreturn(); +} + +// +// tests that the return from sys_sigreturn() does not +// modify the a0 register +void +test3() +{ +  uint64 a0; + +  sigalarm(1, dummy_handler); +  printf("test3 start\n"); + +  asm volatile("lui a5, 0"); +  asm volatile("addi a0, a5, 0xac" : : : "a0"); +  for(int i = 0; i < 500000000; i++) +    ; +  asm volatile("mv %0, a0" : "=r" (a0) ); + +  if(a0 != 0xac) +    printf("test3 failed: register a0 changed\n"); +  else +    printf("test3 passed\n"); +} diff --git a/user/bttest.c b/user/bttest.c new file mode 100644 index 0000000..05405f9 --- /dev/null +++ b/user/bttest.c @@ -0,0 +1,10 @@ +#include "kernel/types.h" +#include "kernel/stat.h" +#include "user/user.h" + +int +main(int argc, char *argv[]) +{ +  sleep(1); +  exit(0); +} diff --git a/user/call.c b/user/call.c new file mode 100644 index 0000000..f725dcb --- /dev/null +++ b/user/call.c @@ -0,0 +1,17 @@ +#include "kernel/param.h" +#include "kernel/types.h" +#include "kernel/stat.h" +#include "user/user.h" + +int g(int x) { +  return x+3; +} + +int f(int x) { +  return g(x); +} + +void main(void) { +  printf("%d %d\n", f(8)+1, 13); +  exit(0); +} diff --git a/user/find.c b/user/find.c new file mode 100644 index 0000000..e185e9d --- /dev/null +++ b/user/find.c @@ -0,0 +1,84 @@ +#include "kernel/types.h" + +#include "kernel/fcntl.h" +#include "kernel/fs.h" +#include "kernel/stat.h" +#include "user/user.h" + +char* +fmtname(char* path) +{ +  char* p; + +  // Find first character after last slash. +  for (p = path + strlen(path); p >= path && *p != '/'; p--) +    ; +  p++; +  return p; +} + +void +find(char* root_path, char* filename) +{ +  static char buf[512]; +  char* p; +  int fd; +  struct dirent de; +  struct stat st; + +  if ((fd = open(root_path, O_RDONLY)) < 0) { +    fprintf(2, "find: cannot open %s\n", root_path); +    return; +  } +  if (fstat(fd, &st) < 0) { +    fprintf(2, "find: cannot stat %s\n", root_path); +    close(fd); +    return; +  } + +  switch (st.type) { +    case T_FILE: +      if (!strcmp(fmtname(root_path), filename)) { +        printf("%s\n", root_path); +      } +      break; +    case T_DIR: +      if (strlen(root_path) + 1 + DIRSIZ + 1 > sizeof(buf)) { +        printf("find: path too long\n"); +        break; +      } + +      strcpy(buf, root_path); + +      p = buf + strlen(buf); +      *p++ = '/'; +      while (read(fd, &de, sizeof(de)) == sizeof(de)) { +        if (de.inum == 0) +          continue; +        memmove(p, de.name, DIRSIZ); +        p[DIRSIZ] = '\0'; + +        // printf("i'm finding %s!\n", fmtname(buf)); + +        if (!strcmp(fmtname(buf), ".") || !strcmp(fmtname(buf), "..")) { +          continue; +        } + +        find(buf, filename); +      } +  } +  close(fd); +} + +int +main(int argc, char* argv[]) +{ +  if (argc < 3) { +    fprintf(2, "usage: find [root_path] filename...\n"); +    exit(1); +  } + +  for (int i = 2; i < argc; i++) { +    find(argv[1], argv[i]); +  } +} diff --git a/user/pgtbltest.c b/user/pgtbltest.c new file mode 100644 index 0000000..bce158a --- /dev/null +++ b/user/pgtbltest.c @@ -0,0 +1,70 @@ +#include "kernel/param.h" +#include "kernel/fcntl.h" +#include "kernel/types.h" +#include "kernel/riscv.h" +#include "user/user.h" + +void ugetpid_test(); +void pgaccess_test(); + +int +main(int argc, char *argv[]) +{ +  ugetpid_test(); +  pgaccess_test(); +  printf("pgtbltest: all tests succeeded\n"); +  exit(0); +} + +char *testname = "???"; + +void +err(char *why) +{ +  printf("pgtbltest: %s failed: %s, pid=%d\n", testname, why, getpid()); +  exit(1); +} + +void +ugetpid_test() +{ +  int i; + +  printf("ugetpid_test starting\n"); +  testname = "ugetpid_test"; + +  for (i = 0; i < 64; i++) { +    int ret = fork(); +    if (ret != 0) { +      wait(&ret); +      if (ret != 0) +        exit(1); +      continue; +    } +    if (getpid() != ugetpid()) +      err("missmatched PID"); +    exit(0); +  } +  printf("ugetpid_test: OK\n"); +} + +void +pgaccess_test() +{ +  char *buf; +  unsigned int abits; +  printf("pgaccess_test starting\n"); +  testname = "pgaccess_test"; +  buf = malloc(32 * PGSIZE); +  if (pgaccess(buf, 32, &abits) < 0) +    err("pgaccess failed"); +  buf[PGSIZE * 1] += 1; +  buf[PGSIZE * 2] += 1; +  buf[PGSIZE * 30] += 1; +  if (pgaccess(buf, 32, &abits) < 0) +    err("pgaccess failed"); +  if (abits != ((1 << 1) | (1 << 2) | (1 << 30))) +    err("incorrect access bits set"); +  free(buf); +  printf("pgaccess_test: OK\n"); +} diff --git a/user/pingpong.c b/user/pingpong.c new file mode 100644 index 0000000..7b03a76 --- /dev/null +++ b/user/pingpong.c @@ -0,0 +1,44 @@ +#include "kernel/types.h" +#include "user/user.h" + +int +main(int argc, char* argv[]) +{ +  int p[2]; + +  if (argc > 1) { +    fprintf(2, "usage: pingpong\n"); +    exit(1); +  } + +  pipe(p); + +  int pid = fork(); + +  if (pid == 0) { +    short n; +    read(p[0], &n, sizeof(n)); +    if (n == 42) { +      fprintf(1, "%d: received ping\n", getpid()); +    } +    n++; +    write(p[1], &n, sizeof(n)); +    close(p[0]); +    close(p[1]); +    exit(0); +  } + +  short n = 42; + +  write(p[1], &n, sizeof(n)); +  read(p[0], &n, sizeof(n)); +  if (n == 43) { +    fprintf(1, "%d: received pong\n", getpid()); +  } +  close(p[0]); +  close(p[1]); + +  wait(0); + +  exit(0); +} diff --git a/user/primes.c b/user/primes.c new file mode 100644 index 0000000..b359524 --- /dev/null +++ b/user/primes.c @@ -0,0 +1,74 @@ +#include "kernel/types.h" +#include "user/user.h" + +#define MAX 36 +#define FIRST_PRIME 2 + +int +generate_natural(); // -> out_fd +int +prime_filter(int in_fd, int prime); // -> out_fd + +int +main(int argc, char* argv[]) +{ +  int prime; + +  int in = generate_natural(); +  while (read(in, &prime, sizeof(int))) { +    // printf("prime %d: in_fd: %d\n", prime, in);  // debug +    printf("prime %d\n", prime); +    in = prime_filter(in, prime); +  } + +  close(in); + +  exit(0); +} + +int +generate_natural() +{ +  int out_pipe[2]; + +  pipe(out_pipe); + +  if (!fork()) { +    for (int i = FIRST_PRIME; i < MAX; i++) { +      write(out_pipe[1], &i, sizeof(int)); +    } +    close(out_pipe[1]); + +    exit(0); +  } + +  close(out_pipe[1]); + +  return out_pipe[0]; +} + +int +prime_filter(int in_fd, int prime) +{ +  int num; +  int out_pipe[2]; + +  pipe(out_pipe); + +  if (!fork()) { +    while (read(in_fd, &num, sizeof(int))) { +      if (num % prime) { +        write(out_pipe[1], &num, sizeof(int)); +      } +    } +    close(in_fd); +    close(out_pipe[1]); + +    exit(0); +  } + +  close(in_fd); +  close(out_pipe[1]); + +  return out_pipe[0]; +} @@ -165,6 +165,9 @@ main(void)          fprintf(2, "cannot cd %s\n", buf+3);        continue;      } +    if(buf[0] == 'e' && buf[1] == 'x' && buf[2] == 'i' && buf[3] == 't'){ +      exit(0); +    }      if(fork1() == 0)        runcmd(parsecmd(buf));      wait(0); diff --git a/user/sleep.c b/user/sleep.c new file mode 100644 index 0000000..961f558 --- /dev/null +++ b/user/sleep.c @@ -0,0 +1,22 @@ +#include "kernel/types.h" +#include "user/user.h" + +int +main(int argc, char* argv[]) +{ +  uint sec = 0; + +  if (argc <= 1) { +    fprintf(2, "usage: sleep [time (ticks)]\n"); +    exit(1); +  } +  sec = atoi(argv[1]); + +  sleep(sec); + +  if (argc <= 2) { +    exit(0); +  } + +  exit(0); +} diff --git a/user/sysinfotest.c b/user/sysinfotest.c new file mode 100644 index 0000000..8a648a6 --- /dev/null +++ b/user/sysinfotest.c @@ -0,0 +1,153 @@ +#include "kernel/types.h" +#include "kernel/riscv.h" +#include "kernel/sysinfo.h" +#include "user/user.h" + + +void +sinfo(struct sysinfo *info) { +  if (sysinfo(info) < 0) { +    printf("FAIL: sysinfo failed"); +    exit(1); +  } +} + +// +// use sbrk() to count how many free physical memory pages there are. +// +int +countfree() +{ +  uint64 sz0 = (uint64)sbrk(0); +  struct sysinfo info; +  int n = 0; + +  while(1){ +    if((uint64)sbrk(PGSIZE) == 0xffffffffffffffff){ +      break; +    } +    n += PGSIZE; +  } +  sinfo(&info); +  if (info.freemem != 0) { +    printf("FAIL: there is no free mem, but sysinfo.freemem=%d\n", +      info.freemem); +    exit(1); +  } +  sbrk(-((uint64)sbrk(0) - sz0)); +  return n; +} + +void +testmem() { +  struct sysinfo info; +  uint64 n = countfree(); +   +  sinfo(&info); + +  if (info.freemem!= n) { +    printf("FAIL: free mem %d (bytes) instead of %d\n", info.freemem, n); +    exit(1); +  } +   +  if((uint64)sbrk(PGSIZE) == 0xffffffffffffffff){ +    printf("sbrk failed"); +    exit(1); +  } + +  sinfo(&info); +     +  if (info.freemem != n-PGSIZE) { +    printf("FAIL: free mem %d (bytes) instead of %d\n", n-PGSIZE, info.freemem); +    exit(1); +  } +   +  if((uint64)sbrk(-PGSIZE) == 0xffffffffffffffff){ +    printf("sbrk failed"); +    exit(1); +  } + +  sinfo(&info); +     +  if (info.freemem != n) { +    printf("FAIL: free mem %d (bytes) instead of %d\n", n, info.freemem); +    exit(1); +  } +} + +void +testcall() { +  struct sysinfo info; +   +  if (sysinfo(&info) < 0) { +    printf("FAIL: sysinfo failed\n"); +    exit(1); +  } + +  if (sysinfo((struct sysinfo *) 0xeaeb0b5b00002f5e) !=  0xffffffffffffffff) { +    printf("FAIL: sysinfo succeeded with bad argument\n"); +    exit(1); +  } +} + +void testproc() { +  struct sysinfo info; +  uint64 nproc; +  int status; +  int pid; +   +  sinfo(&info); +  nproc = info.nproc; + +  pid = fork(); +  if(pid < 0){ +    printf("sysinfotest: fork failed\n"); +    exit(1); +  } +  if(pid == 0){ +    sinfo(&info); +    if(info.nproc != nproc+1) { +      printf("sysinfotest: FAIL nproc is %d instead of %d\n", info.nproc, nproc+1); +      exit(1); +    } +    exit(0); +  } +  wait(&status); +  sinfo(&info); +  if(info.nproc != nproc) { +      printf("sysinfotest: FAIL nproc is %d instead of %d\n", info.nproc, nproc); +      exit(1); +  } +} + +void testbad() { +  int pid = fork(); +  int xstatus; +   +  if(pid < 0){ +    printf("sysinfotest: fork failed\n"); +    exit(1); +  } +  if(pid == 0){ +      sinfo(0x0); +      exit(0); +  } +  wait(&xstatus); +  if(xstatus == -1)  // kernel killed child? +    exit(0); +  else { +    printf("sysinfotest: testbad succeeded %d\n", xstatus); +    exit(xstatus); +  } +} + +int +main(int argc, char *argv[]) +{ +  printf("sysinfotest: start\n"); +  testcall(); +  testmem(); +  testproc(); +  printf("sysinfotest: OK\n"); +  exit(0); +} diff --git a/user/trace.c b/user/trace.c new file mode 100644 index 0000000..dd77760 --- /dev/null +++ b/user/trace.c @@ -0,0 +1,27 @@ +#include "kernel/param.h" +#include "kernel/types.h" +#include "kernel/stat.h" +#include "user/user.h" + +int +main(int argc, char *argv[]) +{ +  int i; +  char *nargv[MAXARG]; + +  if(argc < 3 || (argv[1][0] < '0' || argv[1][0] > '9')){ +    fprintf(2, "Usage: %s mask command\n", argv[0]); +    exit(1); +  } + +  if (trace(atoi(argv[1])) < 0) { +    fprintf(2, "%s: trace failed\n", argv[0]); +    exit(1); +  } +   +  for(i = 2; i < argc && i < MAXARG; i++){ +    nargv[i-2] = argv[i]; +  } +  exec(nargv[0], nargv); +  exit(0); +} diff --git a/user/ulib.c b/user/ulib.c index c7b66c4..871adc9 100644 --- a/user/ulib.c +++ b/user/ulib.c @@ -1,8 +1,13 @@  #include "kernel/types.h"  #include "kernel/stat.h"  #include "kernel/fcntl.h" +#ifdef LAB_PGTBL +#include "kernel/riscv.h" +#include "kernel/memlayout.h" +#endif  #include "user/user.h" +  //  // wrapper so that it's OK if main() does not call exit().  // @@ -145,3 +150,12 @@ memcpy(void *dst, const void *src, uint n)  {    return memmove(dst, src, n);  } + +#ifdef LAB_PGTBL +int +ugetpid(void) +{ +  struct usyscall *u = (struct usyscall *)USYSCALL; +  return u->pid; +} +#endif diff --git a/user/user.h b/user/user.h index 4d398d5..34591fd 100644 --- a/user/user.h +++ b/user/user.h @@ -1,4 +1,5 @@  struct stat; +struct sysinfo;  // system calls  int fork(void); @@ -22,6 +23,18 @@ int getpid(void);  char* sbrk(int);  int sleep(int);  int uptime(void); +#ifdef LAB_NET +int connect(uint32, uint16, uint16); +#endif +#ifdef LAB_PGTBL +int pgaccess(void *base, int len, void *mask); +// usyscall region +int ugetpid(void); +#endif +int trace(int); +int sysinfo(struct sysinfo*); +int sigalarm(int ticks, void (*handler)()); +int sigreturn(void);  // ulib.c  int stat(const char*, struct stat*); @@ -39,3 +52,4 @@ void free(void*);  int atoi(const char*);  int memcmp(const void *, const void *, uint);  void *memcpy(void *, const void *, uint); +int statistics(void*, int); diff --git a/user/usys.pl b/user/usys.pl index 01e426e..33af0ad 100755 --- a/user/usys.pl +++ b/user/usys.pl @@ -36,3 +36,9 @@ entry("getpid");  entry("sbrk");  entry("sleep");  entry("uptime"); +entry("trace"); +entry("sysinfo"); +entry("connect"); +entry("pgaccess"); +entry("sigalarm"); +entry("sigreturn"); diff --git a/user/xargs.c b/user/xargs.c new file mode 100644 index 0000000..b5b9bee --- /dev/null +++ b/user/xargs.c @@ -0,0 +1,60 @@ +#include "kernel/types.h" + +#include "kernel/param.h" +#include "kernel/stat.h" +#include "user/user.h" + +#define is_blank(chr) (chr == ' ' || chr == '\t') + +int +main(int argc, char* argv[]) +{ +  char buf[2048], ch; +  char* p = buf; +  char* v[MAXARG]; +  int c; +  int blanks = 0; +  int offset = 0; + +  if (argc <= 1) { +    fprintf(2, "usage: xargs <command> [argv...]\n"); +    exit(1); +  } + +  for (c = 1; c < argc; c++) { +    v[c - 1] = argv[c]; +  } +  --c; + +  while (read(0, &ch, 1) > 0) { +    if (is_blank(ch)) { +      blanks++; +      continue; +    } + +    if (blanks) { +      buf[offset++] = 0; + +      v[c++] = p; +      p = buf + offset; + +      blanks = 0; +    } + +    if (ch != '\n') { +      buf[offset++] = ch; +    } else { +      v[c++] = p; +      p = buf + offset; + +      if (!fork()) { +        exit(exec(v[0], v)); +      } +      wait(0); + +      c = argc - 1; +    } +  } + +  exit(0); +} | 
