29 Commits
util ... cow

Author SHA1 Message Date
c8bae855c5 cow lab finished 2025-07-03 10:28:51 +08:00
66657d1ca0 cowtest fixed and try to finish usertests 2025-07-03 10:13:07 +08:00
bc8921a77f cowlab bug fixed 2025-07-01 10:52:21 +08:00
c6fa25504f cow lab initialized 2025-06-28 09:57:36 +08:00
7c42fbed17 trapslab finished 2025-06-23 19:08:25 +08:00
70ee668b9b comment added 2025-06-23 11:18:49 +08:00
c7c962ffef alarm task finished 2025-06-18 16:02:24 +08:00
4c08583743 backtrace task finished 2025-06-14 17:09:29 +08:00
b63d0c9147 answers-traps.txt added 2025-06-12 11:43:43 +08:00
028cf61d61 trapslab initialized 2025-06-12 10:45:04 +08:00
2a8fad821b usertest patched 2025-06-03 10:22:56 +08:00
ccc7f1ac12 pgtbl lab finished 2025-06-03 08:51:07 +08:00
7b2491c658 usertests and optional finished 2025-05-29 21:10:27 +08:00
e12b8c1d32 print_kpgtbl bug fixed 2025-05-29 20:26:55 +08:00
19e38dc598 task5 finished 2025-05-29 20:01:24 +08:00
b4bdc3e1db prepare for next 2025-05-29 20:00:24 +08:00
8fb0212778 task4 finished 2025-05-29 11:15:51 +08:00
f0aaffb0b6 task3 finished 2025-05-27 17:11:31 +08:00
bd21012f73 task2 finished 2025-05-27 15:59:57 +08:00
5292fdc6ac gcc-15 bug fixed 2025-05-23 21:47:16 +08:00
38997cbef6 pagetable lab initialized 2025-05-06 11:20:36 +08:00
0e751d690f optinal finished 2025-03-26 20:17:38 +08:00
2001e8e478 optinal load_avg to fix 2025-03-26 09:32:27 +08:00
e66ab82e63 syscall optional to finish 2025-03-25 19:18:29 +08:00
992f76ca30 syscall lab finished 2025-03-25 11:36:21 +08:00
a087b429df syscall trace finished 2025-03-25 10:35:06 +08:00
d92eea9e49 syscall lab need to finish 2025-03-25 01:13:50 +08:00
e33ff43dd6 syscall lab start 2025-03-08 11:25:52 +08:00
07fc8a52bd syscall branch 2025-03-04 11:23:18 +08:00
47 changed files with 1392 additions and 1806 deletions

2
.gitignore vendored
View File

@ -24,3 +24,5 @@ ph
barrier barrier
/lab-*.json /lab-*.json
.DS_Store .DS_Store
compile_commands.json

5
.lldbinit Normal file
View File

@ -0,0 +1,5 @@
settings set target.default-arch riscv64
platform select remote-gdb-server
process connect connect://127.0.0.1:26000
target create kernel/kernel
settings set stop-disassembly-display always

View File

@ -1,6 +1,6 @@
The xv6 software is: The xv6 software is:
Copyright (c) 2006-2019 Frans Kaashoek, Robert Morris, Russ Cox, Copyright (c) 2006-2024 Frans Kaashoek, Robert Morris, Russ Cox,
Massachusetts Institute of Technology Massachusetts Institute of Technology
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining

View File

@ -44,7 +44,7 @@ OBJS_KCSAN += \
$K/kcsan.o $K/kcsan.o
endif endif
ifeq ($(LAB),$(filter $(LAB), lock)) ifeq ($(LAB),lock)
OBJS += \ OBJS += \
$K/stats.o\ $K/stats.o\
$K/sprintf.o $K/sprintf.o
@ -55,7 +55,6 @@ ifeq ($(LAB),net)
OBJS += \ OBJS += \
$K/e1000.o \ $K/e1000.o \
$K/net.o \ $K/net.o \
$K/sysnet.o \
$K/pci.o $K/pci.o
endif endif
@ -86,7 +85,7 @@ LD = $(TOOLPREFIX)ld
OBJCOPY = $(TOOLPREFIX)objcopy OBJCOPY = $(TOOLPREFIX)objcopy
OBJDUMP = $(TOOLPREFIX)objdump OBJDUMP = $(TOOLPREFIX)objdump
CFLAGS = -Wall -Werror -Ofast -fno-omit-frame-pointer -ggdb -gdwarf-2 CFLAGS = -Wall -Werror -O -fno-omit-frame-pointer -ggdb -gdwarf-2
ifdef LAB ifdef LAB
LABUPPER = $(shell echo $(LAB) | tr a-z A-Z) LABUPPER = $(shell echo $(LAB) | tr a-z A-Z)
@ -96,7 +95,14 @@ endif
CFLAGS += $(XCFLAGS) CFLAGS += $(XCFLAGS)
CFLAGS += -MD CFLAGS += -MD
CFLAGS += -mcmodel=medany CFLAGS += -mcmodel=medany
CFLAGS += -ffreestanding -fno-common -nostdlib -mno-relax # CFLAGS += -ffreestanding -fno-common -nostdlib -mno-relax
CFLAGS += -fno-common -nostdlib
CFLAGS += -fno-builtin-strncpy -fno-builtin-strncmp -fno-builtin-strlen -fno-builtin-memset
CFLAGS += -fno-builtin-memmove -fno-builtin-memcmp -fno-builtin-log -fno-builtin-bzero
CFLAGS += -fno-builtin-strchr -fno-builtin-exit -fno-builtin-malloc -fno-builtin-putc
CFLAGS += -fno-builtin-free
CFLAGS += -fno-builtin-memcpy -Wno-main
CFLAGS += -fno-builtin-printf -fno-builtin-fprintf -fno-builtin-vprintf
CFLAGS += -I. CFLAGS += -I.
CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector) CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)
@ -141,7 +147,7 @@ tags: $(OBJS) _init
ULIB = $U/ulib.o $U/usys.o $U/printf.o $U/umalloc.o ULIB = $U/ulib.o $U/usys.o $U/printf.o $U/umalloc.o
ifeq ($(LAB),$(filter $(LAB), lock)) ifeq ($(LAB),lock)
ULIB += $U/statistics.o ULIB += $U/statistics.o
endif endif
@ -188,16 +194,18 @@ UPROGS=\
$U/_grind\ $U/_grind\
$U/_wc\ $U/_wc\
$U/_zombie\ $U/_zombie\
$U/_sleep\
$U/_uptime\
$U/_pingpong\
$U/_primes\
$U/_find\
$U/_xargs\
ifeq ($(LAB),$(filter $(LAB), lock))
ifeq ($(LAB),syscall)
UPROGS += \
$U/_attack\
$U/_attacktest\
$U/_secret
endif
ifeq ($(LAB),lock)
UPROGS += \ UPROGS += \
$U/_stats $U/_stats
endif endif
@ -230,10 +238,10 @@ $U/_uthread: $U/uthread.o $U/uthread_switch.o $(ULIB)
$(OBJDUMP) -S $U/_uthread > $U/uthread.asm $(OBJDUMP) -S $U/_uthread > $U/uthread.asm
ph: notxv6/ph.c ph: notxv6/ph.c
gcc -o ph -g -Ofast $(XCFLAGS) notxv6/ph.c -pthread gcc -o ph -g -O2 $(XCFLAGS) notxv6/ph.c -pthread
barrier: notxv6/barrier.c barrier: notxv6/barrier.c
gcc -o barrier -g -Ofast $(XCFLAGS) notxv6/barrier.c -pthread gcc -o barrier -g -O2 $(XCFLAGS) notxv6/barrier.c -pthread
endif endif
ifeq ($(LAB),pgtbl) ifeq ($(LAB),pgtbl)
@ -256,7 +264,7 @@ endif
ifeq ($(LAB),net) ifeq ($(LAB),net)
UPROGS += \ UPROGS += \
$U/_nettests $U/_nettest
endif endif
UEXTRA= UEXTRA=
@ -271,13 +279,11 @@ fs.img: mkfs/mkfs README $(UEXTRA) $(UPROGS)
-include kernel/*.d user/*.d -include kernel/*.d user/*.d
clean: clean:
rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \ rm -rf *.tex *.dvi *.idx *.aux *.log *.ind *.ilg *.dSYM *.zip *.pcap \
*/*.o */*.d */*.asm */*.sym \ */*.o */*.d */*.asm */*.sym \
$U/initcode $U/initcode.out $K/kernel fs.img \ $U/initcode $U/initcode.out $U/usys.S $U/_* \
mkfs/mkfs .gdbinit \ $K/kernel \
$U/usys.S \ mkfs/mkfs fs.img .gdbinit __pycache__ xv6.out* \
$(UPROGS) \
*.zip \
ph barrier ph barrier
# try to generate a unique GDB port # try to generate a unique GDB port
@ -293,7 +299,8 @@ ifeq ($(LAB),fs)
CPUS := 1 CPUS := 1
endif endif
FWDPORT = $(shell expr `id -u` % 5000 + 25999) FWDPORT1 = $(shell expr `id -u` % 5000 + 25999)
FWDPORT2 = $(shell expr `id -u` % 5000 + 30999)
QEMUOPTS = -machine virt -bios none -kernel $K/kernel -m 128M -smp $(CPUS) -nographic QEMUOPTS = -machine virt -bios none -kernel $K/kernel -m 128M -smp $(CPUS) -nographic
QEMUOPTS += -global virtio-mmio.force-legacy=false QEMUOPTS += -global virtio-mmio.force-legacy=false
@ -301,7 +308,7 @@ QEMUOPTS += -drive file=fs.img,if=none,format=raw,id=x0
QEMUOPTS += -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 QEMUOPTS += -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0
ifeq ($(LAB),net) ifeq ($(LAB),net)
QEMUOPTS += -netdev user,id=net0,hostfwd=udp::$(FWDPORT)-:2000 -object filter-dump,id=net0,netdev=net0,file=packets.pcap QEMUOPTS += -netdev user,id=net0,hostfwd=udp::$(FWDPORT1)-:2000,hostfwd=udp::$(FWDPORT2)-:2001 -object filter-dump,id=net0,netdev=net0,file=packets.pcap
QEMUOPTS += -device e1000,netdev=net0,bus=pcie.0 QEMUOPTS += -device e1000,netdev=net0,bus=pcie.0
endif endif
@ -319,11 +326,6 @@ ifeq ($(LAB),net)
# try to generate a unique port for the echo server # try to generate a unique port for the echo server
SERVERPORT = $(shell expr `id -u` % 5000 + 25099) SERVERPORT = $(shell expr `id -u` % 5000 + 25099)
server:
python3 server.py $(SERVERPORT)
ping:
python3 ping.py $(FWDPORT)
endif endif
## ##
@ -341,9 +343,7 @@ grade:
@echo $(MAKE) clean @echo $(MAKE) clean
@$(MAKE) clean || \ @$(MAKE) clean || \
(echo "'make clean' failed. HINT: Do you have another running instance of xv6?" && exit 1) (echo "'make clean' failed. HINT: Do you have another running instance of xv6?" && exit 1)
# ./grade-lab-$(LAB) $(GRADEFLAGS) python3.12 ./grade-lab-$(LAB) $(GRADEFLAGS)
python grade-lab-$(LAB)
## ##
## FOR submissions ## FOR submissions

35
README
View File

@ -14,25 +14,22 @@ locking), Cliff Frey (MP), Xiao Yu (MP), Nickolai Zeldovich, and Austin
Clements. Clements.
We are also grateful for the bug reports and patches contributed by We are also grateful for the bug reports and patches contributed by
Takahiro Aoyagi, Silas Boyd-Wickizer, Anton Burtsev, carlclone, Ian Takahiro Aoyagi, Marcelo Arroyo, Silas Boyd-Wickizer, Anton Burtsev,
Chen, Dan Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi, carlclone, Ian Chen, Dan Cross, Cody Cutler, Mike CAT, Tej Chajed,
eyalz800, Nelson Elhage, Saar Ettinger, Alice Ferrazzi, Nathaniel Asami Doi,Wenyang Duan, eyalz800, Nelson Elhage, Saar Ettinger, Alice
Filardo, flespark, Peter Froehlich, Yakir Goaron, Shivam Handa, Matt Ferrazzi, Nathaniel Filardo, flespark, Peter Froehlich, Yakir Goaron,
Harvey, Bryan Henry, jaichenhengjie, Jim Huang, Matúš Jókay, John Shivam Handa, Matt Harvey, Bryan Henry, jaichenhengjie, Jim Huang,
Jolly, Alexander Kapshuk, Anders Kaseorg, kehao95, Wolfgang Keller, Matúš Jókay, John Jolly, Alexander Kapshuk, Anders Kaseorg, kehao95,
Jungwoo Kim, Jonathan Kimmitt, Eddie Kohler, Vadim Kolontsov, Austin Wolfgang Keller, Jungwoo Kim, Jonathan Kimmitt, Eddie Kohler, Vadim
Liew, l0stman, Pavan Maddamsetti, Imbar Marinescu, Yandong Mao, Matan Kolontsov, Austin Liew, l0stman, Pavan Maddamsetti, Imbar Marinescu,
Shabtay, Hitoshi Mitake, Carmi Merimovich, Mark Morrissey, mtasm, Joel Yandong Mao, Matan Shabtay, Hitoshi Mitake, Carmi Merimovich, Mark
Nider, Hayato Ohhashi, OptimisticSide, Harry Porter, Greg Price, Jude Morrissey, mtasm, Joel Nider, Hayato Ohhashi, OptimisticSide,
Rich, segfault, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya phosphagos, Harry Porter, Greg Price, RayAndrew, Jude Rich, segfault,
Shigemitsu, Cam Tenny, tyfkda, Warren Toomey, Stephen Tu, Rafael Ubal, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya Shigemitsu, snoire,
Amane Uehara, Pablo Ventura, Xi Wang, WaheedHafez, Keiichi Watanabe, Taojie, Cam Tenny, tyfkda, Warren Toomey, Stephen Tu, Alissa Tung,
Nicolas Wolovick, wxdao, Grant Wu, Jindong Zhang, Icenowy Zheng, Rafael Ubal, Amane Uehara, Pablo Ventura, Xi Wang, WaheedHafez,
ZhUyU1997, and Zou Chang Wei. Keiichi Watanabe, Lucas Wolf, Nicolas Wolovick, wxdao, Grant Wu, x653,
Jindong Zhang, Icenowy Zheng, ZhUyU1997, and Zou Chang Wei.
The code in the files that constitute xv6 is
Copyright 2006-2022 Frans Kaashoek, Robert Morris, and Russ Cox.
ERROR REPORTS ERROR REPORTS

46
README.md Normal file
View File

@ -0,0 +1,46 @@
xv6 is a re-implementation of Dennis Ritchie's and Ken Thompson's Unix
Version 6 (v6). xv6 loosely follows the structure and style of v6,
but is implemented for a modern RISC-V multiprocessor using ANSI C.
ACKNOWLEDGMENTS
xv6 is inspired by John Lions's Commentary on UNIX 6th Edition (Peer
to Peer Communications; ISBN: 1-57398-013-7; 1st edition (June 14,
2000)). See also https://pdos.csail.mit.edu/6.1810/, which provides
pointers to on-line resources for v6.
The following people have made contributions: Russ Cox (context switching,
locking), Cliff Frey (MP), Xiao Yu (MP), Nickolai Zeldovich, and Austin
Clements.
We are also grateful for the bug reports and patches contributed by
Takahiro Aoyagi, Marcelo Arroyo, Silas Boyd-Wickizer, Anton Burtsev,
carlclone, Ian Chen, Dan Cross, Cody Cutler, Mike CAT, Tej Chajed,
Asami Doi,Wenyang Duan, eyalz800, Nelson Elhage, Saar Ettinger, Alice
Ferrazzi, Nathaniel Filardo, flespark, Peter Froehlich, Yakir Goaron,
Shivam Handa, Matt Harvey, Bryan Henry, jaichenhengjie, Jim Huang,
Matúš Jókay, John Jolly, Alexander Kapshuk, Anders Kaseorg, kehao95,
Wolfgang Keller, Jungwoo Kim, Jonathan Kimmitt, Eddie Kohler, Vadim
Kolontsov, Austin Liew, l0stman, Pavan Maddamsetti, Imbar Marinescu,
Yandong Mao, Matan Shabtay, Hitoshi Mitake, Carmi Merimovich, Mark
Morrissey, mtasm, Joel Nider, Hayato Ohhashi, OptimisticSide,
phosphagos, Harry Porter, Greg Price, RayAndrew, Jude Rich, segfault,
Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya Shigemitsu, snoire,
Taojie, Cam Tenny, tyfkda, Warren Toomey, Stephen Tu, Alissa Tung,
Rafael Ubal, Amane Uehara, Pablo Ventura, Xi Wang, WaheedHafez,
Keiichi Watanabe, Lucas Wolf, Nicolas Wolovick, wxdao, Grant Wu, x653,
Jindong Zhang, Icenowy Zheng, ZhUyU1997, and Zou Chang Wei.
ERROR REPORTS
Please send errors and suggestions to Frans Kaashoek and Robert Morris
(kaashoek,rtm@mit.edu). The main purpose of xv6 is as a teaching
operating system for MIT's 6.1810, so we are more interested in
simplifications and clarifications than new features.
BUILDING AND RUNNING XV6
You will need a RISC-V "newlib" tool chain from
https://github.com/riscv/riscv-gnu-toolchain, and qemu compiled for
riscv64-softmmu. Once they are installed, and in your shell
search path, you can run "make qemu".

View File

@ -1,702 +0,0 @@
[
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-c",
"-o",
"kernel/entry.o",
"kernel/entry.S"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/entry.S",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/entry.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/kalloc.o",
"kernel/kalloc.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/kalloc.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/kalloc.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/string.o",
"kernel/string.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/string.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/string.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/main.o",
"kernel/main.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/main.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/main.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/vm.o",
"kernel/vm.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/vm.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/vm.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/proc.o",
"kernel/proc.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/proc.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/proc.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-c",
"-o",
"kernel/swtch.o",
"kernel/swtch.S"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/swtch.S",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/swtch.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-c",
"-o",
"kernel/trampoline.o",
"kernel/trampoline.S"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/trampoline.S",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/trampoline.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/trap.o",
"kernel/trap.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/trap.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/trap.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/syscall.o",
"kernel/syscall.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/syscall.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/syscall.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/sysproc.o",
"kernel/sysproc.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/sysproc.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/sysproc.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/bio.o",
"kernel/bio.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/bio.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/bio.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/fs.o",
"kernel/fs.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/fs.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/fs.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/log.o",
"kernel/log.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/log.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/log.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/sleeplock.o",
"kernel/sleeplock.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/sleeplock.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/sleeplock.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/file.o",
"kernel/file.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/file.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/file.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/pipe.o",
"kernel/pipe.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/pipe.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/pipe.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/exec.o",
"kernel/exec.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/exec.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/exec.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/sysfile.o",
"kernel/sysfile.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/sysfile.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/sysfile.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-c",
"-o",
"kernel/kernelvec.o",
"kernel/kernelvec.S"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/kernelvec.S",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/kernelvec.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/plic.o",
"kernel/plic.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/plic.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/plic.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/virtio_disk.o",
"kernel/virtio_disk.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/virtio_disk.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/virtio_disk.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/start.o",
"kernel/start.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/start.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/start.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/console.o",
"kernel/console.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/console.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/console.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/printf.o",
"kernel/printf.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/printf.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/printf.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/uart.o",
"kernel/uart.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/uart.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/uart.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-mcmodel=medany",
"-ffreestanding",
"-fno-common",
"-mno-relax",
"-I.",
"-fno-stack-protector",
"-fno-pie",
"-c",
"-o",
"kernel/spinlock.o",
"kernel/spinlock.c"
],
"directory": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/spinlock.c",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/kernel/spinlock.o"
},
{
"arguments": [
"/usr/bin/riscv64-unknown-elf-gcc",
"-Wall",
"-Werror",
"-O2",
"-fno-omit-frame-pointer",
"-ggdb",
"-gdwarf-2",
"-DSOL_UTIL",
"-DLAB_UTIL",
"-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": "/run/media/gh0s7/Data/project/csail/xv6-labs",
"file": "/run/media/gh0s7/Data/project/csail/xv6-labs/user/initcode.S",
"output": "/run/media/gh0s7/Data/project/csail/xv6-labs/user/initcode.o"
}
]

View File

@ -1 +1 @@
LAB=util LAB=cow

159
cowlab.md Normal file
View File

@ -0,0 +1,159 @@
# xv6-labs: Copy-On-Write (COW) Fork 实验详细总结
## 实验目标
实现 xv6 操作系统的 COW写时复制fork
- fork 时父子进程共享物理页,只有在写入时才真正分配和复制物理页。
- 提高 fork+exec 的效率,减少不必要的内存拷贝。
## 主要实现步骤与详细代码
### 1. 物理页引用计数
**文件kernel/kalloc.c**
- 在文件顶部添加:
```c
#define NPAGE ((PHYSTOP - KERNBASE) / PGSIZE)
static int refcnt[NPAGE];
static inline int pa2idx(void *pa) { return ((uint64)pa - KERNBASE) / PGSIZE; }
```
- kalloc 分配新页时:
```c
if(r) {
memset((char*)r, 5, PGSIZE);
int idx = pa2idx((void*)r);
refcnt[idx] = 1;
}
```
- kfree 释放页时:
```c
int idx = pa2idx(pa);
acquire(&kmem.lock);
if(refcnt[idx] > 1) {
refcnt[idx]--;
release(&kmem.lock);
return;
}
refcnt[idx] = 0;
release(&kmem.lock);
memset(pa, 1, PGSIZE);
// ...加入空闲链表...
```
- 增加辅助函数:
```c
void incref(void *pa) { refcnt[pa2idx(pa)]++; }
void decref(void *pa) { refcnt[pa2idx(pa)]--; }
int getref(void *pa) { return refcnt[pa2idx(pa)]; }
```
### 2. PTE 标记 COW
**文件kernel/riscv.h**
```c
#define PTE_COW (1L << 8) // 使用RSW位标记COW
```
### 3. 修改 uvmcopy 实现 COW fork
**文件kernel/vm.c**
- 在文件头部声明:
```c
void incref(void *pa);
```
- 修改 uvmcopy
```c
int uvmcopy(pagetable_t old, pagetable_t new, uint64 sz) {
...
for(i = 0; i < sz; i += PGSIZE){
...
pa = PTE2PA(*pte);
flags = PTE_FLAGS(*pte);
if(flags & PTE_W) {
flags = (flags & ~PTE_W) | PTE_COW;
*pte = PA2PTE(pa) | flags;
}
if(mappages(new, i, PGSIZE, pa, flags) != 0){
uvmunmap(new, 0, i / PGSIZE, 0);
return -1;
}
incref((void*)pa);
}
return 0;
}
```
### 4. usertrap 处理写页错误
**文件kernel/trap.c**
- 在文件头部声明:
```c
void kfree(void *pa);
void *kalloc(void);
```
- 在 usertrap() 添加COW处理
```c
else if((scause == 15 || scause == 13)) { // store/load page fault
pte_t *pte = walk(p->pagetable, stval, 0);
if(pte && (*pte & PTE_V) && (*pte & PTE_U) && (*pte & PTE_COW)) {
uint64 pa = PTE2PA(*pte);
char *mem = kalloc();
if(mem == 0) {
setkilled(p);
} else {
memmove(mem, (void*)pa, PGSIZE);
*pte = PA2PTE(mem) | (PTE_FLAGS(*pte) & ~PTE_COW) | PTE_W;
kfree((void*)pa);
}
} else {
setkilled(p);
}
}
```
### 5. copyout 处理 COW
**文件kernel/vm.c**
- 修改 copyout
```c
if((*pte & PTE_W) == 0) {
if((*pte & PTE_COW) != 0) {
pa0 = PTE2PA(*pte);
char *mem = kalloc();
if(mem == 0)
return -1;
memmove(mem, (void*)pa0, PGSIZE);
*pte = PA2PTE(mem) | PTE_FLAGS(*pte) | PTE_W;
*pte &= ~PTE_COW;
kfree((void*)pa0);
} else {
return -1;
}
}
```
### 6. 释放页时引用计数
- uvmunmap 释放页时直接调用 kfreekfree 内部已处理引用计数。
### 7. walk() 边界健壮性
**文件kernel/vm.c**
- 修改 walk()
```c
if(va >= MAXVA)
return 0;
```
## 调试与测试
- 通过 `make qemu`,运行 `usertests``cowtest`,确保所有测试通过。
- 重点关注 `MAXVAplus``forktest``sbrkfail` 等边界和异常测试。
- 遇到 panic("walk") 问题,修正 walk() 返回 0。
- 通过多次 fork/exec、写入、回收等场景验证内存共享和释放的正确性。
## 常见问题与修复
- **panic("walk")**walk() 对非法地址应返回0而不是panic。
- **refcnt数组不能用end做基址**应以KERNBASE为基址保证数组大小编译期可知。
- **重复定义PTE宏**只保留riscv.h中的定义。
## 总结
- COW fork 显著提升了 fork+exec 的效率。
- 通过引用计数和 COW 标志,保证了内存的正确共享与释放。
- 通过边界检查和优雅失败,保证了系统健壮性。
本实验加深了对操作系统内存管理、页表机制和异常处理的理解。

59
grade-lab-cow Normal file
View File

@ -0,0 +1,59 @@
#!/usr/bin/env python3
import re
from gradelib import *
r = Runner(save("xv6.out"))
@test(0, "running cowtest")
def test_cowtest():
r.run_qemu(shell_script([
'cowtest'
]), timeout=300)
@test(30, "simple", parent=test_cowtest)
def test_simple():
matches = re.findall("^simple: ok$", r.qemu.output, re.M)
assert_equal(len(matches), 2, "Number of appearances of 'simple: ok'")
@test(30, "three", parent=test_cowtest)
def test_three():
matches = re.findall("^three: ok$", r.qemu.output, re.M)
assert_equal(len(matches), 3, "Number of appearances of 'three: ok'")
@test(20, "file", parent=test_cowtest)
def test_file():
r.match('^file: ok$')
@test(20, "forkfork", parent=test_cowtest)
def test_forkfork():
r.match('^forkfork: ok$')
@test(0, "usertests")
def test_usertests():
r.run_qemu(shell_script([
'usertests -q'
]), timeout=1000)
r.match('^ALL TESTS PASSED$')
def usertest_check(testcase, nextcase, output):
if not re.search(r'\ntest {}: [\s\S]*OK\ntest {}'.format(testcase, nextcase), output):
raise AssertionError('Failed ' + testcase)
@test(5, "usertests: copyin", parent=test_usertests)
def test_sbrkbugs():
usertest_check("copyin", "copyout", r.qemu.output)
@test(5, "usertests: copyout", parent=test_usertests)
def test_sbrkbugs():
usertest_check("copyout", "copyinstr1", r.qemu.output)
@test(19, "usertests: all tests", parent=test_usertests)
def test_usertests_all():
r.match('^ALL TESTS PASSED$')
@test(1, "time")
def test_time():
check_time()
run_tests()

View File

@ -1,86 +0,0 @@
#!/usr/bin/env python3
import re
from gradelib import *
r = Runner(save("xv6.out"))
@test(5, "sleep, no arguments")
def test_sleep_no_args():
r.run_qemu(shell_script([
'sleep'
]))
r.match(no=["exec .* failed", "$ sleep\n$"])
@test(5, "sleep, returns")
def test_sleep_no_args():
r.run_qemu(shell_script([
'sleep',
'echo OK'
]))
r.match('^OK$', no=["exec .* failed", "$ sleep\n$"])
@test(10, "sleep, makes syscall")
def test_sleep():
r.run_qemu(shell_script([
'sleep 10',
'echo FAIL'
]), stop_breakpoint('sys_sleep'))
r.match('\\$ sleep 10', no=['FAIL'])
@test(20, "pingpong")
def test_pingpong():
r.run_qemu(shell_script([
'pingpong', 'echo OK'
]))
r.match('^\\d+: received ping$', '^\\d+: received pong$', '^OK$')
@test(20, "primes")
def test_primes():
r.run_qemu(shell_script([
'primes', 'echo OK'
]))
args = ['prime %d' % i for i in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31]]
args.append('^OK$')
r.match(*args)
@test(10, "find, in current directory")
def test_find_curdir():
fn = random_str()
r.run_qemu(shell_script([
'echo > %s' % fn,
'find . %s' % fn
]))
r.match('./%s' % fn)
@test(10, "find, recursive")
def test_find_recursive():
needle = random_str()
dirs = [random_str() for _ in range(3)]
r.run_qemu(shell_script([
'mkdir %s' % dirs[0],
'echo > %s/%s' % (dirs[0], needle),
'mkdir %s/%s' % (dirs[0], dirs[1]),
'echo > %s/%s/%s' % (dirs[0], dirs[1], needle),
'mkdir %s' % dirs[2],
'echo > %s/%s' % (dirs[2], needle),
'find . %s' % needle
]))
r.match('./%s/%s' % (dirs[0], needle),
'./%s/%s/%s' % (dirs[0], dirs[1], needle),
'./%s/%s' % (dirs[2], needle))
@test(19, "xargs")
def test_xargs():
r.run_qemu(shell_script([
'sh < xargstest.sh',
'echo DONE',
], 'DONE'))
matches = re.findall("hello", r.qemu.output)
assert_equal(len(matches), 3, "Number of appearances of 'hello'")
@test(1, "time")
def test_time():
check_time()
run_tests()

View File

@ -77,7 +77,7 @@ int piperead(struct pipe *, uint64, int);
int pipewrite(struct pipe*, uint64, int); int pipewrite(struct pipe*, uint64, int);
// printf.c // printf.c
void printf(char *, ...); int printf(char*, ...) __attribute__ ((format (printf, 1, 2)));
void panic(char*) __attribute__((noreturn)); void panic(char*) __attribute__((noreturn));
void printfinit(void); void printfinit(void);

View File

@ -75,17 +75,17 @@ exec(char *path, char **argv)
p = myproc(); p = myproc();
uint64 oldsz = p->sz; uint64 oldsz = p->sz;
// Allocate two pages at the next page boundary. // Allocate some pages at the next page boundary.
// Make the first inaccessible as a stack guard. // Make the first inaccessible as a stack guard.
// Use the second as the user stack. // Use the rest as the user stack.
sz = PGROUNDUP(sz); sz = PGROUNDUP(sz);
uint64 sz1; uint64 sz1;
if((sz1 = uvmalloc(pagetable, sz, sz + 2*PGSIZE, PTE_W)) == 0) if((sz1 = uvmalloc(pagetable, sz, sz + (USERSTACK+1)*PGSIZE, PTE_W)) == 0)
goto bad; goto bad;
sz = sz1; sz = sz1;
uvmclear(pagetable, sz-2*PGSIZE); uvmclear(pagetable, sz-(USERSTACK+1)*PGSIZE);
sp = sz; sp = sz;
stackbase = sp - PGSIZE; stackbase = sp - USERSTACK*PGSIZE;
// Push argument strings, prepare rest of stack in ustack. // Push argument strings, prepare rest of stack in ustack.
for(argc = 0; argv[argc]; argc++) { for(argc = 0; argv[argc]; argc++) {

View File

@ -1,6 +1,6 @@
// On-disk file system format. // On-disk file system format.
// Both the kernel and user programs use this header file. // Both the kernel and user programs use this header file.
#include "kernel/types.h"
#define ROOTINO 1 // root i-number #define ROOTINO 1 // root i-number
#define BSIZE 1024 // block size #define BSIZE 1024 // block size
@ -57,3 +57,4 @@ struct dirent {
ushort inum; ushort inum;
char name[DIRSIZ]; char name[DIRSIZ];
}; };

View File

@ -9,6 +9,12 @@
#include "riscv.h" #include "riscv.h"
#include "defs.h" #include "defs.h"
#define NPAGE ((PHYSTOP - KERNBASE) / PGSIZE)
static int refcnt[NPAGE];
static inline int pa2idx(void *pa) {
return ((uint64)pa - KERNBASE) / PGSIZE;
}
void freerange(void *pa_start, void *pa_end); void freerange(void *pa_start, void *pa_end);
extern char end[]; // first address after kernel. extern char end[]; // first address after kernel.
@ -23,10 +29,25 @@ struct {
struct run *freelist; struct run *freelist;
} kmem; } kmem;
void incref(void *pa) {
int idx = pa2idx(pa);
refcnt[idx]++;
}
void decref(void *pa) {
int idx = pa2idx(pa);
refcnt[idx]--;
}
int getref(void *pa) {
int idx = pa2idx(pa);
return refcnt[idx];
}
void void
kinit() kinit()
{ {
initlock(&kmem.lock, "kmem"); initlock(&kmem.lock, "kmem");
for(int i = 0; i < NPAGE; i++)
refcnt[i] = 0;
freerange(end, (void*)PHYSTOP); freerange(end, (void*)PHYSTOP);
} }
@ -51,6 +72,16 @@ kfree(void *pa)
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP) if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
panic("kfree"); panic("kfree");
int idx = pa2idx(pa);
acquire(&kmem.lock);
if(refcnt[idx] > 1) {
refcnt[idx]--;
release(&kmem.lock);
return;
}
refcnt[idx] = 0;
release(&kmem.lock);
// Fill with junk to catch dangling refs. // Fill with junk to catch dangling refs.
memset(pa, 1, PGSIZE); memset(pa, 1, PGSIZE);
@ -76,7 +107,10 @@ kalloc(void)
kmem.freelist = r->next; kmem.freelist = r->next;
release(&kmem.lock); release(&kmem.lock);
if(r) if(r) {
memset((char*)r, 5, PGSIZE); // fill with junk memset((char*)r, 5, PGSIZE); // fill with junk
int idx = pa2idx((void*)r);
refcnt[idx] = 1;
}
return (void*)r; return (void*)r;
} }

View File

@ -3,7 +3,7 @@
# mode come here. # mode come here.
# #
# the current stack is a kernel stack. # the current stack is a kernel stack.
# push all registers, call kerneltrap(). # push registers, call kerneltrap().
# when kerneltrap() returns, restore registers, return. # when kerneltrap() returns, restore registers, return.
# #
.globl kerneltrap .globl kerneltrap
@ -13,7 +13,7 @@ kernelvec:
# make room to save registers. # make room to save registers.
addi sp, sp, -256 addi sp, sp, -256
# save the registers. # save caller-saved registers.
sd ra, 0(sp) sd ra, 0(sp)
sd sp, 8(sp) sd sp, 8(sp)
sd gp, 16(sp) sd gp, 16(sp)
@ -21,8 +21,6 @@ kernelvec:
sd t0, 32(sp) sd t0, 32(sp)
sd t1, 40(sp) sd t1, 40(sp)
sd t2, 48(sp) sd t2, 48(sp)
sd s0, 56(sp)
sd s1, 64(sp)
sd a0, 72(sp) sd a0, 72(sp)
sd a1, 80(sp) sd a1, 80(sp)
sd a2, 88(sp) sd a2, 88(sp)
@ -31,16 +29,6 @@ kernelvec:
sd a5, 112(sp) sd a5, 112(sp)
sd a6, 120(sp) sd a6, 120(sp)
sd a7, 128(sp) sd a7, 128(sp)
sd s2, 136(sp)
sd s3, 144(sp)
sd s4, 152(sp)
sd s5, 160(sp)
sd s6, 168(sp)
sd s7, 176(sp)
sd s8, 184(sp)
sd s9, 192(sp)
sd s10, 200(sp)
sd s11, 208(sp)
sd t3, 216(sp) sd t3, 216(sp)
sd t4, 224(sp) sd t4, 224(sp)
sd t5, 232(sp) sd t5, 232(sp)
@ -57,8 +45,6 @@ kernelvec:
ld t0, 32(sp) ld t0, 32(sp)
ld t1, 40(sp) ld t1, 40(sp)
ld t2, 48(sp) ld t2, 48(sp)
ld s0, 56(sp)
ld s1, 64(sp)
ld a0, 72(sp) ld a0, 72(sp)
ld a1, 80(sp) ld a1, 80(sp)
ld a2, 88(sp) ld a2, 88(sp)
@ -67,16 +53,6 @@ kernelvec:
ld a5, 112(sp) ld a5, 112(sp)
ld a6, 120(sp) ld a6, 120(sp)
ld a7, 128(sp) ld a7, 128(sp)
ld s2, 136(sp)
ld s3, 144(sp)
ld s4, 152(sp)
ld s5, 160(sp)
ld s6, 168(sp)
ld s7, 176(sp)
ld s8, 184(sp)
ld s9, 192(sp)
ld s10, 200(sp)
ld s11, 208(sp)
ld t3, 216(sp) ld t3, 216(sp)
ld t4, 224(sp) ld t4, 224(sp)
ld t5, 232(sp) ld t5, 232(sp)
@ -86,39 +62,3 @@ kernelvec:
# return to whatever we were doing in the kernel. # return to whatever we were doing in the kernel.
sret sret
#
# machine-mode timer interrupt.
#
.globl timervec
.align 4
timervec:
# start.c has set up the memory that mscratch points to:
# scratch[0,8,16] : register save area.
# scratch[24] : address of CLINT's MTIMECMP register.
# scratch[32] : desired interval between interrupts.
csrrw a0, mscratch, a0
sd a1, 0(a0)
sd a2, 8(a0)
sd a3, 16(a0)
# schedule the next timer interrupt
# by adding interval to mtimecmp.
ld a1, 24(a0) # CLINT_MTIMECMP(hart)
ld a2, 32(a0) # interval
ld a3, 0(a1)
add a3, a3, a2
sd a3, 0(a1)
# arrange for a supervisor software interrupt
# after this handler returns.
li a1, 2
csrw sip, a1
ld a3, 16(a0)
ld a2, 8(a0)
ld a1, 0(a0)
csrrw a0, mscratch, a0
mret

View File

@ -25,11 +25,6 @@
#define VIRTIO0 0x10001000 #define VIRTIO0 0x10001000
#define VIRTIO0_IRQ 1 #define VIRTIO0_IRQ 1
// core local interruptor (CLINT), which contains the timer.
#define CLINT 0x2000000L
#define CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 8*(hartid))
#define CLINT_MTIME (CLINT + 0xBFF8) // cycles since boot.
// qemu puts platform-level interrupt controller (PLIC) here. // qemu puts platform-level interrupt controller (PLIC) here.
#define PLIC 0x0c000000L #define PLIC 0x0c000000L
#define PLIC_PRIORITY (PLIC + 0x0) #define PLIC_PRIORITY (PLIC + 0x0)

View File

@ -11,3 +11,5 @@
#define NBUF (MAXOPBLOCKS*3) // size of disk block cache #define NBUF (MAXOPBLOCKS*3) // size of disk block cache
#define FSSIZE 2000 // size of file system in blocks #define FSSIZE 2000 // size of file system in blocks
#define MAXPATH 128 // maximum file path name #define MAXPATH 128 // maximum file path name
#define USERSTACK 1 // user stack pages

View File

@ -26,13 +26,13 @@ static struct {
static char digits[] = "0123456789abcdef"; static char digits[] = "0123456789abcdef";
static void static void
printint(int xx, int base, int sign) printint(long long xx, int base, int sign)
{ {
char buf[16]; char buf[16];
int i; int i;
uint x; unsigned long long x;
if(sign && (sign = xx < 0)) if(sign && (sign = (xx < 0)))
x = -xx; x = -xx;
else else
x = xx; x = xx;
@ -59,30 +59,71 @@ printptr(uint64 x)
consputc(digits[x >> (sizeof(uint64) * 8 - 4)]); consputc(digits[x >> (sizeof(uint64) * 8 - 4)]);
} }
// Print to the console. only understands %d, %x, %p, %s. // Print to the console.
void int
printf(char *fmt, ...) printf(char *fmt, ...)
{ {
va_list ap; va_list ap;
int i, c, locking; int i, cx, c0, c1, c2, locking;
char *s; char *s;
locking = pr.locking; locking = pr.locking;
if(locking) if(locking)
acquire(&pr.lock); acquire(&pr.lock);
if (fmt == 0)
panic("null fmt");
va_start(ap, fmt); va_start(ap, fmt);
for(i = 0; (c = fmt[i] & 0xff) != 0; i++){ for(i = 0; (cx = fmt[i] & 0xff) != 0; i++){
if(c != '%'){ if(cx != '%'){
consputc(c); consputc(cx);
continue; continue;
} }
c = fmt[++i] & 0xff; i++;
if(c == 0) c0 = fmt[i+0] & 0xff;
c1 = c2 = 0;
if(c0) c1 = fmt[i+1] & 0xff;
if(c1) c2 = fmt[i+2] & 0xff;
if(c0 == 'd'){
printint(va_arg(ap, int), 10, 1);
} else if(c0 == 'l' && c1 == 'd'){
printint(va_arg(ap, uint64), 10, 1);
i += 1;
} else if(c0 == 'l' && c1 == 'l' && c2 == 'd'){
printint(va_arg(ap, uint64), 10, 1);
i += 2;
} else if(c0 == 'u'){
printint(va_arg(ap, int), 10, 0);
} else if(c0 == 'l' && c1 == 'u'){
printint(va_arg(ap, uint64), 10, 0);
i += 1;
} else if(c0 == 'l' && c1 == 'l' && c2 == 'u'){
printint(va_arg(ap, uint64), 10, 0);
i += 2;
} else if(c0 == 'x'){
printint(va_arg(ap, int), 16, 0);
} else if(c0 == 'l' && c1 == 'x'){
printint(va_arg(ap, uint64), 16, 0);
i += 1;
} else if(c0 == 'l' && c1 == 'l' && c2 == 'x'){
printint(va_arg(ap, uint64), 16, 0);
i += 2;
} else if(c0 == 'p'){
printptr(va_arg(ap, uint64));
} else if(c0 == 's'){
if((s = va_arg(ap, char*)) == 0)
s = "(null)";
for(; *s; s++)
consputc(*s);
} else if(c0 == '%'){
consputc('%');
} else if(c0 == 0){
break; break;
} else {
// Print unknown % sequence to draw attention.
consputc('%');
consputc(c0);
}
#if 0
switch(c){ switch(c){
case 'd': case 'd':
printint(va_arg(ap, int), 10, 1); printint(va_arg(ap, int), 10, 1);
@ -108,11 +149,14 @@ printf(char *fmt, ...)
consputc(c); consputc(c);
break; break;
} }
#endif
} }
va_end(ap); va_end(ap);
if(locking) if(locking)
release(&pr.lock); release(&pr.lock);
return 0;
} }
void void
@ -120,8 +164,7 @@ panic(char *s)
{ {
pr.locking = 0; pr.locking = 0;
printf("panic: "); printf("panic: ");
printf(s); printf("%s\n", s);
printf("\n");
panicked = 1; // freeze uart output from other CPUs panicked = 1; // freeze uart output from other CPUs
for(;;) for(;;)
; ;

View File

@ -454,6 +454,7 @@ scheduler(void)
// processes are waiting. // processes are waiting.
intr_on(); intr_on();
int found = 0;
for(p = proc; p < &proc[NPROC]; p++) { for(p = proc; p < &proc[NPROC]; p++) {
acquire(&p->lock); acquire(&p->lock);
if(p->state == RUNNABLE) { if(p->state == RUNNABLE) {
@ -467,9 +468,15 @@ scheduler(void)
// Process is done running for now. // Process is done running for now.
// It should have changed its p->state before coming back. // It should have changed its p->state before coming back.
c->proc = 0; c->proc = 0;
found = 1;
} }
release(&p->lock); release(&p->lock);
} }
if(found == 0) {
// nothing to run; stop running on this core until an interrupt.
intr_on();
asm volatile("wfi");
}
} }
} }

View File

@ -1,45 +0,0 @@
//
// ramdisk that uses the disk image loaded by qemu -initrd fs.img
//
#include "types.h"
#include "riscv.h"
#include "defs.h"
#include "param.h"
#include "memlayout.h"
#include "spinlock.h"
#include "sleeplock.h"
#include "fs.h"
#include "buf.h"
void
ramdiskinit(void)
{
}
// If B_DIRTY is set, write buf to disk, clear B_DIRTY, set B_VALID.
// Else if B_VALID is not set, read buf from disk, set B_VALID.
void
ramdiskrw(struct buf *b)
{
if(!holdingsleep(&b->lock))
panic("ramdiskrw: buf not locked");
if((b->flags & (B_VALID|B_DIRTY)) == B_VALID)
panic("ramdiskrw: nothing to do");
if(b->blockno >= FSSIZE)
panic("ramdiskrw: blockno too big");
uint64 diskaddr = b->blockno * BSIZE;
char *addr = (char *)RAMDISK + diskaddr;
if(b->flags & B_DIRTY){
// write
memmove(addr, b->data, BSIZE);
b->flags &= ~B_DIRTY;
} else {
// read
memmove(b->data, addr, BSIZE);
b->flags |= B_VALID;
}
}

View File

@ -96,9 +96,7 @@ w_sie(uint64 x)
} }
// Machine-mode Interrupt Enable // Machine-mode Interrupt Enable
#define MIE_MEIE (1L << 11) // external #define MIE_STIE (1L << 5) // supervisor timer
#define MIE_MTIE (1L << 7) // timer
#define MIE_MSIE (1L << 3) // software
static inline uint64 static inline uint64
r_mie() r_mie()
{ {
@ -176,11 +174,38 @@ r_stvec()
return x; return x;
} }
// Machine-mode interrupt vector // Supervisor Timer Comparison Register
static inline void static inline uint64
w_mtvec(uint64 x) r_stimecmp()
{ {
asm volatile("csrw mtvec, %0" : : "r" (x)); uint64 x;
// asm volatile("csrr %0, stimecmp" : "=r" (x) );
asm volatile("csrr %0, 0x14d" : "=r" (x) );
return x;
}
static inline void
w_stimecmp(uint64 x)
{
// asm volatile("csrw stimecmp, %0" : : "r" (x));
asm volatile("csrw 0x14d, %0" : : "r" (x));
}
// Machine Environment Configuration Register
static inline uint64
r_menvcfg()
{
uint64 x;
// asm volatile("csrr %0, menvcfg" : "=r" (x) );
asm volatile("csrr %0, 0x30a" : "=r" (x) );
return x;
}
static inline void
w_menvcfg(uint64 x)
{
// asm volatile("csrw menvcfg, %0" : : "r" (x));
asm volatile("csrw 0x30a, %0" : : "r" (x));
} }
// Physical Memory Protection // Physical Memory Protection
@ -217,12 +242,6 @@ r_satp()
return x; return x;
} }
static inline void
w_mscratch(uint64 x)
{
asm volatile("csrw mscratch, %0" : : "r" (x));
}
// Supervisor Trap Cause // Supervisor Trap Cause
static inline uint64 static inline uint64
r_scause() r_scause()
@ -343,6 +362,7 @@ typedef uint64 *pagetable_t; // 512 PTEs
#define PTE_W (1L << 2) #define PTE_W (1L << 2)
#define PTE_X (1L << 3) #define PTE_X (1L << 3)
#define PTE_U (1L << 4) // user can access #define PTE_U (1L << 4) // user can access
#define PTE_COW (1L << 8) // 使用RSW位标记COW
// shift a physical address to the right place for a PTE. // shift a physical address to the right place for a PTE.
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10) #define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)

View File

@ -10,12 +10,6 @@ void timerinit();
// entry.S needs one stack per CPU. // entry.S needs one stack per CPU.
__attribute__ ((aligned (16))) char stack0[4096 * NCPU]; __attribute__ ((aligned (16))) char stack0[4096 * NCPU];
// a scratch area per CPU for machine-mode timer interrupts.
uint64 timer_scratch[NCPU][5];
// assembly code in kernelvec.S for machine-mode timer interrupt.
extern void timervec();
// entry.S jumps here in machine mode on stack0. // entry.S jumps here in machine mode on stack0.
void void
start() start()
@ -54,36 +48,19 @@ start()
asm volatile("mret"); asm volatile("mret");
} }
// arrange to receive timer interrupts. // ask each hart to generate timer interrupts.
// they will arrive in machine mode at
// at timervec in kernelvec.S,
// which turns them into software interrupts for
// devintr() in trap.c.
void void
timerinit() timerinit()
{ {
// each CPU has a separate source of timer interrupts. // enable supervisor-mode timer interrupts.
int id = r_mhartid(); w_mie(r_mie() | MIE_STIE);
// ask the CLINT for a timer interrupt. // enable the sstc extension (i.e. stimecmp).
int interval = 1000000; // cycles; about 1/10th second in qemu. w_menvcfg(r_menvcfg() | (1L << 63));
*(uint64*)CLINT_MTIMECMP(id) = *(uint64*)CLINT_MTIME + interval;
// prepare information in scratch[] for timervec. // allow supervisor to use stimecmp and time.
// scratch[0..2] : space for timervec to save registers. w_mcounteren(r_mcounteren() | 2);
// scratch[3] : address of CLINT MTIMECMP register.
// scratch[4] : desired interval (in cycles) between timer interrupts.
uint64 *scratch = &timer_scratch[id][0];
scratch[3] = CLINT_MTIMECMP(id);
scratch[4] = interval;
w_mscratch((uint64)scratch);
// set the machine-mode trap handler. // ask for the very first timer interrupt.
w_mtvec((uint64)timervec); w_stimecmp(r_time() + 1000000);
// enable machine-mode interrupts.
w_mstatus(r_mstatus() | MSTATUS_MIE);
// enable machine-mode timer interrupts.
w_mie(r_mie() | MIE_MTIE);
} }

View File

@ -1,7 +1,6 @@
#define T_DIR 1 // Directory #define T_DIR 1 // Directory
#define T_FILE 2 // File #define T_FILE 2 // File
#define T_DEVICE 3 // Device #define T_DEVICE 3 // Device
#include "types.h"
struct stat { struct stat {
int dev; // File system's disk device int dev; // File system's disk device

View File

@ -16,6 +16,9 @@ void kernelvec();
extern int devintr(); extern int devintr();
typedef uint64 pte_t;
pte_t *walk(pagetable_t pagetable, uint64 va, int alloc);
void void
trapinit(void) trapinit(void)
{ {
@ -50,7 +53,10 @@ usertrap(void)
// save user program counter. // save user program counter.
p->trapframe->epc = r_sepc(); p->trapframe->epc = r_sepc();
if(r_scause() == 8){ uint64 scause = r_scause();
uint64 stval = r_stval();
if(scause == 8){
// system call // system call
if(killed(p)) if(killed(p))
@ -67,9 +73,26 @@ usertrap(void)
syscall(); syscall();
} else if((which_dev = devintr()) != 0){ } else if((which_dev = devintr()) != 0){
// ok // ok
} else if((scause == 15 || scause == 13)) { // store/load page fault
pte_t *pte = walk(p->pagetable, stval, 0);
if(pte && (*pte & PTE_V) && (*pte & PTE_U) && (*pte & PTE_COW)) {
uint64 pa = PTE2PA(*pte);
char *mem = kalloc();
if(mem == 0) {
setkilled(p);
} else { } else {
printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid); memmove(mem, (void*)pa, PGSIZE);
printf(" sepc=%p stval=%p\n", r_sepc(), r_stval()); *pte = PA2PTE(mem) | (PTE_FLAGS(*pte) & ~PTE_COW) | PTE_W;
kfree((void*)pa);
}
} else {
printf("usertrap(): unexpected scause 0x%lx pid=%d\n", scause, p->pid);
printf(" sepc=0x%lx stval=0x%lx\n", r_sepc(), r_stval());
setkilled(p);
}
} else {
printf("usertrap(): unexpected scause 0x%lx pid=%d\n", r_scause(), p->pid);
printf(" sepc=0x%lx stval=0x%lx\n", r_sepc(), r_stval());
setkilled(p); setkilled(p);
} }
@ -145,13 +168,13 @@ kerneltrap()
panic("kerneltrap: interrupts enabled"); panic("kerneltrap: interrupts enabled");
if((which_dev = devintr()) == 0){ if((which_dev = devintr()) == 0){
printf("scause %p\n", scause); // interrupt or trap from an unknown source
printf("sepc=%p stval=%p\n", r_sepc(), r_stval()); printf("scause=0x%lx sepc=0x%lx stval=0x%lx\n", scause, r_sepc(), r_stval());
panic("kerneltrap"); panic("kerneltrap");
} }
// give up the CPU if this is a timer interrupt. // give up the CPU if this is a timer interrupt.
if(which_dev == 2 && myproc() != 0 && myproc()->state == RUNNING) if(which_dev == 2 && myproc() != 0)
yield(); yield();
// the yield() may have caused some traps to occur, // the yield() may have caused some traps to occur,
@ -163,12 +186,19 @@ kerneltrap()
void void
clockintr() clockintr()
{ {
if(cpuid() == 0){
acquire(&tickslock); acquire(&tickslock);
ticks++; ticks++;
wakeup(&ticks); wakeup(&ticks);
release(&tickslock); release(&tickslock);
} }
// ask for the next timer interrupt. this also clears
// the interrupt request. 1000000 is about a tenth
// of a second.
w_stimecmp(r_time() + 1000000);
}
// check if it's an external interrupt or software interrupt, // check if it's an external interrupt or software interrupt,
// and handle it. // and handle it.
// returns 2 if timer interrupt, // returns 2 if timer interrupt,
@ -179,8 +209,7 @@ devintr()
{ {
uint64 scause = r_scause(); uint64 scause = r_scause();
if((scause & 0x8000000000000000L) && if(scause == 0x8000000000000009L){
(scause & 0xff) == 9){
// this is a supervisor external interrupt, via PLIC. // this is a supervisor external interrupt, via PLIC.
// irq indicates which device interrupted. // irq indicates which device interrupted.
@ -201,21 +230,15 @@ devintr()
plic_complete(irq); plic_complete(irq);
return 1; return 1;
} else if(scause == 0x8000000000000001L){ } else if(scause == 0x8000000000000005L){
// software interrupt from a machine-mode timer interrupt, // timer interrupt.
// forwarded by timervec in kernelvec.S.
if(cpuid() == 0){
clockintr(); clockintr();
}
// acknowledge the software interrupt by clearing
// the SSIP bit in sip.
w_sip(r_sip() & ~2);
return 2; return 2;
} else { } else {
return 0; return 0;
} }
} }
void kfree(void *pa);
void *kalloc(void);

View File

@ -13,7 +13,7 @@
// the UART control registers are memory-mapped // the UART control registers are memory-mapped
// at address UART0. this macro returns the // at address UART0. this macro returns the
// address of one of the registers. // address of one of the registers.
#define Reg(reg) ((volatile unsigned char *)(UART0 + reg)) #define Reg(reg) ((volatile unsigned char *)(UART0 + (reg)))
// the UART control registers. // the UART control registers.
// some have different meanings for // some have different meanings for
@ -136,6 +136,7 @@ uartstart()
while(1){ while(1){
if(uart_tx_w == uart_tx_r){ if(uart_tx_w == uart_tx_r){
// transmit buffer is empty. // transmit buffer is empty.
ReadReg(ISR);
return; return;
} }

View File

@ -6,6 +6,10 @@
#include "defs.h" #include "defs.h"
#include "fs.h" #include "fs.h"
void incref(void *pa);
void kfree(void *pa);
void *kalloc(void);
/* /*
* the kernel's page table. * the kernel's page table.
*/ */
@ -31,7 +35,7 @@ kvmmake(void)
kvmmap(kpgtbl, VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W); kvmmap(kpgtbl, VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W);
// PLIC // PLIC
kvmmap(kpgtbl, PLIC, PLIC, 0x400000, PTE_R | PTE_W); kvmmap(kpgtbl, PLIC, PLIC, 0x4000000, PTE_R | PTE_W);
// map kernel text executable and read-only. // map kernel text executable and read-only.
kvmmap(kpgtbl, KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X); kvmmap(kpgtbl, KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X);
@ -86,7 +90,8 @@ pte_t *
walk(pagetable_t pagetable, uint64 va, int alloc) walk(pagetable_t pagetable, uint64 va, int alloc)
{ {
if(va >= MAXVA) if(va >= MAXVA)
panic("walk"); return 0;
// panic("walk");
for(int level = 2; level > 0; level--) { for(int level = 2; level > 0; level--) {
pte_t *pte = &pagetable[PX(level, va)]; pte_t *pte = &pagetable[PX(level, va)];
@ -315,7 +320,7 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
pte_t *pte; pte_t *pte;
uint64 pa, i; uint64 pa, i;
uint flags; uint flags;
char *mem; // char *mem;
for(i = 0; i < sz; i += PGSIZE){ for(i = 0; i < sz; i += PGSIZE){
if((pte = walk(old, i, 0)) == 0) if((pte = walk(old, i, 0)) == 0)
@ -324,19 +329,21 @@ uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
panic("uvmcopy: page not present"); panic("uvmcopy: page not present");
pa = PTE2PA(*pte); pa = PTE2PA(*pte);
flags = PTE_FLAGS(*pte); flags = PTE_FLAGS(*pte);
if((mem = kalloc()) == 0) // 如果是可写页去掉PTE_W设置PTE_COW
goto err; if(flags & PTE_W) {
memmove(mem, (char*)pa, PGSIZE); flags = (flags & ~PTE_W) | PTE_COW;
if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){ *pte = PA2PTE(pa) | flags;
kfree(mem);
goto err;
} }
// 子页表同样映射,权限同上
if(mappages(new, i, PGSIZE, pa, flags) != 0){
// kfree(mem); // 不再分配新页
uvmunmap(new, 0, i / PGSIZE, 0);
return -1;
}
// 增加物理页引用计数
incref((void*)pa);
} }
return 0; return 0;
err:
uvmunmap(new, 0, i / PGSIZE, 1);
return -1;
} }
// mark a PTE invalid for user access. // mark a PTE invalid for user access.
@ -366,9 +373,25 @@ copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
if(va0 >= MAXVA) if(va0 >= MAXVA)
return -1; return -1;
pte = walk(pagetable, va0, 0); pte = walk(pagetable, va0, 0);
if(pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0 || if(pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
(*pte & PTE_W) == 0)
return -1; return -1;
if((*pte & PTE_W) == 0) {
// COW处理
if((*pte & PTE_COW) != 0) {
pa0 = PTE2PA(*pte);
char *mem = kalloc();
if(mem == 0)
return -1;
memmove(mem, (void*)pa0, PGSIZE);
// 更新PTE为新物理页可写去掉COW
*pte = PA2PTE(mem) | PTE_FLAGS(*pte) | PTE_W;
*pte &= ~PTE_COW;
// 原物理页引用计数减一
kfree((void*)pa0);
} else {
return -1;
}
}
pa0 = PTE2PA(*pte); pa0 = PTE2PA(*pte);
n = PGSIZE - (dstva - va0); n = PGSIZE - (dstva - va0);
if(n > len) if(n > len)

View File

@ -20,7 +20,7 @@
// Disk layout: // Disk layout:
// [ boot block | sb block | log | inode blocks | free bit map | data blocks ] // [ boot block | sb block | log | inode blocks | free bit map | data blocks ]
int nbitmap = FSSIZE/(BSIZE*8) + 1; int nbitmap = FSSIZE/BPB + 1;
int ninodeblocks = NINODES / IPB + 1; int ninodeblocks = NINODES / IPB + 1;
int nlog = LOGSIZE; int nlog = LOGSIZE;
int nmeta; // Number of meta blocks (boot, sb, nlog, inode, bitmap) int nmeta; // Number of meta blocks (boot, sb, nlog, inode, bitmap)
@ -147,6 +147,8 @@ main(int argc, char *argv[])
if(shortname[0] == '_') if(shortname[0] == '_')
shortname += 1; shortname += 1;
assert(strlen(shortname) <= DIRSIZ);
inum = ialloc(T_FILE); inum = ialloc(T_FILE);
bzero(&de, sizeof(de)); bzero(&de, sizeof(de));
@ -238,7 +240,7 @@ balloc(int used)
int i; int i;
printf("balloc: first %d blocks have been allocated\n", used); printf("balloc: first %d blocks have been allocated\n", used);
assert(used < BSIZE*8); assert(used < BPB);
bzero(buf, BSIZE); bzero(buf, BSIZE);
for(i = 0; i < used; i++){ for(i = 0; i < used; i++){
buf[i/8] = buf[i/8] | (0x1 << (i%8)); buf[i/8] = buf[i/8] | (0x1 << (i%8));

View File

@ -1 +1 @@
5 9

View File

@ -1,11 +1,12 @@
#include "kernel/fcntl.h"
#include "kernel/stat.h"
#include "kernel/types.h" #include "kernel/types.h"
#include "kernel/fcntl.h"
#include "user/user.h" #include "user/user.h"
char buf[512]; char buf[512];
void cat(int fd) { void
cat(int fd)
{
int n; int n;
while((n = read(fd, buf, sizeof(buf))) > 0) { while((n = read(fd, buf, sizeof(buf))) > 0) {
@ -20,7 +21,9 @@ void cat(int fd) {
} }
} }
int main(int argc, char *argv[]) { int
main(int argc, char *argv[])
{
int fd, i; int fd, i;
if(argc <= 1){ if(argc <= 1){

240
user/cowtest.c Normal file
View File

@ -0,0 +1,240 @@
//
// tests for copy-on-write fork() assignment.
//
#include "kernel/types.h"
#include "kernel/memlayout.h"
#include "user/user.h"
// allocate more than half of physical memory,
// then fork. this will fail in the default
// kernel, which does not support copy-on-write.
void
simpletest()
{
uint64 phys_size = PHYSTOP - KERNBASE;
int sz = (phys_size / 3) * 2;
printf("simple: ");
char *p = sbrk(sz);
if(p == (char*)0xffffffffffffffffL){
printf("sbrk(%d) failed\n", sz);
exit(-1);
}
for(char *q = p; q < p + sz; q += 4096){
*(int*)q = getpid();
}
int pid = fork();
if(pid < 0){
printf("fork() failed\n");
exit(-1);
}
if(pid == 0)
exit(0);
wait(0);
if(sbrk(-sz) == (char*)0xffffffffffffffffL){
printf("sbrk(-%d) failed\n", sz);
exit(-1);
}
printf("ok\n");
}
// three processes all write COW memory.
// this causes more than half of physical memory
// to be allocated, so it also checks whether
// copied pages are freed.
void
threetest()
{
uint64 phys_size = PHYSTOP - KERNBASE;
int sz = phys_size / 4;
int pid1, pid2;
printf("three: ");
char *p = sbrk(sz);
if(p == (char*)0xffffffffffffffffL){
printf("sbrk(%d) failed\n", sz);
exit(-1);
}
pid1 = fork();
if(pid1 < 0){
printf("fork failed\n");
exit(-1);
}
if(pid1 == 0){
pid2 = fork();
if(pid2 < 0){
printf("fork failed");
exit(-1);
}
if(pid2 == 0){
for(char *q = p; q < p + (sz/5)*4; q += 4096){
*(int*)q = getpid();
}
for(char *q = p; q < p + (sz/5)*4; q += 4096){
if(*(int*)q != getpid()){
printf("wrong content\n");
exit(-1);
}
}
exit(-1);
}
for(char *q = p; q < p + (sz/2); q += 4096){
*(int*)q = 9999;
}
exit(0);
}
for(char *q = p; q < p + sz; q += 4096){
*(int*)q = getpid();
}
wait(0);
sleep(1);
for(char *q = p; q < p + sz; q += 4096){
if(*(int*)q != getpid()){
printf("wrong content\n");
exit(-1);
}
}
if(sbrk(-sz) == (char*)0xffffffffffffffffL){
printf("sbrk(-%d) failed\n", sz);
exit(-1);
}
printf("ok\n");
}
char junk1[4096];
int fds[2];
char junk2[4096];
char buf[4096];
char junk3[4096];
// test whether copyout() simulates COW faults.
void
filetest()
{
printf("file: ");
buf[0] = 99;
for(int i = 0; i < 4; i++){
if(pipe(fds) != 0){
printf("pipe() failed\n");
exit(-1);
}
int pid = fork();
if(pid < 0){
printf("fork failed\n");
exit(-1);
}
if(pid == 0){
sleep(1);
if(read(fds[0], buf, sizeof(i)) != sizeof(i)){
printf("error: read failed\n");
exit(1);
}
sleep(1);
int j = *(int*)buf;
if(j != i){
printf("error: read the wrong value\n");
exit(1);
}
exit(0);
}
if(write(fds[1], &i, sizeof(i)) != sizeof(i)){
printf("error: write failed\n");
exit(-1);
}
}
int xstatus = 0;
for(int i = 0; i < 4; i++) {
wait(&xstatus);
if(xstatus != 0) {
exit(1);
}
}
if(buf[0] != 99){
printf("error: child overwrote parent\n");
exit(1);
}
printf("ok\n");
}
//
// try to expose races in page reference counting.
//
void
forkforktest()
{
printf("forkfork: ");
int sz = 256 * 4096;
char *p = sbrk(sz);
memset(p, 27, sz);
int children = 3;
for(int iter = 0; iter < 100; iter++){
for(int nc = 0; nc < children; nc++){
if(fork() == 0){
sleep(2);
fork();
fork();
exit(0);
}
}
for(int nc = 0; nc < children; nc++){
int st;
wait(&st);
}
}
sleep(5);
for(int i = 0; i < sz; i += 4096){
if(p[i] != 27){
printf("error: parent's memory was modified!\n");
exit(1);
}
}
printf("ok\n");
}
int
main(int argc, char *argv[])
{
simpletest();
// check that the first simpletest() freed the physical memory.
simpletest();
threetest();
threetest();
threetest();
filetest();
forkforktest();
printf("ALL COW TESTS PASSED\n");
exit(0);
}

View File

@ -1,98 +0,0 @@
#include "kernel/fs.h"
#include "kernel/stat.h"
#include "kernel/types.h"
#include "user/user.h"
int match_pattern(const char *name, const char *pattern) {
const char *star = 0;
const char *name_ptr = name;
const char *pattern_ptr = pattern;
while (1) {
if (*pattern_ptr == '*') {
star = pattern_ptr++;
name_ptr = name;
continue;
}
if (!*name)
return (!*pattern_ptr || (star && !*++pattern_ptr));
if (*pattern_ptr == '?' || *pattern_ptr == *name) {
pattern_ptr++;
name++;
continue;
}
if (star) {
pattern_ptr = star + 1;
name = ++name_ptr;
continue;
}
return 0;
}
}
void find(char *path, char *pattern) {
char buf[512], *p;
int fd;
struct dirent de;
struct stat st;
if ((fd = open(path, 0)) < 0) {
fprintf(2, "find: cannot open %s\n", path);
return;
}
if (fstat(fd, &st) < 0) {
fprintf(2, "find: cannot stat %s\n", path);
close(fd);
return;
}
if (st.type != T_DIR) {
fprintf(2, "find: %s is not a directory\n", path);
close(fd);
return;
}
if (strlen(path) + 1 + DIRSIZ + 1 > sizeof buf) {
fprintf(2, "find: path too long\n");
close(fd);
return;
}
strcpy(buf, path);
p = buf + strlen(buf);
*p++ = '/';
while (read(fd, &de, sizeof(de)) == sizeof(de)) {
if (de.inum == 0 || !strcmp(de.name, ".") || !strcmp(de.name, ".."))
continue;
memmove(p, de.name, DIRSIZ);
p[DIRSIZ] = 0;
if (stat(buf, &st) < 0) {
fprintf(2, "find: cannot stat %s\n", buf);
continue;
}
if (st.type == T_DIR) {
find(buf, pattern);
} else if (st.type == T_FILE) {
if (match_pattern(de.name, pattern)) {
fprintf(1, "%s\n", buf);
}
}
}
close(fd);
}
int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(2, "Usage: find <path> <pattern>\n");
exit(1);
}
find(argv[1], argv[2]);
exit(0);
}

View File

@ -24,5 +24,5 @@ init:
# char *argv[] = { init, 0 }; # char *argv[] = { init, 0 };
.p2align 2 .p2align 2
argv: argv:
.long init .quad init
.long 0 .quad 0

View File

@ -1,10 +1,12 @@
#include "kernel/fcntl.h"
#include "kernel/fs.h"
#include "kernel/stat.h"
#include "kernel/types.h" #include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h" #include "user/user.h"
#include "kernel/fs.h"
#include "kernel/fcntl.h"
char *fmtname(char *path) { char*
fmtname(char *path)
{
static char buf[DIRSIZ+1]; static char buf[DIRSIZ+1];
char *p; char *p;
@ -21,7 +23,9 @@ char *fmtname(char *path) {
return buf; return buf;
} }
void ls(char *path) { void
ls(char *path)
{
char buf[512], *p; char buf[512], *p;
int fd; int fd;
struct dirent de; struct dirent de;
@ -41,7 +45,7 @@ void ls(char *path) {
switch(st.type){ switch(st.type){
case T_DEVICE: case T_DEVICE:
case T_FILE: case T_FILE:
printf("%s %d %d %l\n", fmtname(path), st.type, st.ino, st.size); printf("%s %d %d %d\n", fmtname(path), st.type, st.ino, (int) st.size);
break; break;
case T_DIR: case T_DIR:
@ -61,14 +65,16 @@ void ls(char *path) {
printf("ls: cannot stat %s\n", buf); printf("ls: cannot stat %s\n", buf);
continue; continue;
} }
printf("%s %d %d %d\n", fmtname(buf), st.type, st.ino, st.size); printf("%s %d %d %d\n", fmtname(buf), st.type, st.ino, (int) st.size);
} }
break; break;
} }
close(fd); close(fd);
} }
int main(int argc, char *argv[]) { int
main(int argc, char *argv[])
{
int i; int i;
if(argc < 2){ if(argc < 2){

View File

@ -1,21 +0,0 @@
#include "kernel/types.h"
#include "user/user.h"
int main(int argc, char *argv[]) {
int proc_f2s[2], proc_s2f[2];
char buffer[8];
pipe(proc_f2s);
pipe(proc_s2f);
if (fork() == 0) {
read(proc_s2f[0], buffer, 4);
printf("%d: received %s\n", getpid(), buffer);
write(proc_f2s[1], "pong", strlen("pong"));
} else {
write(proc_s2f[1], "ping", strlen("ping"));
read(proc_f2s[0], buffer, 4);
printf("%d: received %s\n", getpid(), buffer);
}
exit(0);
}

View File

@ -1,61 +0,0 @@
#include "kernel/types.h"
#include "user/user.h"
void redirect(int n, int pd[]) {
close(n);
dup(pd[n]);
close(pd[0]);
close(pd[1]);
}
void primes() {
int previous, next;
int fd[2];
while (read(0, &previous, sizeof(int))) {
printf("prime %d\n", previous);
if (pipe(fd) < 0) {
fprintf(2, "pipe failed\n");
exit(1);
}
if (fork() == 0) {
redirect(1, fd);
while (read(0, &next, sizeof(int))) {
if (next % previous != 0) {
write(1, &next, sizeof(int));
}
}
exit(0);
} else {
close(fd[1]);
redirect(0, fd);
}
}
}
int main(int argc, char *argv[]) {
int fd[2];
if (pipe(fd) < 0) {
fprintf(2, "pipe failed\n");
exit(1);
}
if (fork() == 0) {
redirect(1, fd);
for (int i = 2; i < 36; i++) {
write(1, &i, sizeof(int));
}
exit(0);
} else {
close(fd[1]);
redirect(0, fd);
primes();
}
exit(0);
}

View File

@ -1,14 +1,20 @@
#include "kernel/stat.h"
#include "kernel/types.h" #include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h" #include "user/user.h"
#include <stdarg.h> #include <stdarg.h>
static char digits[] = "0123456789ABCDEF"; static char digits[] = "0123456789ABCDEF";
static void putc(int fd, char c) { write(fd, &c, 1); } static void
putc(int fd, char c)
{
write(fd, &c, 1);
}
static void printint(int fd, int xx, int base, int sgn) { static void
printint(int fd, int xx, int base, int sgn)
{
char buf[16]; char buf[16];
int i, neg; int i, neg;
uint x; uint x;
@ -32,7 +38,8 @@ static void printint(int fd, int xx, int base, int sgn) {
putc(fd, buf[i]); putc(fd, buf[i]);
} }
static void printptr(int fd, uint64 x) { static void
printptr(int fd, uint64 x) {
int i; int i;
putc(fd, '0'); putc(fd, '0');
putc(fd, 'x'); putc(fd, 'x');
@ -41,20 +48,65 @@ static void printptr(int fd, uint64 x) {
} }
// Print to the given fd. Only understands %d, %x, %p, %s. // Print to the given fd. Only understands %d, %x, %p, %s.
void vprintf(int fd, const char *fmt, va_list ap) { void
vprintf(int fd, const char *fmt, va_list ap)
{
char *s; char *s;
int c, i, state; int c0, c1, c2, i, state;
state = 0; state = 0;
for(i = 0; fmt[i]; i++){ for(i = 0; fmt[i]; i++){
c = fmt[i] & 0xff; c0 = fmt[i] & 0xff;
if(state == 0){ if(state == 0){
if (c == '%') { if(c0 == '%'){
state = '%'; state = '%';
} else { } else {
putc(fd, c); putc(fd, c0);
} }
} else if(state == '%'){ } else if(state == '%'){
c1 = c2 = 0;
if(c0) c1 = fmt[i+1] & 0xff;
if(c1) c2 = fmt[i+2] & 0xff;
if(c0 == 'd'){
printint(fd, va_arg(ap, int), 10, 1);
} else if(c0 == 'l' && c1 == 'd'){
printint(fd, va_arg(ap, uint64), 10, 1);
i += 1;
} else if(c0 == 'l' && c1 == 'l' && c2 == 'd'){
printint(fd, va_arg(ap, uint64), 10, 1);
i += 2;
} else if(c0 == 'u'){
printint(fd, va_arg(ap, int), 10, 0);
} else if(c0 == 'l' && c1 == 'u'){
printint(fd, va_arg(ap, uint64), 10, 0);
i += 1;
} else if(c0 == 'l' && c1 == 'l' && c2 == 'u'){
printint(fd, va_arg(ap, uint64), 10, 0);
i += 2;
} else if(c0 == 'x'){
printint(fd, va_arg(ap, int), 16, 0);
} else if(c0 == 'l' && c1 == 'x'){
printint(fd, va_arg(ap, uint64), 16, 0);
i += 1;
} else if(c0 == 'l' && c1 == 'l' && c2 == 'x'){
printint(fd, va_arg(ap, uint64), 16, 0);
i += 2;
} else if(c0 == 'p'){
printptr(fd, va_arg(ap, uint64));
} else if(c0 == 's'){
if((s = va_arg(ap, char*)) == 0)
s = "(null)";
for(; *s; s++)
putc(fd, *s);
} else if(c0 == '%'){
putc(fd, '%');
} else {
// Unknown % sequence. Print it to draw attention.
putc(fd, '%');
putc(fd, c0);
}
#if 0
if(c == 'd'){ if(c == 'd'){
printint(fd, va_arg(ap, int), 10, 1); printint(fd, va_arg(ap, int), 10, 1);
} else if(c == 'l') { } else if(c == 'l') {
@ -80,19 +132,24 @@ void vprintf(int fd, const char *fmt, va_list ap) {
putc(fd, '%'); putc(fd, '%');
putc(fd, c); putc(fd, c);
} }
#endif
state = 0; state = 0;
} }
} }
} }
void fprintf(int fd, const char *fmt, ...) { void
fprintf(int fd, const char *fmt, ...)
{
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
vprintf(fd, fmt, ap); vprintf(fd, fmt, ap);
} }
void printf(const char *fmt, ...) { void
printf(const char *fmt, ...)
{
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);

View File

@ -1,9 +1,8 @@
// Shell. // Shell.
#include "kernel/fcntl.h"
#include "kernel/fs.h"
#include "kernel/types.h" #include "kernel/types.h"
#include "user/user.h" #include "user/user.h"
#include "kernel/fcntl.h"
// Parsed command representation // Parsed command representation
#define EXEC 1 #define EXEC 1
@ -54,11 +53,11 @@ int fork1(void); // Fork but panics on failure.
void panic(char*); void panic(char*);
struct cmd *parsecmd(char*); struct cmd *parsecmd(char*);
void runcmd(struct cmd*) __attribute__((noreturn)); void runcmd(struct cmd*) __attribute__((noreturn));
// void handle_tab_completion(char *buf, int *i, int nbuf);
// 尝试添加tab补全功能
// Execute cmd. Never returns. // Execute cmd. Never returns.
void runcmd(struct cmd *cmd) { void
runcmd(struct cmd *cmd)
{
int p[2]; int p[2];
struct backcmd *bcmd; struct backcmd *bcmd;
struct execcmd *ecmd; struct execcmd *ecmd;
@ -132,7 +131,9 @@ void runcmd(struct cmd *cmd) {
exit(0); exit(0);
} }
int getcmd(char *buf, int nbuf) { int
getcmd(char *buf, int nbuf)
{
write(2, "$ ", 2); write(2, "$ ", 2);
memset(buf, 0, nbuf); memset(buf, 0, nbuf);
gets(buf, nbuf); gets(buf, nbuf);
@ -141,7 +142,9 @@ int getcmd(char *buf, int nbuf) {
return 0; return 0;
} }
int main(void) { int
main(void)
{
static char buf[100]; static char buf[100];
int fd; int fd;
@ -155,9 +158,6 @@ int main(void) {
// Read and run input commands. // Read and run input commands.
while(getcmd(buf, sizeof(buf)) >= 0){ while(getcmd(buf, sizeof(buf)) >= 0){
if (strcmp(buf, "exit\n") == 0) {
exit(0);
}
if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){ if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
// Chdir must be called by the parent, not the child. // Chdir must be called by the parent, not the child.
buf[strlen(buf)-1] = 0; // chop \n buf[strlen(buf)-1] = 0; // chop \n
@ -172,12 +172,16 @@ int main(void) {
exit(0); exit(0);
} }
void panic(char *s) { void
panic(char *s)
{
fprintf(2, "%s\n", s); fprintf(2, "%s\n", s);
exit(1); exit(1);
} }
int fork1(void) { int
fork1(void)
{
int pid; int pid;
pid = fork(); pid = fork();
@ -189,7 +193,9 @@ int fork1(void) {
//PAGEBREAK! //PAGEBREAK!
// Constructors // Constructors
struct cmd *execcmd(void) { struct cmd*
execcmd(void)
{
struct execcmd *cmd; struct execcmd *cmd;
cmd = malloc(sizeof(*cmd)); cmd = malloc(sizeof(*cmd));
@ -198,8 +204,9 @@ struct cmd *execcmd(void) {
return (struct cmd*)cmd; return (struct cmd*)cmd;
} }
struct cmd *redircmd(struct cmd *subcmd, char *file, char *efile, int mode, struct cmd*
int fd) { redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
{
struct redircmd *cmd; struct redircmd *cmd;
cmd = malloc(sizeof(*cmd)); cmd = malloc(sizeof(*cmd));
@ -213,7 +220,9 @@ struct cmd *redircmd(struct cmd *subcmd, char *file, char *efile, int mode,
return (struct cmd*)cmd; return (struct cmd*)cmd;
} }
struct cmd *pipecmd(struct cmd *left, struct cmd *right) { struct cmd*
pipecmd(struct cmd *left, struct cmd *right)
{
struct pipecmd *cmd; struct pipecmd *cmd;
cmd = malloc(sizeof(*cmd)); cmd = malloc(sizeof(*cmd));
@ -224,7 +233,9 @@ struct cmd *pipecmd(struct cmd *left, struct cmd *right) {
return (struct cmd*)cmd; return (struct cmd*)cmd;
} }
struct cmd *listcmd(struct cmd *left, struct cmd *right) { struct cmd*
listcmd(struct cmd *left, struct cmd *right)
{
struct listcmd *cmd; struct listcmd *cmd;
cmd = malloc(sizeof(*cmd)); cmd = malloc(sizeof(*cmd));
@ -235,7 +246,9 @@ struct cmd *listcmd(struct cmd *left, struct cmd *right) {
return (struct cmd*)cmd; return (struct cmd*)cmd;
} }
struct cmd *backcmd(struct cmd *subcmd) { struct cmd*
backcmd(struct cmd *subcmd)
{
struct backcmd *cmd; struct backcmd *cmd;
cmd = malloc(sizeof(*cmd)); cmd = malloc(sizeof(*cmd));
@ -250,7 +263,9 @@ struct cmd *backcmd(struct cmd *subcmd) {
char whitespace[] = " \t\r\n\v"; char whitespace[] = " \t\r\n\v";
char symbols[] = "<|>&;()"; char symbols[] = "<|>&;()";
int gettoken(char **ps, char *es, char **q, char **eq) { int
gettoken(char **ps, char *es, char **q, char **eq)
{
char *s; char *s;
int ret; int ret;
@ -293,7 +308,9 @@ int gettoken(char **ps, char *es, char **q, char **eq) {
return ret; return ret;
} }
int peek(char **ps, char *es, char *toks) { int
peek(char **ps, char *es, char *toks)
{
char *s; char *s;
s = *ps; s = *ps;
@ -308,7 +325,9 @@ struct cmd *parsepipe(char **, char *);
struct cmd *parseexec(char**, char*); struct cmd *parseexec(char**, char*);
struct cmd *nulterminate(struct cmd*); struct cmd *nulterminate(struct cmd*);
struct cmd *parsecmd(char *s) { struct cmd*
parsecmd(char *s)
{
char *es; char *es;
struct cmd *cmd; struct cmd *cmd;
@ -323,7 +342,9 @@ struct cmd *parsecmd(char *s) {
return cmd; return cmd;
} }
struct cmd *parseline(char **ps, char *es) { struct cmd*
parseline(char **ps, char *es)
{
struct cmd *cmd; struct cmd *cmd;
cmd = parsepipe(ps, es); cmd = parsepipe(ps, es);
@ -338,7 +359,9 @@ struct cmd *parseline(char **ps, char *es) {
return cmd; return cmd;
} }
struct cmd *parsepipe(char **ps, char *es) { struct cmd*
parsepipe(char **ps, char *es)
{
struct cmd *cmd; struct cmd *cmd;
cmd = parseexec(ps, es); cmd = parseexec(ps, es);
@ -349,7 +372,9 @@ struct cmd *parsepipe(char **ps, char *es) {
return cmd; return cmd;
} }
struct cmd *parseredirs(struct cmd *cmd, char **ps, char *es) { struct cmd*
parseredirs(struct cmd *cmd, char **ps, char *es)
{
int tok; int tok;
char *q, *eq; char *q, *eq;
@ -372,7 +397,9 @@ struct cmd *parseredirs(struct cmd *cmd, char **ps, char *es) {
return cmd; return cmd;
} }
struct cmd *parseblock(char **ps, char *es) { struct cmd*
parseblock(char **ps, char *es)
{
struct cmd *cmd; struct cmd *cmd;
if(!peek(ps, es, "(")) if(!peek(ps, es, "("))
@ -386,7 +413,9 @@ struct cmd *parseblock(char **ps, char *es) {
return cmd; return cmd;
} }
struct cmd *parseexec(char **ps, char *es) { struct cmd*
parseexec(char **ps, char *es)
{
char *q, *eq; char *q, *eq;
int tok, argc; int tok, argc;
struct execcmd *cmd; struct execcmd *cmd;
@ -418,7 +447,9 @@ struct cmd *parseexec(char **ps, char *es) {
} }
// NUL-terminate all the counted strings. // NUL-terminate all the counted strings.
struct cmd *nulterminate(struct cmd *cmd) { struct cmd*
nulterminate(struct cmd *cmd)
{
int i; int i;
struct backcmd *bcmd; struct backcmd *bcmd;
struct execcmd *ecmd; struct execcmd *ecmd;

View File

@ -1,13 +0,0 @@
#include "kernel/types.h"
#include "user/user.h"
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(2, "Usage: sleep <time>\n");
exit(1);
}
int time = atoi(argv[1]);
// printf("time: %d\n", time);
sleep(time);
exit(0);
}

View File

@ -1,18 +1,22 @@
#include "kernel/fcntl.h"
#include "kernel/stat.h"
#include "kernel/types.h" #include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/fcntl.h"
#include "user/user.h" #include "user/user.h"
// //
// wrapper so that it's OK if main() does not call exit(). // wrapper so that it's OK if main() does not call exit().
// //
void _main() { void
start()
{
extern int main(); extern int main();
main(); main();
exit(0); exit(0);
} }
char *strcpy(char *s, const char *t) { char*
strcpy(char *s, const char *t)
{
char *os; char *os;
os = s; os = s;
@ -21,34 +25,17 @@ char *strcpy(char *s, const char *t) {
return os; return os;
} }
char *strncpy(char *s, const char *t, int n) { int
char *os; strcmp(const char *p, const char *q)
{
os = s;
if (n <= 0)
return os;
while (--n > 0 && (*s++ = *t++) != 0)
;
while (n-- > 0)
*s++ = 0;
return os;
}
int strcmp(const char *p, const char *q) {
while(*p && *p == *q) while(*p && *p == *q)
p++, q++; p++, q++;
return (uchar)*p - (uchar)*q; return (uchar)*p - (uchar)*q;
} }
int strncmp(const char *p, const char *q, int n) { uint
while (n > 0 && *p && *p == *q) strlen(const char *s)
p++, q++, n--; {
if (n == 0)
return 0;
return (uchar)*p - (uchar)*q;
}
uint strlen(const char *s) {
int n; int n;
for(n = 0; s[n]; n++) for(n = 0; s[n]; n++)
@ -56,7 +43,9 @@ uint strlen(const char *s) {
return n; return n;
} }
void *memset(void *dst, int c, uint n) { void*
memset(void *dst, int c, uint n)
{
char *cdst = (char *) dst; char *cdst = (char *) dst;
int i; int i;
for(i = 0; i < n; i++){ for(i = 0; i < n; i++){
@ -65,14 +54,18 @@ void *memset(void *dst, int c, uint n) {
return dst; return dst;
} }
char *strchr(const char *s, char c) { char*
strchr(const char *s, char c)
{
for(; *s; s++) for(; *s; s++)
if(*s == c) if(*s == c)
return (char*)s; return (char*)s;
return 0; return 0;
} }
char *gets(char *buf, int max) { char*
gets(char *buf, int max)
{
int i, cc; int i, cc;
char c; char c;
@ -88,7 +81,9 @@ char *gets(char *buf, int max) {
return buf; return buf;
} }
int stat(const char *n, struct stat *st) { int
stat(const char *n, struct stat *st)
{
int fd; int fd;
int r; int r;
@ -100,7 +95,9 @@ int stat(const char *n, struct stat *st) {
return r; return r;
} }
int atoi(const char *s) { int
atoi(const char *s)
{
int n; int n;
n = 0; n = 0;
@ -109,7 +106,9 @@ int atoi(const char *s) {
return n; return n;
} }
void *memmove(void *vdst, const void *vsrc, int n) { void*
memmove(void *vdst, const void *vsrc, int n)
{
char *dst; char *dst;
const char *src; const char *src;
@ -127,7 +126,9 @@ void *memmove(void *vdst, const void *vsrc, int n) {
return vdst; return vdst;
} }
int memcmp(const void *s1, const void *s2, uint n) { int
memcmp(const void *s1, const void *s2, uint n)
{
const char *p1 = s1, *p2 = s2; const char *p1 = s1, *p2 = s2;
while (n-- > 0) { while (n-- > 0) {
if (*p1 != *p2) { if (*p1 != *p2) {
@ -139,6 +140,8 @@ int memcmp(const void *s1, const void *s2, uint n) {
return 0; return 0;
} }
void *memcpy(void *dst, const void *src, uint n) { void *
memcpy(void *dst, const void *src, uint n)
{
return memmove(dst, src, n); return memmove(dst, src, n);
} }

View File

@ -1,15 +0,0 @@
#include "kernel/types.h"
#include "user/user.h"
int main(int argc, char *argv[]) {
if (argc != 1) {
// 错误输出到stderr文件描述符2
fprintf(2, "Usage: uptime\n");
exit(1);
}
fprintf(1,"up: %d\n",uptime());
exit(0);
}

View File

@ -1,4 +1,3 @@
#include "kernel/types.h"
struct stat; struct stat;
// system calls // system calls
@ -27,18 +26,18 @@ int uptime(void);
// ulib.c // ulib.c
int stat(const char*, struct stat*); int stat(const char*, struct stat*);
char* strcpy(char*, const char*); char* strcpy(char*, const char*);
char *strncpy(char *, const char *, int);
void *memmove(void*, const void*, int); void *memmove(void*, const void*, int);
char* strchr(const char*, char c); char* strchr(const char*, char c);
int strcmp(const char*, const char*); int strcmp(const char*, const char*);
int strncmp(const char *, const char *, int); void fprintf(int, const char*, ...) __attribute__ ((format (printf, 2, 3)));
void fprintf(int, const char *, ...); void printf(const char*, ...) __attribute__ ((format (printf, 1, 2)));
void printf(const char *, ...);
char* gets(char*, int max); char* gets(char*, int max);
uint strlen(const char*); uint strlen(const char*);
void* memset(void*, int, uint); void* memset(void*, int, uint);
void *malloc(uint);
void free(void *);
int atoi(const char*); int atoi(const char*);
int memcmp(const void *, const void *, uint); int memcmp(const void *, const void *, uint);
void *memcpy(void *, const void *, uint); void *memcpy(void *, const void *, uint);
// umalloc.c
void* malloc(uint);
void free(void*);

View File

@ -1,6 +1,4 @@
OUTPUT_ARCH( "riscv" ) OUTPUT_ARCH( "riscv" )
ENTRY( _main )
SECTIONS SECTIONS
{ {
@ -15,9 +13,14 @@ SECTIONS
*(.srodata .srodata.*) /* do not need to distinguish this from .rodata */ *(.srodata .srodata.*) /* do not need to distinguish this from .rodata */
. = ALIGN(16); . = ALIGN(16);
*(.rodata .rodata.*) *(.rodata .rodata.*)
. = ALIGN(0x1000);
} }
.eh_frame : {
*(.eh_frame)
*(.eh_frame.*)
}
. = ALIGN(0x1000);
.data : { .data : {
. = ALIGN(16); . = ALIGN(16);
*(.sdata .sdata.*) /* do not need to distinguish this from .data */ *(.sdata .sdata.*) /* do not need to distinguish this from .data */

View File

@ -32,9 +32,10 @@ char buf[BUFSZ];
void void
copyin(char *s) copyin(char *s)
{ {
uint64 addrs[] = { 0x80000000LL, 0xffffffffffffffff }; uint64 addrs[] = { 0x80000000LL, 0x3fffffe000, 0x3ffffff000, 0x4000000000,
0xffffffffffffffff };
for(int ai = 0; ai < 2; ai++){ for(int ai = 0; ai < sizeof(addrs)/sizeof(addrs[0]); ai++){
uint64 addr = addrs[ai]; uint64 addr = addrs[ai];
int fd = open("copyin1", O_CREATE|O_WRONLY); int fd = open("copyin1", O_CREATE|O_WRONLY);
@ -44,7 +45,7 @@ copyin(char *s)
} }
int n = write(fd, (void*)addr, 8192); int n = write(fd, (void*)addr, 8192);
if(n >= 0){ if(n >= 0){
printf("write(fd, %p, 8192) returned %d, not -1\n", addr, n); printf("write(fd, %p, 8192) returned %d, not -1\n", (void*)addr, n);
exit(1); exit(1);
} }
close(fd); close(fd);
@ -52,7 +53,7 @@ copyin(char *s)
n = write(1, (char*)addr, 8192); n = write(1, (char*)addr, 8192);
if(n > 0){ if(n > 0){
printf("write(1, %p, 8192) returned %d, not -1 or 0\n", addr, n); printf("write(1, %p, 8192) returned %d, not -1 or 0\n", (void*)addr, n);
exit(1); exit(1);
} }
@ -63,7 +64,7 @@ copyin(char *s)
} }
n = write(fds[1], (char*)addr, 8192); n = write(fds[1], (char*)addr, 8192);
if(n > 0){ if(n > 0){
printf("write(pipe, %p, 8192) returned %d, not -1 or 0\n", addr, n); printf("write(pipe, %p, 8192) returned %d, not -1 or 0\n", (void*)addr, n);
exit(1); exit(1);
} }
close(fds[0]); close(fds[0]);
@ -76,9 +77,10 @@ copyin(char *s)
void void
copyout(char *s) copyout(char *s)
{ {
uint64 addrs[] = { 0LL, 0x80000000LL, 0xffffffffffffffff }; uint64 addrs[] = { 0LL, 0x80000000LL, 0x3fffffe000, 0x3ffffff000, 0x4000000000,
0xffffffffffffffff };
for(int ai = 0; ai < 2; ai++){ for(int ai = 0; ai < sizeof(addrs)/sizeof(addrs[0]); ai++){
uint64 addr = addrs[ai]; uint64 addr = addrs[ai];
int fd = open("README", 0); int fd = open("README", 0);
@ -88,7 +90,7 @@ copyout(char *s)
} }
int n = read(fd, (void*)addr, 8192); int n = read(fd, (void*)addr, 8192);
if(n > 0){ if(n > 0){
printf("read(fd, %p, 8192) returned %d, not -1 or 0\n", addr, n); printf("read(fd, %p, 8192) returned %d, not -1 or 0\n", (void*)addr, n);
exit(1); exit(1);
} }
close(fd); close(fd);
@ -105,7 +107,7 @@ copyout(char *s)
} }
n = read(fds[0], (void*)addr, 8192); n = read(fds[0], (void*)addr, 8192);
if(n > 0){ if(n > 0){
printf("read(pipe, %p, 8192) returned %d, not -1 or 0\n", addr, n); printf("read(pipe, %p, 8192) returned %d, not -1 or 0\n", (void*)addr, n);
exit(1); exit(1);
} }
close(fds[0]); close(fds[0]);
@ -117,14 +119,15 @@ copyout(char *s)
void void
copyinstr1(char *s) copyinstr1(char *s)
{ {
uint64 addrs[] = { 0x80000000LL, 0xffffffffffffffff }; uint64 addrs[] = { 0x80000000LL, 0x3fffffe000, 0x3ffffff000, 0x4000000000,
0xffffffffffffffff };
for(int ai = 0; ai < 2; ai++){ for(int ai = 0; ai < sizeof(addrs)/sizeof(addrs[0]); ai++){
uint64 addr = addrs[ai]; uint64 addr = addrs[ai];
int fd = open((char *)addr, O_CREATE|O_WRONLY); int fd = open((char *)addr, O_CREATE|O_WRONLY);
if(fd >= 0){ if(fd >= 0){
printf("open(%p) returned %d, not -1\n", addr, fd); printf("open(%p) returned %d, not -1\n", (void*)addr, fd);
exit(1); exit(1);
} }
} }
@ -241,7 +244,7 @@ copyinstr3(char *s)
// See if the kernel refuses to read/write user memory that the // See if the kernel refuses to read/write user memory that the
// application doesn't have anymore, because it returned it. // application doesn't have anymore, because it returned it.
void void
rwsbrk() rwsbrk(char* argv)
{ {
int fd, n; int fd, n;
@ -264,7 +267,7 @@ rwsbrk()
} }
n = write(fd, (void*)(a+4096), 1024); n = write(fd, (void*)(a+4096), 1024);
if(n >= 0){ if(n >= 0){
printf("write(fd, %p, 1024) returned %d, not -1\n", a+4096, n); printf("write(fd, %p, 1024) returned %d, not -1\n", (void*)a+4096, n);
exit(1); exit(1);
} }
close(fd); close(fd);
@ -277,7 +280,7 @@ rwsbrk()
} }
n = read(fd, (void*)(a+4096), 10); n = read(fd, (void*)(a+4096), 10);
if(n >= 0){ if(n >= 0){
printf("read(fd, %p, 10) returned %d, not -1\n", a+4096, n); printf("read(fd, %p, 10) returned %d, not -1\n", (void*)a+4096, n);
exit(1); exit(1);
} }
close(fd); close(fd);
@ -589,7 +592,7 @@ writebig(char *s)
for(i = 0; i < MAXFILE; i++){ for(i = 0; i < MAXFILE; i++){
((int*)buf)[0] = i; ((int*)buf)[0] = i;
if(write(fd, buf, BSIZE) != BSIZE){ if(write(fd, buf, BSIZE) != BSIZE){
printf("%s: error: write big file failed\n", s, i); printf("%s: error: write big file failed i=%d\n", s, i);
exit(1); exit(1);
} }
} }
@ -606,7 +609,7 @@ writebig(char *s)
for(;;){ for(;;){
i = read(fd, buf, BSIZE); i = read(fd, buf, BSIZE);
if(i == 0){ if(i == 0){
if(n == MAXFILE - 1){ if(n != MAXFILE){
printf("%s: read only %d blocks from big", s, n); printf("%s: read only %d blocks from big", s, n);
exit(1); exit(1);
} }
@ -773,7 +776,7 @@ pipe1(char *s)
cc = sizeof(buf); cc = sizeof(buf);
} }
if(total != N * SZ){ if(total != N * SZ){
printf("%s: pipe1 oops 3 total %d\n", total); printf("%s: pipe1 oops 3 total %d\n", s, total);
exit(1); exit(1);
} }
close(fds[0]); close(fds[0]);
@ -1069,7 +1072,7 @@ mem(char *s)
} }
m1 = malloc(1024*20); m1 = malloc(1024*20);
if(m1 == 0){ if(m1 == 0){
printf("couldn't allocate mem?!!\n", s); printf("%s: couldn't allocate mem?!!\n", s);
exit(1); exit(1);
} }
free(m1); free(m1);
@ -1161,14 +1164,14 @@ fourfiles(char *s)
pid = fork(); pid = fork();
if(pid < 0){ if(pid < 0){
printf("fork failed\n", s); printf("%s: fork failed\n", s);
exit(1); exit(1);
} }
if(pid == 0){ if(pid == 0){
fd = open(fname, O_CREATE | O_RDWR); fd = open(fname, O_CREATE | O_RDWR);
if(fd < 0){ if(fd < 0){
printf("create failed\n", s); printf("%s: create failed\n", s);
exit(1); exit(1);
} }
@ -1197,7 +1200,7 @@ fourfiles(char *s)
while((n = read(fd, buf, sizeof(buf))) > 0){ while((n = read(fd, buf, sizeof(buf))) > 0){
for(j = 0; j < n; j++){ for(j = 0; j < n; j++){
if(buf[j] != '0'+i){ if(buf[j] != '0'+i){
printf("wrong char\n", s); printf("%s: wrong char\n", s);
exit(1); exit(1);
} }
} }
@ -1223,7 +1226,7 @@ createdelete(char *s)
for(pi = 0; pi < NCHILD; pi++){ for(pi = 0; pi < NCHILD; pi++){
pid = fork(); pid = fork();
if(pid < 0){ if(pid < 0){
printf("fork failed\n", s); printf("%s: fork failed\n", s);
exit(1); exit(1);
} }
@ -1277,7 +1280,7 @@ createdelete(char *s)
for(i = 0; i < N; i++){ for(i = 0; i < N; i++){
for(pi = 0; pi < NCHILD; pi++){ for(pi = 0; pi < NCHILD; pi++){
name[0] = 'p' + i; name[0] = 'p' + pi;
name[1] = '0' + i; name[1] = '0' + i;
unlink(name); unlink(name);
} }
@ -1544,7 +1547,7 @@ subdir(char *s)
} }
if(mkdir("/dd/dd") != 0){ if(mkdir("/dd/dd") != 0){
printf("subdir mkdir dd/dd failed\n", s); printf("%s: subdir mkdir dd/dd failed\n", s);
exit(1); exit(1);
} }
@ -1569,7 +1572,7 @@ subdir(char *s)
close(fd); close(fd);
if(link("dd/dd/ff", "dd/dd/ffff") != 0){ if(link("dd/dd/ff", "dd/dd/ffff") != 0){
printf("link dd/dd/ff dd/dd/ffff failed\n", s); printf("%s: link dd/dd/ff dd/dd/ffff failed\n", s);
exit(1); exit(1);
} }
@ -1591,7 +1594,7 @@ subdir(char *s)
exit(1); exit(1);
} }
if(chdir("dd/../../../dd") != 0){ if(chdir("dd/../../../dd") != 0){
printf("chdir dd/../../dd failed\n", s); printf("%s: chdir dd/../../../dd failed\n", s);
exit(1); exit(1);
} }
if(chdir("./..") != 0){ if(chdir("./..") != 0){
@ -2034,7 +2037,7 @@ sbrkbasic(char *s)
for(i = 0; i < 5000; i++){ for(i = 0; i < 5000; i++){
b = sbrk(1); b = sbrk(1);
if(b != a){ if(b != a){
printf("%s: sbrk test failed %d %x %x\n", s, i, a, b); printf("%s: sbrk test failed %d %p %p\n", s, i, a, b);
exit(1); exit(1);
} }
*b = 1; *b = 1;
@ -2092,7 +2095,7 @@ sbrkmuch(char *s)
} }
c = sbrk(0); c = sbrk(0);
if(c != a - PGSIZE){ if(c != a - PGSIZE){
printf("%s: sbrk deallocation produced wrong address, a %x c %x\n", s, a, c); printf("%s: sbrk deallocation produced wrong address, a %p c %p\n", s, a, c);
exit(1); exit(1);
} }
@ -2100,7 +2103,7 @@ sbrkmuch(char *s)
a = sbrk(0); a = sbrk(0);
c = sbrk(PGSIZE); c = sbrk(PGSIZE);
if(c != a || sbrk(0) != a + PGSIZE){ if(c != a || sbrk(0) != a + PGSIZE){
printf("%s: sbrk re-allocation failed, a %x c %x\n", s, a, c); printf("%s: sbrk re-allocation failed, a %p c %p\n", s, a, c);
exit(1); exit(1);
} }
if(*lastaddr == 99){ if(*lastaddr == 99){
@ -2112,7 +2115,7 @@ sbrkmuch(char *s)
a = sbrk(0); a = sbrk(0);
c = sbrk(-(sbrk(0) - oldbrk)); c = sbrk(-(sbrk(0) - oldbrk));
if(c != a){ if(c != a){
printf("%s: sbrk downsize failed, a %x c %x\n", s, a, c); printf("%s: sbrk downsize failed, a %p c %p\n", s, a, c);
exit(1); exit(1);
} }
} }
@ -2131,7 +2134,7 @@ kernmem(char *s)
exit(1); exit(1);
} }
if(pid == 0){ if(pid == 0){
printf("%s: oops could read %x = %x\n", s, a, *a); printf("%s: oops could read %p = %x\n", s, a, *a);
exit(1); exit(1);
} }
int xstatus; int xstatus;
@ -2155,7 +2158,7 @@ MAXVAplus(char *s)
} }
if(pid == 0){ if(pid == 0){
*(char*)a = 99; *(char*)a = 99;
printf("%s: oops wrote %x\n", s, a); printf("%s: oops wrote %p\n", s, (void*)a);
exit(1); exit(1);
} }
int xstatus; int xstatus;
@ -2307,9 +2310,14 @@ bigargtest(char *s)
if(pid == 0){ if(pid == 0){
static char *args[MAXARG]; static char *args[MAXARG];
int i; int i;
char big[400];
memset(big, ' ', sizeof(big));
big[sizeof(big)-1] = '\0';
for(i = 0; i < MAXARG-1; i++) for(i = 0; i < MAXARG-1; i++)
args[i] = "bigargs test: failed\n "; args[i] = big;
args[MAXARG-1] = 0; args[MAXARG-1] = 0;
// this exec() should fail (and return) because the
// arguments are too large.
exec("echo", args); exec("echo", args);
fd = open("bigarg-ok", O_CREATE); fd = open("bigarg-ok", O_CREATE);
close(fd); close(fd);
@ -2406,9 +2414,9 @@ stacktest(char *s)
pid = fork(); pid = fork();
if(pid == 0) { if(pid == 0) {
char *sp = (char *) r_sp(); char *sp = (char *) r_sp();
sp -= PGSIZE; sp -= USERSTACK*PGSIZE;
// the *sp should cause a trap. // the *sp should cause a trap.
printf("%s: stacktest: read below stack %p\n", s, *sp); printf("%s: stacktest: read below stack %d\n", s, *sp);
exit(1); exit(1);
} else if(pid < 0){ } else if(pid < 0){
printf("%s: fork failed\n", s); printf("%s: fork failed\n", s);
@ -2421,27 +2429,34 @@ stacktest(char *s)
exit(xstatus); exit(xstatus);
} }
// check that writes to text segment fault // check that writes to a few forbidden addresses
// cause a fault, e.g. process's text and TRAMPOLINE.
void void
textwrite(char *s) nowrite(char *s)
{ {
int pid; int pid;
int xstatus; int xstatus;
uint64 addrs[] = { 0, 0x80000000LL, 0x3fffffe000, 0x3ffffff000, 0x4000000000,
0xffffffffffffffff };
for(int ai = 0; ai < sizeof(addrs)/sizeof(addrs[0]); ai++){
pid = fork(); pid = fork();
if(pid == 0) { if(pid == 0) {
volatile int *addr = (int *) 0; volatile int *addr = (int *) addrs[ai];
*addr = 10; *addr = 10;
exit(1); printf("%s: write to %p did not fail!\n", s, addr);
exit(0);
} else if(pid < 0){ } else if(pid < 0){
printf("%s: fork failed\n", s); printf("%s: fork failed\n", s);
exit(1); exit(1);
} }
wait(&xstatus); wait(&xstatus);
if(xstatus == -1) // kernel killed child? if(xstatus == 0){
// kernel did not kill child!
exit(1);
}
}
exit(0); exit(0);
else
exit(xstatus);
} }
// regression test. copyin(), copyout(), and copyinstr() used to cast // regression test. copyin(), copyout(), and copyinstr() used to cast
@ -2629,7 +2644,7 @@ struct test {
{bigargtest, "bigargtest"}, {bigargtest, "bigargtest"},
{argptest, "argptest"}, {argptest, "argptest"},
{stacktest, "stacktest"}, {stacktest, "stacktest"},
{textwrite, "textwrite"}, {nowrite, "nowrite"},
{pgbug, "pgbug" }, {pgbug, "pgbug" },
{sbrkbugs, "sbrkbugs" }, {sbrkbugs, "sbrkbugs" },
{sbrklast, "sbrklast"}, {sbrklast, "sbrklast"},
@ -2666,7 +2681,7 @@ bigdir(char *s)
name[2] = '0' + (i % 64); name[2] = '0' + (i % 64);
name[3] = '\0'; name[3] = '\0';
if(link("bd", name) != 0){ if(link("bd", name) != 0){
printf("%s: bigdir link(bd, %s) failed\n", s, name); printf("%s: bigdir i=%d link(bd, %s) failed\n", s, i, name);
exit(1); exit(1);
} }
} }
@ -2868,7 +2883,7 @@ diskfull(char *s)
// this mkdir() is expected to fail. // this mkdir() is expected to fail.
if(mkdir("diskfulldir") == 0) if(mkdir("diskfulldir") == 0)
printf("%s: mkdir(diskfulldir) unexpectedly succeeded!\n"); printf("%s: mkdir(diskfulldir) unexpectedly succeeded!\n", s);
unlink("diskfulldir"); unlink("diskfulldir");

View File

@ -1,59 +0,0 @@
#include "kernel/param.h"
#include "kernel/stat.h"
#include "kernel/types.h"
#include "user/user.h"
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(2, "Usage: xargs command\n");
exit(1);
}
char *cmd[argc + 1];
int index = 0, data = 0;
for (int i = 1; i < argc; ++i) {
cmd[index++] = argv[i];
}
char buffer[MAXARG];
char line[MAXARG] = {0};
int line_pos = 0;
while ((data = read(0, buffer, MAXARG)) > 0) {
for (int i = 0; i < data; ++i) {
if (buffer[i] == '\n' || buffer[i] == ' ') {
line[line_pos] = 0;
if (line_pos > 0) {
char *arg = malloc(line_pos + 1);
strcpy(arg, line);
cmd[index++] = arg;
}
line_pos = 0;
if (buffer[i] == '\n') {
cmd[index] = 0;
if (fork() == 0) {
exec(cmd[0], cmd);
exit(1);
}
wait(0);
index = argc - 1;
}
} else {
line[line_pos++] = buffer[i];
}
}
}
// bug fixed
if (line_pos > 0) {
line[line_pos] = 0;
cmd[index++] = line;
cmd[index] = 0;
if (fork() == 0) {
exec(cmd[0], cmd);
}
wait(0);
}
exit(0);
}

View File

@ -1,6 +0,0 @@
mkdir a
echo hello > a/b
mkdir c
echo hello > c/b
echo hello > b
find . b | xargs grep hello