diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 6 | ||||
| -rw-r--r-- | conf/lab.mk | 2 | ||||
| -rwxr-xr-x | grade-lab-traps | 74 | ||||
| -rw-r--r-- | user/alarmtest.c | 193 | ||||
| -rw-r--r-- | user/bttest.c | 10 | ||||
| -rw-r--r-- | user/call.c | 17 | 
7 files changed, 299 insertions, 4 deletions
| @@ -23,5 +23,6 @@ ph  barrier  /lab-*.json  .DS_Store +*.dSYM  riscv/  compile_flags.txt @@ -91,7 +91,7 @@ CFLAGS = -Wall -Werror -O -fno-omit-frame-pointer -ggdb -gdwarf-2  ifdef LAB  LABUPPER = $(shell echo $(LAB) | tr a-z A-Z) -XCFLAGS += -DSOL_$(LABUPPER) -DLAB_$(LABUPPER) +XCFLAGS += -DSOL_$(LABUPPER) -DLAB_$(LABUPPER) -DLAB_PGTBL  endif  CFLAGS += $(XCFLAGS) @@ -273,8 +273,8 @@ fs.img: mkfs/mkfs README $(UEXTRA) $(UPROGS)  -include kernel/*.d user/*.d -clean:  -	rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \ +clean: +	rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg *.dSYM *.zip \  	*/*.o */*.d */*.asm */*.sym \  	$U/initcode $U/initcode.out $K/kernel fs.img \  	mkfs/mkfs .gdbinit \ diff --git a/conf/lab.mk b/conf/lab.mk index 2992d87..2b9988d 100644 --- a/conf/lab.mk +++ b/conf/lab.mk @@ -1 +1 @@ -LAB=pgtbl +LAB=traps diff --git a/grade-lab-traps b/grade-lab-traps new file mode 100755 index 0000000..10613d3 --- /dev/null +++ b/grade-lab-traps @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 + +import os +import re +import subprocess +from gradelib import * + +r = Runner(save("xv6.out")) + +@test(5, "answers-traps.txt") +def test_answers(): +    # just a simple sanity check, will be graded manually +    check_answers("answers-traps.txt") + +BACKTRACE_RE = r"^(0x000000008[0-9a-f]+)" + +def addr2line(): +    for f in ['riscv64-unknown-elf-addr2line', 'riscv64-linux-gnu-addr2line', 'addr2line', ]: +        try: +            devnull = open(os.devnull) +            subprocess.Popen([f], stdout=devnull, stderr=devnull).communicate() +            return f +        except OSError: +            continue +    raise AssertionError('Cannot find the addr2line program') + +@test(10, "backtrace test") +def test_backtracetest(): +    r.run_qemu(shell_script([ +        'bttest' +    ])) +    a2l = addr2line() +    matches = re.findall(BACKTRACE_RE, r.qemu.output, re.MULTILINE) +    assert_equal(len(matches), 3) +    files = ['sysproc.c', 'syscall.c', 'trap.c'] +    for f, m in zip(files, matches): +        result = subprocess.run([a2l, '-e', 'kernel/kernel', m], stdout=subprocess.PIPE) +        if not f in result.stdout.decode("utf-8"): +            raise AssertionError('Trace is incorrect; no %s' % f) + +@test(0, "running alarmtest") +def test_alarmtest(): +    r.run_qemu(shell_script([ +        'alarmtest' +    ])) + +@test(20, "alarmtest: test0", parent=test_alarmtest) +def test_alarmtest_test0(): +    r.match('^test0 passed$') + +@test(20, "alarmtest: test1", parent=test_alarmtest) +def test_alarmtest_test1(): +    r.match('^\\.?test1 passed$') + +@test(10, "alarmtest: test2", parent=test_alarmtest) +def test_alarmtest_test2(): +    r.match('^\\.?test2 passed$') + +@test(10, "alarmtest: test3", parent=test_alarmtest) +def test_alarmtest_test3(): +    r.match('^test3 passed$') + +@test(19, "usertests") +def test_usertests(): +    r.run_qemu(shell_script([ +        'usertests -q' +    ]), timeout=300) +    r.match('^ALL TESTS PASSED$') + +@test(1, "time") +def test_time(): +    check_time() + +run_tests() 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); +} | 
