diff --git a/.cache/clangd/index/bio.c.34489AC9E3FB27B2.idx b/.cache/clangd/index/bio.c.34489AC9E3FB27B2.idx new file mode 100644 index 0000000..4605511 Binary files /dev/null and b/.cache/clangd/index/bio.c.34489AC9E3FB27B2.idx differ diff --git a/.cache/clangd/index/buf.h.7DA89D0539A50AFB.idx b/.cache/clangd/index/buf.h.7DA89D0539A50AFB.idx new file mode 100644 index 0000000..46c2b70 Binary files /dev/null and b/.cache/clangd/index/buf.h.7DA89D0539A50AFB.idx differ diff --git a/.cache/clangd/index/console.c.A959DCA84FDA00CD.idx b/.cache/clangd/index/console.c.A959DCA84FDA00CD.idx new file mode 100644 index 0000000..27a9712 Binary files /dev/null and b/.cache/clangd/index/console.c.A959DCA84FDA00CD.idx differ diff --git a/.cache/clangd/index/defs.h.72A9C4FFB86E6400.idx b/.cache/clangd/index/defs.h.72A9C4FFB86E6400.idx new file mode 100644 index 0000000..fdb6dfc Binary files /dev/null and b/.cache/clangd/index/defs.h.72A9C4FFB86E6400.idx differ diff --git a/.cache/clangd/index/elf.h.B51ED6807EFE6571.idx b/.cache/clangd/index/elf.h.B51ED6807EFE6571.idx new file mode 100644 index 0000000..5099316 Binary files /dev/null and b/.cache/clangd/index/elf.h.B51ED6807EFE6571.idx differ diff --git a/.cache/clangd/index/entry.S.7790893A73F2EC77.idx b/.cache/clangd/index/entry.S.7790893A73F2EC77.idx new file mode 100644 index 0000000..e894067 Binary files /dev/null and b/.cache/clangd/index/entry.S.7790893A73F2EC77.idx differ diff --git a/.cache/clangd/index/exec.c.C583EF6E813AE52A.idx b/.cache/clangd/index/exec.c.C583EF6E813AE52A.idx new file mode 100644 index 0000000..43bbc27 Binary files /dev/null and b/.cache/clangd/index/exec.c.C583EF6E813AE52A.idx differ diff --git a/.cache/clangd/index/fcntl.h.204FC1983BB1DFC2.idx b/.cache/clangd/index/fcntl.h.204FC1983BB1DFC2.idx new file mode 100644 index 0000000..49fdadc Binary files /dev/null and b/.cache/clangd/index/fcntl.h.204FC1983BB1DFC2.idx differ diff --git a/.cache/clangd/index/file.c.E75BF18666EA6C16.idx b/.cache/clangd/index/file.c.E75BF18666EA6C16.idx new file mode 100644 index 0000000..acd967a Binary files /dev/null and b/.cache/clangd/index/file.c.E75BF18666EA6C16.idx differ diff --git a/.cache/clangd/index/file.h.2A63A83574D7D652.idx b/.cache/clangd/index/file.h.2A63A83574D7D652.idx new file mode 100644 index 0000000..573e589 Binary files /dev/null and b/.cache/clangd/index/file.h.2A63A83574D7D652.idx differ diff --git a/.cache/clangd/index/fs.c.DE158A81433875BE.idx b/.cache/clangd/index/fs.c.DE158A81433875BE.idx new file mode 100644 index 0000000..d09e3a1 Binary files /dev/null and b/.cache/clangd/index/fs.c.DE158A81433875BE.idx differ diff --git a/.cache/clangd/index/fs.h.F83902F1C88C3791.idx b/.cache/clangd/index/fs.h.F83902F1C88C3791.idx new file mode 100644 index 0000000..bd942a8 Binary files /dev/null and b/.cache/clangd/index/fs.h.F83902F1C88C3791.idx differ diff --git a/.cache/clangd/index/initcode.S.373AF54AA740F373.idx b/.cache/clangd/index/initcode.S.373AF54AA740F373.idx new file mode 100644 index 0000000..2a24094 Binary files /dev/null and b/.cache/clangd/index/initcode.S.373AF54AA740F373.idx differ diff --git a/.cache/clangd/index/kalloc.c.2F15DD93067E2B26.idx b/.cache/clangd/index/kalloc.c.2F15DD93067E2B26.idx new file mode 100644 index 0000000..1123038 Binary files /dev/null and b/.cache/clangd/index/kalloc.c.2F15DD93067E2B26.idx differ diff --git a/.cache/clangd/index/kernelvec.S.06F25524429F6CAE.idx b/.cache/clangd/index/kernelvec.S.06F25524429F6CAE.idx new file mode 100644 index 0000000..6d4347b Binary files /dev/null and b/.cache/clangd/index/kernelvec.S.06F25524429F6CAE.idx differ diff --git a/.cache/clangd/index/log.c.D81C51C68A1AD96E.idx b/.cache/clangd/index/log.c.D81C51C68A1AD96E.idx new file mode 100644 index 0000000..276d3c6 Binary files /dev/null and b/.cache/clangd/index/log.c.D81C51C68A1AD96E.idx differ diff --git a/.cache/clangd/index/main.c.2DC262271CAFD048.idx b/.cache/clangd/index/main.c.2DC262271CAFD048.idx new file mode 100644 index 0000000..4a05bc8 Binary files /dev/null and b/.cache/clangd/index/main.c.2DC262271CAFD048.idx differ diff --git a/.cache/clangd/index/memlayout.h.0B2C565D58B84A48.idx b/.cache/clangd/index/memlayout.h.0B2C565D58B84A48.idx new file mode 100644 index 0000000..9f27e6d Binary files /dev/null and b/.cache/clangd/index/memlayout.h.0B2C565D58B84A48.idx differ diff --git a/.cache/clangd/index/param.h.37451DCC2B36E012.idx b/.cache/clangd/index/param.h.37451DCC2B36E012.idx new file mode 100644 index 0000000..963f60d Binary files /dev/null and b/.cache/clangd/index/param.h.37451DCC2B36E012.idx differ diff --git a/.cache/clangd/index/pipe.c.2473E067140E4F18.idx b/.cache/clangd/index/pipe.c.2473E067140E4F18.idx new file mode 100644 index 0000000..fde1892 Binary files /dev/null and b/.cache/clangd/index/pipe.c.2473E067140E4F18.idx differ diff --git a/.cache/clangd/index/plic.c.2EA8519EDD3A2B20.idx b/.cache/clangd/index/plic.c.2EA8519EDD3A2B20.idx new file mode 100644 index 0000000..33631e9 Binary files /dev/null and b/.cache/clangd/index/plic.c.2EA8519EDD3A2B20.idx differ diff --git a/.cache/clangd/index/printf.c.0918689B2930FAE2.idx b/.cache/clangd/index/printf.c.0918689B2930FAE2.idx new file mode 100644 index 0000000..af5312e Binary files /dev/null and b/.cache/clangd/index/printf.c.0918689B2930FAE2.idx differ diff --git a/.cache/clangd/index/proc.c.5346DCDE506E9F58.idx b/.cache/clangd/index/proc.c.5346DCDE506E9F58.idx new file mode 100644 index 0000000..7d9b38f Binary files /dev/null and b/.cache/clangd/index/proc.c.5346DCDE506E9F58.idx differ diff --git a/.cache/clangd/index/proc.h.27341B4843D3B8B6.idx b/.cache/clangd/index/proc.h.27341B4843D3B8B6.idx new file mode 100644 index 0000000..ab1c63b Binary files /dev/null and b/.cache/clangd/index/proc.h.27341B4843D3B8B6.idx differ diff --git a/.cache/clangd/index/riscv.h.6737E35D6CB953E7.idx b/.cache/clangd/index/riscv.h.6737E35D6CB953E7.idx new file mode 100644 index 0000000..ebabe88 Binary files /dev/null and b/.cache/clangd/index/riscv.h.6737E35D6CB953E7.idx differ diff --git a/.cache/clangd/index/sleeplock.c.BC30DEE970D57711.idx b/.cache/clangd/index/sleeplock.c.BC30DEE970D57711.idx new file mode 100644 index 0000000..22a20a8 Binary files /dev/null and b/.cache/clangd/index/sleeplock.c.BC30DEE970D57711.idx differ diff --git a/.cache/clangd/index/sleeplock.h.56E9B1C95DBCB92F.idx b/.cache/clangd/index/sleeplock.h.56E9B1C95DBCB92F.idx new file mode 100644 index 0000000..4ca73a2 Binary files /dev/null and b/.cache/clangd/index/sleeplock.h.56E9B1C95DBCB92F.idx differ diff --git a/.cache/clangd/index/spinlock.c.1B29CD753041D103.idx b/.cache/clangd/index/spinlock.c.1B29CD753041D103.idx new file mode 100644 index 0000000..bc9194f Binary files /dev/null and b/.cache/clangd/index/spinlock.c.1B29CD753041D103.idx differ diff --git a/.cache/clangd/index/spinlock.h.7E8FC04641EE310E.idx b/.cache/clangd/index/spinlock.h.7E8FC04641EE310E.idx new file mode 100644 index 0000000..219f9eb Binary files /dev/null and b/.cache/clangd/index/spinlock.h.7E8FC04641EE310E.idx differ diff --git a/.cache/clangd/index/start.c.92F9EB51DC5F96B3.idx b/.cache/clangd/index/start.c.92F9EB51DC5F96B3.idx new file mode 100644 index 0000000..effdda7 Binary files /dev/null and b/.cache/clangd/index/start.c.92F9EB51DC5F96B3.idx differ diff --git a/.cache/clangd/index/stat.h.AEE4CE7ADDE89C85.idx b/.cache/clangd/index/stat.h.AEE4CE7ADDE89C85.idx new file mode 100644 index 0000000..4bace52 Binary files /dev/null and b/.cache/clangd/index/stat.h.AEE4CE7ADDE89C85.idx differ diff --git a/.cache/clangd/index/string.c.87F56374FD494C3A.idx b/.cache/clangd/index/string.c.87F56374FD494C3A.idx new file mode 100644 index 0000000..bde6008 Binary files /dev/null and b/.cache/clangd/index/string.c.87F56374FD494C3A.idx differ diff --git a/.cache/clangd/index/swtch.S.11DB57B07ECB88BC.idx b/.cache/clangd/index/swtch.S.11DB57B07ECB88BC.idx new file mode 100644 index 0000000..7ccddfb Binary files /dev/null and b/.cache/clangd/index/swtch.S.11DB57B07ECB88BC.idx differ diff --git a/.cache/clangd/index/syscall.c.05D088F49A8C83CC.idx b/.cache/clangd/index/syscall.c.05D088F49A8C83CC.idx new file mode 100644 index 0000000..398382c Binary files /dev/null and b/.cache/clangd/index/syscall.c.05D088F49A8C83CC.idx differ diff --git a/.cache/clangd/index/syscall.h.66E962A052CADC6A.idx b/.cache/clangd/index/syscall.h.66E962A052CADC6A.idx new file mode 100644 index 0000000..a9b04a2 Binary files /dev/null and b/.cache/clangd/index/syscall.h.66E962A052CADC6A.idx differ diff --git a/.cache/clangd/index/sysfile.c.C337A604B3627C12.idx b/.cache/clangd/index/sysfile.c.C337A604B3627C12.idx new file mode 100644 index 0000000..9a6b440 Binary files /dev/null and b/.cache/clangd/index/sysfile.c.C337A604B3627C12.idx differ diff --git a/.cache/clangd/index/sysproc.c.E5BC46BBC06178C3.idx b/.cache/clangd/index/sysproc.c.E5BC46BBC06178C3.idx new file mode 100644 index 0000000..e80f95c Binary files /dev/null and b/.cache/clangd/index/sysproc.c.E5BC46BBC06178C3.idx differ diff --git a/.cache/clangd/index/trampoline.S.ABB830BE366004AD.idx b/.cache/clangd/index/trampoline.S.ABB830BE366004AD.idx new file mode 100644 index 0000000..ea5ddc9 Binary files /dev/null and b/.cache/clangd/index/trampoline.S.ABB830BE366004AD.idx differ diff --git a/.cache/clangd/index/trap.c.E331BC8CB04ABF35.idx b/.cache/clangd/index/trap.c.E331BC8CB04ABF35.idx new file mode 100644 index 0000000..431730b Binary files /dev/null and b/.cache/clangd/index/trap.c.E331BC8CB04ABF35.idx differ diff --git a/.cache/clangd/index/types.h.9C15A82D28EB699F.idx b/.cache/clangd/index/types.h.9C15A82D28EB699F.idx new file mode 100644 index 0000000..4c17da9 Binary files /dev/null and b/.cache/clangd/index/types.h.9C15A82D28EB699F.idx differ diff --git a/.cache/clangd/index/uart.c.382E637B5067D2B7.idx b/.cache/clangd/index/uart.c.382E637B5067D2B7.idx new file mode 100644 index 0000000..61e1188 Binary files /dev/null and b/.cache/clangd/index/uart.c.382E637B5067D2B7.idx differ diff --git a/.cache/clangd/index/virtio.h.7AE2FDAEE3C87964.idx b/.cache/clangd/index/virtio.h.7AE2FDAEE3C87964.idx new file mode 100644 index 0000000..324596f Binary files /dev/null and b/.cache/clangd/index/virtio.h.7AE2FDAEE3C87964.idx differ diff --git a/.cache/clangd/index/virtio_disk.c.8DF9309BB95BE078.idx b/.cache/clangd/index/virtio_disk.c.8DF9309BB95BE078.idx new file mode 100644 index 0000000..8bf0cf8 Binary files /dev/null and b/.cache/clangd/index/virtio_disk.c.8DF9309BB95BE078.idx differ diff --git a/.cache/clangd/index/vm.c.70D05D5C0213F437.idx b/.cache/clangd/index/vm.c.70D05D5C0213F437.idx new file mode 100644 index 0000000..df084de Binary files /dev/null and b/.cache/clangd/index/vm.c.70D05D5C0213F437.idx differ diff --git a/.gitignore b/.gitignore index 07216f3..5c33438 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,11 @@ mkfs kernel/kernel user/usys.S .gdbinit +*.zip +xv6.out* +.vagrant/ +submissions/ +ph +barrier +/lab-*.json +.DS_Store diff --git a/Makefile b/Makefile index 39a99d7..ebfd077 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,16 @@ + +# To compile and run with a lab solution, set the lab name in conf/lab.mk +# (e.g., LAB=util). Run make grade to test solution with the lab's +# grade script (e.g., grade-lab-util). + +-include conf/lab.mk + K=kernel U=user OBJS = \ $K/entry.o \ - $K/start.o \ - $K/console.o \ - $K/printf.o \ - $K/uart.o \ $K/kalloc.o \ - $K/spinlock.o \ $K/string.o \ $K/main.o \ $K/vm.o \ @@ -30,6 +32,34 @@ OBJS = \ $K/plic.o \ $K/virtio_disk.o +OBJS_KCSAN = \ + $K/start.o \ + $K/console.o \ + $K/printf.o \ + $K/uart.o \ + $K/spinlock.o + +ifdef KCSAN +OBJS_KCSAN += \ + $K/kcsan.o +endif + +ifeq ($(LAB),$(filter $(LAB), lock)) +OBJS += \ + $K/stats.o\ + $K/sprintf.o +endif + + +ifeq ($(LAB),net) +OBJS += \ + $K/e1000.o \ + $K/net.o \ + $K/sysnet.o \ + $K/pci.o +endif + + # riscv64-unknown-elf- or riscv64-linux-gnu- # perhaps in /opt/riscv/bin #TOOLPREFIX = @@ -57,12 +87,28 @@ OBJCOPY = $(TOOLPREFIX)objcopy OBJDUMP = $(TOOLPREFIX)objdump 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) +endif + +CFLAGS += $(XCFLAGS) CFLAGS += -MD CFLAGS += -mcmodel=medany CFLAGS += -ffreestanding -fno-common -nostdlib -mno-relax CFLAGS += -I. CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector) +ifeq ($(LAB),net) +CFLAGS += -DNET_TESTS_PORT=$(SERVERPORT) +endif + +ifdef KCSAN +CFLAGS += -DKCSAN +KCSANFLAG = -fsanitize=thread -fno-inline +endif + # Disable PIE when possible (for Ubuntu 16.10 toolchain) ifneq ($(shell $(CC) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),) CFLAGS += -fno-pie -no-pie @@ -73,11 +119,17 @@ endif LDFLAGS = -z max-page-size=4096 -$K/kernel: $(OBJS) $K/kernel.ld $U/initcode - $(LD) $(LDFLAGS) -T $K/kernel.ld -o $K/kernel $(OBJS) +$K/kernel: $(OBJS) $(OBJS_KCSAN) $K/kernel.ld $U/initcode + $(LD) $(LDFLAGS) -T $K/kernel.ld -o $K/kernel $(OBJS) $(OBJS_KCSAN) $(OBJDUMP) -S $K/kernel > $K/kernel.asm $(OBJDUMP) -t $K/kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $K/kernel.sym +$(OBJS): EXTRAFLAG := $(KCSANFLAG) + +$K/%.o: $K/%.c + $(CC) $(CFLAGS) $(EXTRAFLAG) -c -o $@ $< + + $U/initcode: $U/initcode.S $(CC) $(CFLAGS) -march=rv64g -nostdinc -I. -Ikernel -c $U/initcode.S -o $U/initcode.o $(LD) $(LDFLAGS) -N -e start -Ttext 0 -o $U/initcode.out $U/initcode.o @@ -89,6 +141,10 @@ tags: $(OBJS) _init ULIB = $U/ulib.o $U/usys.o $U/printf.o $U/umalloc.o +ifeq ($(LAB),$(filter $(LAB), lock)) +ULIB += $U/statistics.o +endif + _%: %.o $(ULIB) $(LD) $(LDFLAGS) -T $U/user.ld -o $@ $^ $(OBJDUMP) -S $@ > $*.asm @@ -107,7 +163,7 @@ $U/_forktest: $U/forktest.o $(ULIB) $(OBJDUMP) -S $U/_forktest > $U/forktest.asm mkfs/mkfs: mkfs/mkfs.c $K/fs.h $K/param.h - gcc -Werror -Wall -I. -o mkfs/mkfs mkfs/mkfs.c + gcc $(XCFLAGS) -Werror -Wall -I. -o mkfs/mkfs mkfs/mkfs.c # Prevent deletion of intermediate files, e.g. cat.o, after first build, so # that disk image changes after first build are persistent until clean. More @@ -132,9 +188,81 @@ UPROGS=\ $U/_grind\ $U/_wc\ $U/_zombie\ + $U/_trace\ + $U/_sysinfotest + -fs.img: mkfs/mkfs README $(UPROGS) - mkfs/mkfs fs.img README $(UPROGS) + +ifeq ($(LAB),$(filter $(LAB), lock)) +UPROGS += \ + $U/_stats +endif + +ifeq ($(LAB),traps) +UPROGS += \ + $U/_call\ + $U/_bttest +endif + +ifeq ($(LAB),lazy) +UPROGS += \ + $U/_lazytests +endif + +ifeq ($(LAB),cow) +UPROGS += \ + $U/_cowtest +endif + +ifeq ($(LAB),thread) +UPROGS += \ + $U/_uthread + +$U/uthread_switch.o : $U/uthread_switch.S + $(CC) $(CFLAGS) -c -o $U/uthread_switch.o $U/uthread_switch.S + +$U/_uthread: $U/uthread.o $U/uthread_switch.o $(ULIB) + $(LD) $(LDFLAGS) -N -e main -Ttext 0 -o $U/_uthread $U/uthread.o $U/uthread_switch.o $(ULIB) + $(OBJDUMP) -S $U/_uthread > $U/uthread.asm + +ph: notxv6/ph.c + gcc -o ph -g -O2 $(XCFLAGS) notxv6/ph.c -pthread + +barrier: notxv6/barrier.c + gcc -o barrier -g -O2 $(XCFLAGS) notxv6/barrier.c -pthread +endif + +ifeq ($(LAB),pgtbl) +UPROGS += \ + $U/_pgtbltest +endif + +ifeq ($(LAB),lock) +UPROGS += \ + $U/_kalloctest\ + $U/_bcachetest +endif + +ifeq ($(LAB),fs) +UPROGS += \ + $U/_bigfile +endif + + + +ifeq ($(LAB),net) +UPROGS += \ + $U/_nettests +endif + +UEXTRA= +ifeq ($(LAB),util) + UEXTRA += user/xargstest.sh +endif + + +fs.img: mkfs/mkfs README $(UEXTRA) $(UPROGS) + mkfs/mkfs fs.img README $(UEXTRA) $(UPROGS) -include kernel/*.d user/*.d @@ -144,7 +272,9 @@ clean: $U/initcode $U/initcode.out $K/kernel fs.img \ mkfs/mkfs .gdbinit \ $U/usys.S \ - $(UPROGS) + $(UPROGS) \ + *.zip \ + ph barrier # try to generate a unique GDB port GDBPORT = $(shell expr `id -u` % 5000 + 25000) @@ -155,12 +285,22 @@ QEMUGDB = $(shell if $(QEMU) -help | grep -q '^-gdb'; \ ifndef CPUS CPUS := 3 endif +ifeq ($(LAB),fs) +CPUS := 1 +endif + +FWDPORT = $(shell expr `id -u` % 5000 + 25999) QEMUOPTS = -machine virt -bios none -kernel $K/kernel -m 128M -smp $(CPUS) -nographic QEMUOPTS += -global virtio-mmio.force-legacy=false QEMUOPTS += -drive file=fs.img,if=none,format=raw,id=x0 QEMUOPTS += -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 +ifeq ($(LAB),net) +QEMUOPTS += -netdev user,id=net0,hostfwd=udp::$(FWDPORT)-:2000 -object filter-dump,id=net0,netdev=net0,file=packets.pcap +QEMUOPTS += -device e1000,netdev=net0,bus=pcie.0 +endif + qemu: $K/kernel fs.img $(QEMU) $(QEMUOPTS) @@ -171,3 +311,61 @@ qemu-gdb: $K/kernel .gdbinit fs.img @echo "*** Now run 'gdb' in another window." 1>&2 $(QEMU) $(QEMUOPTS) -S $(QEMUGDB) +ifeq ($(LAB),net) +# try to generate a unique port for the echo server +SERVERPORT = $(shell expr `id -u` % 5000 + 25099) + +server: + python3 server.py $(SERVERPORT) + +ping: + python3 ping.py $(FWDPORT) +endif + +## +## FOR testing lab grading script +## + +ifneq ($(V),@) +GRADEFLAGS += -v +endif + +print-gdbport: + @echo $(GDBPORT) + +grade: + @echo $(MAKE) clean + @$(MAKE) clean || \ + (echo "'make clean' failed. HINT: Do you have another running instance of xv6?" && exit 1) + ./grade-lab-$(LAB) $(GRADEFLAGS) + +## +## FOR submissions +## + +submit-check: + @if ! test -d .git; then \ + echo No .git directory, is this a git repository?; \ + false; \ + fi + @if test "$$(git symbolic-ref HEAD)" != refs/heads/$(LAB); then \ + git branch; \ + read -p "You are not on the $(LAB) branch. Hand-in the current branch? [y/N] " r; \ + test "$$r" = y; \ + fi + @if ! git diff-files --quiet || ! git diff-index --quiet --cached HEAD; then \ + git status -s; \ + echo; \ + echo "You have uncomitted changes. Please commit or stash them."; \ + false; \ + fi + @if test -n "`git status -s`"; then \ + git status -s; \ + read -p "Untracked files will not be handed in. Continue? [y/N] " r; \ + test "$$r" = y; \ + fi + +zipball: clean submit-check + git archive --verbose --format zip --output lab.zip HEAD + +.PHONY: zipball clean grade submit-check diff --git a/compile_commands.json b/compile_commands.json new file mode 100644 index 0000000..b8debc6 --- /dev/null +++ b/compile_commands.json @@ -0,0 +1,702 @@ +[ + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-c", + "-o", + "kernel/entry.o", + "kernel/entry.S" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/entry.S", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/entry.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/kalloc.o", + "kernel/kalloc.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/kalloc.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/kalloc.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/string.o", + "kernel/string.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/string.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/string.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/main.o", + "kernel/main.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/main.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/main.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/vm.o", + "kernel/vm.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/vm.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/vm.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/proc.o", + "kernel/proc.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/proc.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/proc.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-c", + "-o", + "kernel/swtch.o", + "kernel/swtch.S" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/swtch.S", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/swtch.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-c", + "-o", + "kernel/trampoline.o", + "kernel/trampoline.S" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/trampoline.S", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/trampoline.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/trap.o", + "kernel/trap.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/trap.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/trap.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/syscall.o", + "kernel/syscall.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/syscall.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/syscall.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/sysproc.o", + "kernel/sysproc.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/sysproc.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/sysproc.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/bio.o", + "kernel/bio.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/bio.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/bio.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/fs.o", + "kernel/fs.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/fs.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/fs.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/log.o", + "kernel/log.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/log.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/log.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/sleeplock.o", + "kernel/sleeplock.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/sleeplock.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/sleeplock.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/file.o", + "kernel/file.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/file.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/file.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/pipe.o", + "kernel/pipe.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/pipe.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/pipe.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/exec.o", + "kernel/exec.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/exec.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/exec.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/sysfile.o", + "kernel/sysfile.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/sysfile.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/sysfile.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-c", + "-o", + "kernel/kernelvec.o", + "kernel/kernelvec.S" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/kernelvec.S", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/kernelvec.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/plic.o", + "kernel/plic.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/plic.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/plic.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/virtio_disk.o", + "kernel/virtio_disk.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/virtio_disk.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/virtio_disk.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/start.o", + "kernel/start.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/start.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/start.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/console.o", + "kernel/console.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/console.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/console.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/printf.o", + "kernel/printf.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/printf.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/printf.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/uart.o", + "kernel/uart.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/uart.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/uart.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-c", + "-o", + "kernel/spinlock.o", + "kernel/spinlock.c" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/kernel/spinlock.c", + "output": "/home/novice/mit_xv6/xv6-labs-2023/kernel/spinlock.o" + }, + { + "arguments": [ + "/usr/bin/riscv64-linux-gnu-gcc", + "-Wall", + "-Werror", + "-O", + "-fno-omit-frame-pointer", + "-ggdb", + "-gdwarf-2", + "-DSOL_SYSCALL", + "-DLAB_SYSCALL", + "-mcmodel=medany", + "-ffreestanding", + "-fno-common", + "-mno-relax", + "-I.", + "-fno-stack-protector", + "-fno-pie", + "-march=rv64g", + "-nostdinc", + "-I.", + "-Ikernel", + "-c", + "-o", + "user/initcode.o", + "user/initcode.S" + ], + "directory": "/home/novice/mit_xv6/xv6-labs-2023", + "file": "/home/novice/mit_xv6/xv6-labs-2023/user/initcode.S", + "output": "/home/novice/mit_xv6/xv6-labs-2023/user/initcode.o" + } +] diff --git a/conf/lab.mk b/conf/lab.mk new file mode 100644 index 0000000..278d1a8 --- /dev/null +++ b/conf/lab.mk @@ -0,0 +1 @@ +LAB=syscall diff --git a/grade-lab-syscall b/grade-lab-syscall new file mode 100755 index 0000000..18d3b72 --- /dev/null +++ b/grade-lab-syscall @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 + +import re +from gradelib import * + +r = Runner(save("xv6.out")) + +@test(5, "answers-syscall.txt") +def test_answers(): + # just a simple sanity check, will be graded manually + check_answers("answers-syscall.txt") + +@test(5, "trace 32 grep") +def test_trace_32_grep(): + r.run_qemu(shell_script([ + 'trace 32 grep hello README' + ])) + r.match('^\\d+: syscall read -> 1023') + r.match('^\\d+: syscall read -> 961') + r.match('^\\d+: syscall read -> 321') + r.match('^\\d+: syscall read -> 0') + +@test(5, "trace all grep") +def test_trace_all_grep(): + r.run_qemu(shell_script([ + 'trace 2147483647 grep hello README' + ])) + r.match('^\\d+: syscall trace -> 0') + r.match('^\\d+: syscall exec -> 3') + r.match('^\\d+: syscall open -> 3') + r.match('^\\d+: syscall read -> 1023') + r.match('^\\d+: syscall read -> 961') + r.match('^\\d+: syscall read -> 321') + r.match('^\\d+: syscall read -> 0') + r.match('^\\d+: syscall close -> 0') + +@test(5, "trace nothing") +def test_trace_nothing(): + r.run_qemu(shell_script([ + 'grep hello README' + ])) + r.match(no=[".* syscall .*"]) + +@test(5, "trace children") +def test_trace_children(): + r.run_qemu(shell_script([ + 'trace 2 usertests forkforkfork' + ])) + r.match('3: syscall fork -> 4') + r.match('^5: syscall fork -> \\d+') + r.match('^6: syscall fork -> \\d+') + r.match('^\\d+: syscall fork -> -1') + r.match('^ALL TESTS PASSED') + +@test(14, "sysinfotest") +def test_sysinfotest(): + r.run_qemu(shell_script([ + 'sysinfotest' + ])) + r.match('^sysinfotest: OK', no=[".* FAIL .*"]) + +@test(1, "time") +def test_time(): + check_time() + +run_tests() + + + diff --git a/gradelib.py b/gradelib.py new file mode 100644 index 0000000..f0d4934 --- /dev/null +++ b/gradelib.py @@ -0,0 +1,628 @@ +from __future__ import print_function + +import sys, os, re, time, socket, select, subprocess, errno, shutil, random, string, json +from subprocess import check_call, Popen +from optparse import OptionParser + +__all__ = [] + +################################################################## +# Test structure +# + +__all__ += ["test", "end_part", "run_tests", "get_current_test"] + +TESTS = [] +TOTAL = POSSIBLE = 0 +PART_TOTAL = PART_POSSIBLE = 0 +CURRENT_TEST = None +GRADES = {} + +def test(points, title=None, parent=None): + """Decorator for declaring test functions. If title is None, the + title of the test will be derived from the function name by + stripping the leading "test_" and replacing underscores with + spaces.""" + + def register_test(fn, title=title): + if not title: + assert fn.__name__.startswith("test_") + title = fn.__name__[5:].replace("_", " ") + if parent: + title = " " + title + + def run_test(): + global TOTAL, POSSIBLE, CURRENT_TEST, GRADES + + # Handle test dependencies + if run_test.complete: + return run_test.ok + run_test.complete = True + parent_failed = False + if parent: + parent_failed = not parent() + + # Run the test + fail = None + start = time.time() + CURRENT_TEST = run_test + sys.stdout.write("== Test %s == " % title) + if parent: + sys.stdout.write("\n") + sys.stdout.flush() + try: + if parent_failed: + raise AssertionError('Parent failed: %s' % parent.__name__) + fn() + except AssertionError as e: + fail = str(e) + + # Display and handle test result + POSSIBLE += points + if points: + print("%s: %s" % (title, \ + (color("red", "FAIL") if fail else color("green", "OK"))), end=' ') + if time.time() - start > 0.1: + print("(%.1fs)" % (time.time() - start), end=' ') + print() + if fail: + print(" %s" % fail.replace("\n", "\n ")) + else: + TOTAL += points + if points: + GRADES[title] = 0 if fail else points + + for callback in run_test.on_finish: + callback(fail) + CURRENT_TEST = None + + run_test.ok = not fail + return run_test.ok + + # Record test metadata on the test wrapper function + run_test.__name__ = fn.__name__ + run_test.title = title + run_test.complete = False + run_test.ok = False + run_test.on_finish = [] + TESTS.append(run_test) + return run_test + return register_test + +def end_part(name): + def show_part(): + global PART_TOTAL, PART_POSSIBLE + print("Part %s score: %d/%d" % \ + (name, TOTAL - PART_TOTAL, POSSIBLE - PART_POSSIBLE)) + print() + PART_TOTAL, PART_POSSIBLE = TOTAL, POSSIBLE + show_part.title = "" + TESTS.append(show_part) + +def write_results(): + global options + if not options.results: + return + try: + with open(options.results, "w") as f: + f.write(json.dumps(GRADES)) + except OSError as e: + print("Provided a bad results path. Error:", e) + +def run_tests(): + """Set up for testing and run the registered test functions.""" + + # Handle command line + global options + parser = OptionParser(usage="usage: %prog [-v] [filters...]") + parser.add_option("-v", "--verbose", action="store_true", + help="print commands") + parser.add_option("--color", choices=["never", "always", "auto"], + default="auto", help="never, always, or auto") + parser.add_option("--results", help="results file path") + (options, args) = parser.parse_args() + + # Start with a full build to catch build errors + make() + + # Clean the file system if there is one + reset_fs() + + # Run tests + limit = list(map(str.lower, args)) + try: + for test in TESTS: + if not limit or any(l in test.title.lower() for l in limit): + test() + if not limit: + write_results() + print("Score: %d/%d" % (TOTAL, POSSIBLE)) + except KeyboardInterrupt: + pass + if TOTAL < POSSIBLE: + sys.exit(1) + +def get_current_test(): + if not CURRENT_TEST: + raise RuntimeError("No test is running") + return CURRENT_TEST + +################################################################## +# Assertions +# + +__all__ += ["assert_equal", "assert_lines_match"] + +def assert_equal(got, expect, msg=""): + if got == expect: + return + if msg: + msg += "\n" + raise AssertionError("%sgot:\n %s\nexpected:\n %s" % + (msg, str(got).replace("\n", "\n "), + str(expect).replace("\n", "\n "))) + +def assert_lines_match(text, *regexps, **kw): + """Assert that all of regexps match some line in text. If a 'no' + keyword argument is given, it must be a list of regexps that must + *not* match any line in text.""" + + def assert_lines_match_kw(no=[]): + return no + no = assert_lines_match_kw(**kw) + + # Check text against regexps + lines = text.splitlines() + good = set() + bad = set() + for i, line in enumerate(lines): + if any(re.match(r, line) for r in regexps): + good.add(i) + regexps = [r for r in regexps if not re.match(r, line)] + if any(re.match(r, line) for r in no): + bad.add(i) + + if not regexps and not bad: + return + + # We failed; construct an informative failure message + show = set() + for lineno in good.union(bad): + for offset in range(-2, 3): + show.add(lineno + offset) + if regexps: + show.update(n for n in range(len(lines) - 5, len(lines))) + + msg = [] + last = -1 + for lineno in sorted(show): + if 0 <= lineno < len(lines): + if lineno != last + 1: + msg.append("...") + last = lineno + msg.append("%s %s" % (color("red", "BAD ") if lineno in bad else + color("green", "GOOD") if lineno in good + else " ", + lines[lineno])) + if last != len(lines) - 1: + msg.append("...") + if bad: + msg.append("unexpected lines in output") + for r in regexps: + msg.append(color("red", "MISSING") + " '%s'" % r) + raise AssertionError("\n".join(msg)) + +################################################################## +# Utilities +# + +__all__ += ["make", "maybe_unlink", "reset_fs", "color", "random_str", "check_time", "check_answers"] + +MAKE_TIMESTAMP = 0 + +def pre_make(): + """Delay prior to running make to ensure file mtimes change.""" + while int(time.time()) == MAKE_TIMESTAMP: + time.sleep(0.1) + +def post_make(): + """Record the time after make completes so that the next run of + make can be delayed if needed.""" + global MAKE_TIMESTAMP + MAKE_TIMESTAMP = int(time.time()) + +def make(*target): + pre_make() + if Popen(("make",) + target).wait(): + sys.exit(1) + post_make() + +def show_command(cmd): + from pipes import quote + print("\n$", " ".join(map(quote, cmd))) + +def maybe_unlink(*paths): + for path in paths: + try: + os.unlink(path) + except EnvironmentError as e: + if e.errno != errno.ENOENT: + raise + +COLORS = {"default": "\033[0m", "red": "\033[31m", "green": "\033[32m"} + +def color(name, text): + if options.color == "always" or (options.color == "auto" and os.isatty(1)): + return COLORS[name] + text + COLORS["default"] + return text + +def reset_fs(): + if os.path.exists("obj/fs/clean-fs.img"): + shutil.copyfile("obj/fs/clean-fs.img", "obj/fs/fs.img") + +def random_str(n=8): + letters = string.ascii_letters + string.digits + return ''.join(random.choice(letters) for _ in range(n)) + +def check_time(): + try: + print("") + with open('time.txt') as f: + d = f.read().strip() + if not re.match(r'^\d+$', d): + raise AssertionError('time.txt does not contain a single integer (number of hours spent on the lab)') + except IOError: + raise AssertionError('Cannot read time.txt') + +def check_answers(file, n=10): + try: + print("") + with open(file) as f: + d = f.read().strip() + if len(d) < n: + raise AssertionError('%s does not seem to contain enough text' % file) + except IOError: + raise AssertionError('Cannot read %s' % file) + + +################################################################## +# Controllers +# + +__all__ += ["QEMU", "GDBClient"] + +class QEMU(object): + _GDBPORT = None + + def __init__(self, *make_args): + # Check that QEMU is not currently running + try: + GDBClient(self.get_gdb_port(), timeout=0).close() + except socket.error: + pass + else: + print("""\ +GDB stub found on port %d. +QEMU appears to already be running. Please exit it if possible or use +'killall qemu' or 'killall qemu.real'.""" % self.get_gdb_port(), file=sys.stderr) + sys.exit(1) + + if options.verbose: + show_command(("make",) + make_args) + cmd = ("make", "-s", "--no-print-directory") + make_args + self.proc = Popen(cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + stdin=subprocess.PIPE) + # Accumulated output as a string + self.output = "" + # Accumulated output as a bytearray + self.outbytes = bytearray() + self.on_output = [] + + @staticmethod + def get_gdb_port(): + if QEMU._GDBPORT is None: + p = Popen(["make", "-s", "--no-print-directory", "print-gdbport"], + stdout=subprocess.PIPE) + (out, _) = p.communicate() + if p.returncode: + raise RuntimeError( + "Failed to get gdbport: make exited with %d" % + p.returncode) + QEMU._GDBPORT = int(out) + return QEMU._GDBPORT + + def fileno(self): + if self.proc: + return self.proc.stdout.fileno() + + def handle_read(self): + buf = os.read(self.proc.stdout.fileno(), 4096) + self.outbytes.extend(buf) + self.output = self.outbytes.decode("utf-8", "replace") + for callback in self.on_output: + callback(buf) + if buf == b"": + self.wait() + return + + def write(self, buf): + if isinstance(buf, str): + buf = buf.encode('utf-8') + self.proc.stdin.write(buf) + self.proc.stdin.flush() + + def wait(self): + if self.proc: + self.proc.wait() + self.proc = None + + def kill(self): + if self.proc: + self.proc.terminate() + +class GDBClient(object): + def __init__(self, port, timeout=15): + start = time.time() + while True: + self.sock = socket.socket() + try: + self.sock.settimeout(1) + self.sock.connect(("localhost", port)) + break + except socket.error: + if time.time() >= start + timeout: + raise + self.__buf = "" + + def fileno(self): + if self.sock: + return self.sock.fileno() + + def handle_read(self): + try: + data = self.sock.recv(4096).decode("ascii", "replace") + except socket.error: + data = "" + if data == "": + self.sock.close() + self.sock = None + return + self.__buf += data + + while True: + m = re.search(r"\$([^#]*)#[0-9a-zA-Z]{2}", self.__buf) + if not m: + break + pkt = m.group(1) + self.__buf = self.__buf[m.end():] + + if pkt.startswith("T05"): + # Breakpoint + raise TerminateTest + + def __send(self, cmd): + packet = "$%s#%02x" % (cmd, sum(map(ord, cmd)) % 256) + self.sock.sendall(packet.encode("ascii")) + + def __send_break(self): + self.sock.sendall(b"\x03") + + def close(self): + if self.sock: + self.sock.close() + self.sock = None + + def cont(self): + self.__send("c") + + def breakpoint(self, addr): + self.__send("Z1,%x,1" % addr) + + +################################################################## +# QEMU test runner +# + +__all__ += ["TerminateTest", "Runner"] + +class TerminateTest(Exception): + pass + +class Runner(): + def __init__(self, *default_monitors): + self.__default_monitors = default_monitors + + def run_qemu(self, *monitors, **kw): + """Run a QEMU-based test. monitors should functions that will + be called with this Runner instance once QEMU and GDB are + started. Typically, they should register callbacks that throw + TerminateTest when stop events occur. The target_base + argument gives the make target to run. The make_args argument + should be a list of additional arguments to pass to make. The + timeout argument bounds how long to run before returning.""" + + def run_qemu_kw(target_base="qemu", make_args=[], timeout=30): + return target_base, make_args, timeout + target_base, make_args, timeout = run_qemu_kw(**kw) + + # Start QEMU + pre_make() + self.qemu = QEMU(target_base + "-gdb", *make_args) + self.gdb = None + + try: + # Wait for QEMU to start or make to fail. This will set + # self.gdb if QEMU starts. + self.qemu.on_output = [self.__monitor_start] + self.__react([self.qemu], timeout=90) + self.qemu.on_output = [] + if self.gdb is None: + print("Failed to connect to QEMU; output:") + print(self.qemu.output) + sys.exit(1) + post_make() + + # QEMU and GDB are up + self.reactors = [self.qemu, self.gdb] + + # Start monitoring + for m in self.__default_monitors + monitors: + m(self) + + # Run and react + self.gdb.cont() + self.__react(self.reactors, timeout) + finally: + # Shutdown QEMU + try: + if self.gdb is None: + sys.exit(1) + self.qemu.kill() + self.__react(self.reactors, 5) + self.gdb.close() + self.qemu.wait() + except: + print("""\ +Failed to shutdown QEMU. You might need to 'killall qemu' or +'killall qemu.real'. +""") + raise + + def __monitor_start(self, output): + if b"\n" in output: + try: + self.gdb = GDBClient(self.qemu.get_gdb_port(), timeout=2) + raise TerminateTest + except socket.error: + pass + if not len(output): + raise TerminateTest + + def __react(self, reactors, timeout): + deadline = time.time() + timeout + try: + while True: + timeleft = deadline - time.time() + if timeleft < 0: + sys.stdout.write("Timeout! ") + sys.stdout.flush() + return + + rset = [r for r in reactors if r.fileno() is not None] + if not rset: + return + + rset, _, _ = select.select(rset, [], [], timeleft) + for reactor in rset: + reactor.handle_read() + except TerminateTest: + pass + + def user_test(self, binary, *monitors, **kw): + """Run a user test using the specified binary. Monitors and + keyword arguments are as for run_qemu. This runs on a disk + snapshot unless the keyword argument 'snapshot' is False.""" + + maybe_unlink("obj/kern/init.o", "obj/kern/kernel") + if kw.pop("snapshot", True): + kw.setdefault("make_args", []).append("QEMUEXTRA+=-snapshot") + self.run_qemu(target_base="run-%s" % binary, *monitors, **kw) + + def match(self, *args, **kwargs): + """Shortcut to call assert_lines_match on the most recent QEMU + output.""" + + assert_lines_match(self.qemu.output, *args, **kwargs) + +################################################################## +# Monitors +# + +__all__ += ["save", "stop_breakpoint", "call_on_line", "stop_on_line", "shell_script"] + +def save(path): + """Return a monitor that writes QEMU's output to path. If the + test fails, copy the output to path.test-name.""" + + def setup_save(runner): + f.seek(0) + f.truncate() + runner.qemu.on_output.append(f.write) + get_current_test().on_finish.append(save_on_finish) + + def save_on_finish(fail): + f.flush() + save_path = path + "." + get_current_test().__name__[5:] + if fail: + shutil.copyfile(path, save_path) + print(" QEMU output saved to %s" % save_path) + elif os.path.exists(save_path): + os.unlink(save_path) + print(" (Old %s failure log removed)" % save_path) + + f = open(path, "wb") + return setup_save + +def stop_breakpoint(addr): + """Returns a monitor that stops when addr is reached. addr may be + a number or the name of a symbol.""" + + def setup_breakpoint(runner): + if isinstance(addr, str): + addrs = [int(sym[:16], 16) for sym in open("kernel/kernel.sym") + if sym[17:].strip() == addr] + assert len(addrs), "Symbol %s not found" % addr + runner.gdb.breakpoint(addrs[0]) + else: + runner.gdb.breakpoint(addr) + return setup_breakpoint + +def call_on_line(regexp, callback): + """Returns a monitor that calls 'callback' when QEMU prints a line + matching 'regexp'.""" + + def setup_call_on_line(runner): + buf = bytearray() + def handle_output(output): + buf.extend(output) + while b"\n" in buf: + line, buf[:] = buf.split(b"\n", 1) + line = line.decode("utf-8", "replace") + if re.match(regexp, line): + callback(line) + runner.qemu.on_output.append(handle_output) + return setup_call_on_line + +def stop_on_line(regexp): + """Returns a monitor that stops when QEMU prints a line matching + 'regexp'.""" + + def stop(line): + raise TerminateTest + return call_on_line(regexp, stop) + +def shell_script(script, terminate_match=None): + """Returns a monitor that plays the script, and stops when the script is + done executing.""" + + def setup_call_on_line(runner): + class context: + n = 0 + buf = bytearray() + def handle_output(output): + context.buf.extend(output) + if terminate_match is not None: + if re.match(terminate_match, context.buf.decode('utf-8', 'replace')): + raise TerminateTest + if b'$ ' in context.buf: + context.buf = bytearray() + if context.n < len(script): + runner.qemu.write(script[context.n]) + runner.qemu.write('\n') + context.n += 1 + else: + if terminate_match is None: + raise TerminateTest + runner.qemu.on_output.append(handle_output) + return setup_call_on_line diff --git a/kernel/defs.h b/kernel/defs.h index a3c962b..76de365 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -8,7 +8,7 @@ struct spinlock; struct sleeplock; struct stat; struct superblock; - +struct sysinfo; // bio.c void binit(void); struct buf* bread(uint, uint); @@ -63,6 +63,7 @@ void ramdiskrw(struct buf*); void* kalloc(void); void kfree(void *); void kinit(void); +uint64 getfreemem(); // log.c void initlog(int, struct superblock*); @@ -106,6 +107,8 @@ 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); +uint64 getnproc(); +int sysinfo(uint64 addr); // swtch.S void swtch(struct context*, struct context*); diff --git a/kernel/kalloc.c b/kernel/kalloc.c index 0699e7e..5679157 100644 --- a/kernel/kalloc.c +++ b/kernel/kalloc.c @@ -80,3 +80,15 @@ kalloc(void) memset((char*)r, 5, PGSIZE); // fill with junk return (void*)r; } + +uint64 +getfreemem(){ + uint64 freemem = 0; + struct run *r; + acquire(&kmem.lock); + for(r = kmem.freelist; r ;r = r->next){ + freemem+=PGSIZE; + } + release(&kmem.lock); + return freemem; +} diff --git a/kernel/proc.c b/kernel/proc.c index 58a8a0b..02c1d93 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -146,6 +146,8 @@ allocproc(void) p->context.ra = (uint64)forkret; p->context.sp = p->kstack + PGSIZE; + p->mask = 0; + return p; } @@ -322,6 +324,10 @@ fork(void) np->state = RUNNABLE; release(&np->lock); + acquire(&np->lock); + np->mask = p->mask; + release(&np->lock); + return pid; } @@ -686,3 +692,31 @@ procdump(void) printf("\n"); } } + +uint64 +getnproc(){ + uint64 nproc = 0; + int i; + for(i = 0; i < NPROC; i++){ + acquire(&proc[i].lock); + if(proc[i].state != UNUSED){ + nproc++; + } + release(&proc[i].lock); + } + return nproc; +} + +int +sysinfo( uint64 addr){ + struct sysinfo sf; + struct proc *p = myproc(); + sf.nproc = getnproc(); + sf.freemem = getfreemem(); + int result; + result = copyout(p->pagetable, addr, (char*)&sf, sizeof(sf)); + if(result < 0){ + return -1; + } + return 0; +} diff --git a/kernel/proc.h b/kernel/proc.h index d021857..a864913 100644 --- a/kernel/proc.h +++ b/kernel/proc.h @@ -20,10 +20,10 @@ struct context { // Per-CPU state. struct cpu { - struct proc *proc; // The process running on this cpu, or null. - struct context context; // swtch() here to enter scheduler(). - int noff; // Depth of push_off() nesting. - int intena; // Were interrupts enabled before push_off()? + struct proc *proc; // The process running on this cpu, or null. + struct context context; // swtch() here to enter scheduler(). + int noff; // Depth of push_off() nesting. + int intena; // Were interrupts enabled before push_off()? }; extern struct cpu cpus[NCPU]; @@ -86,14 +86,14 @@ struct proc { struct spinlock lock; // p->lock must be held when using these: - enum procstate state; // Process state - void *chan; // If non-zero, sleeping on chan - int killed; // If non-zero, have been killed - int xstate; // Exit status to be returned to parent's wait - int pid; // Process ID + enum procstate state; // Process state + void *chan; // If non-zero, sleeping on chan + int killed; // If non-zero, have been killed + int xstate; // Exit status to be returned to parent's wait + int pid; // Process ID // wait_lock must be held when using this: - struct proc *parent; // Parent process + struct proc *parent; // Parent process // these are private to the process, so p->lock need not be held. uint64 kstack; // Virtual address of kernel stack @@ -104,4 +104,10 @@ struct proc { struct file *ofile[NOFILE]; // Open files struct inode *cwd; // Current directory char name[16]; // Process name (debugging) + int mask; // trace mask in syscall lab +}; + +struct sysinfo { + uint64 freemem; // the number of bytes free memory + uint64 nproc; // the number of processes whose state is not UNUSED }; diff --git a/kernel/syscall.c b/kernel/syscall.c index ed65409..ef99a36 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -101,6 +101,8 @@ extern uint64 sys_unlink(void); extern uint64 sys_link(void); extern uint64 sys_mkdir(void); extern uint64 sys_close(void); +extern uint64 sys_trace(void); +extern uint64 sys_sysinfo(void); // An array mapping syscall numbers from syscall.h // to the function that handles the system call. @@ -126,8 +128,13 @@ static uint64 (*syscalls[])(void) = { [SYS_link] sys_link, [SYS_mkdir] sys_mkdir, [SYS_close] sys_close, +[SYS_trace] sys_trace, +[SYS_sysinfo] sys_sysinfo, }; - +char *names[NELEM(syscalls)]={"fork", "exit", "wait", "pipe", "read", "kill", "exec", + "fstat", "chdir", "dup", "getpid", "sbrk", "sleep", + "uptime", "open", "write", "mknod", "unlink", "link", + "mkdir", "close", "trace", "sysinfo",}; void syscall(void) { @@ -139,9 +146,18 @@ syscall(void) // Use num to lookup the system call function for num, call it, // and store its return value in p->trapframe->a0 p->trapframe->a0 = syscalls[num](); + if(p->mask){ + int i ; + for(i = 1;i < NELEM(syscalls); i++){ + if((1 << i) & p->mask){ + printf("%d: syscall %s -> %d\n",p->pid,names[i-1],p->trapframe->a0); + } + } + } } else { printf("%d %s: unknown sys call %d\n", p->pid, p->name, num); p->trapframe->a0 = -1; } + } diff --git a/kernel/syscall.h b/kernel/syscall.h index bc5f356..0dfedc7 100644 --- a/kernel/syscall.h +++ b/kernel/syscall.h @@ -20,3 +20,5 @@ #define SYS_link 19 #define SYS_mkdir 20 #define SYS_close 21 +#define SYS_trace 22 +#define SYS_sysinfo 23 diff --git a/kernel/sysinfo.h b/kernel/sysinfo.h new file mode 100644 index 0000000..fb878e6 --- /dev/null +++ b/kernel/sysinfo.h @@ -0,0 +1,4 @@ +struct sysinfo { + uint64 freemem; // amount of free memory (bytes) + uint64 nproc; // number of process +}; diff --git a/kernel/sysproc.c b/kernel/sysproc.c index 3b4d5bd..ff61878 100644 --- a/kernel/sysproc.c +++ b/kernel/sysproc.c @@ -91,3 +91,29 @@ sys_uptime(void) release(&tickslock); return xticks; } + +uint64 +sys_trace(void) +{ + int getmask; + struct proc *mp = myproc(); + + argint(0,&getmask); + if(getmask < 0) + return -1; + mp->mask = getmask; + return 0; +} + +uint64 +sys_sysinfo(void){ + uint64 p; + argaddr(0,&p); + struct sysinfo sf; + sf.freemem = getfreemem(); + sf.nproc = getnproc(); + if(copyout(myproc()->pagetable,p, (char*)&sf, sizeof(sf)) < 0){ + return -1; + } + return 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/user.h b/user/user.h index 4d398d5..1645956 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,8 @@ int getpid(void); char* sbrk(int); int sleep(int); int uptime(void); +int trace(int); +int sysinfo(struct sysinfo *); // ulib.c int stat(const char*, struct stat*); diff --git a/user/usys.pl b/user/usys.pl index 01e426e..bc109fd 100755 --- a/user/usys.pl +++ b/user/usys.pl @@ -36,3 +36,5 @@ sub entry { entry("sbrk"); entry("sleep"); entry("uptime"); +entry("trace"); +entry("sysinfo");