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
/lab-*.json
.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:
Copyright (c) 2006-2019 Frans Kaashoek, Robert Morris, Russ Cox,
Copyright (c) 2006-2024 Frans Kaashoek, Robert Morris, Russ Cox,
Massachusetts Institute of Technology
Permission is hereby granted, free of charge, to any person obtaining

View File

@ -44,7 +44,7 @@ OBJS_KCSAN += \
$K/kcsan.o
endif
ifeq ($(LAB),$(filter $(LAB), lock))
ifeq ($(LAB),lock)
OBJS += \
$K/stats.o\
$K/sprintf.o
@ -55,7 +55,6 @@ ifeq ($(LAB),net)
OBJS += \
$K/e1000.o \
$K/net.o \
$K/sysnet.o \
$K/pci.o
endif
@ -86,7 +85,7 @@ LD = $(TOOLPREFIX)ld
OBJCOPY = $(TOOLPREFIX)objcopy
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
LABUPPER = $(shell echo $(LAB) | tr a-z A-Z)
@ -96,7 +95,14 @@ endif
CFLAGS += $(XCFLAGS)
CFLAGS += -MD
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 += $(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
ifeq ($(LAB),$(filter $(LAB), lock))
ifeq ($(LAB),lock)
ULIB += $U/statistics.o
endif
@ -188,16 +194,18 @@ UPROGS=\
$U/_grind\
$U/_wc\
$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 += \
$U/_stats
endif
@ -230,10 +238,10 @@ $U/_uthread: $U/uthread.o $U/uthread_switch.o $(ULIB)
$(OBJDUMP) -S $U/_uthread > $U/uthread.asm
ph: notxv6/ph.c
gcc -o ph -g -Ofast $(XCFLAGS) notxv6/ph.c -pthread
gcc -o ph -g -O2 $(XCFLAGS) notxv6/ph.c -pthread
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
ifeq ($(LAB),pgtbl)
@ -256,7 +264,7 @@ endif
ifeq ($(LAB),net)
UPROGS += \
$U/_nettests
$U/_nettest
endif
UEXTRA=
@ -270,14 +278,12 @@ fs.img: mkfs/mkfs README $(UEXTRA) $(UPROGS)
-include kernel/*.d user/*.d
clean:
rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \
clean:
rm -rf *.tex *.dvi *.idx *.aux *.log *.ind *.ilg *.dSYM *.zip *.pcap \
*/*.o */*.d */*.asm */*.sym \
$U/initcode $U/initcode.out $K/kernel fs.img \
mkfs/mkfs .gdbinit \
$U/usys.S \
$(UPROGS) \
*.zip \
$U/initcode $U/initcode.out $U/usys.S $U/_* \
$K/kernel \
mkfs/mkfs fs.img .gdbinit __pycache__ xv6.out* \
ph barrier
# try to generate a unique GDB port
@ -293,7 +299,8 @@ ifeq ($(LAB),fs)
CPUS := 1
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 += -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
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
endif
@ -319,11 +326,6 @@ ifeq ($(LAB),net)
# try to generate a unique port for the echo server
SERVERPORT = $(shell expr `id -u` % 5000 + 25099)
server:
python3 server.py $(SERVERPORT)
ping:
python3 ping.py $(FWDPORT)
endif
##
@ -341,9 +343,7 @@ grade:
@echo $(MAKE) clean
@$(MAKE) clean || \
(echo "'make clean' failed. HINT: Do you have another running instance of xv6?" && exit 1)
# ./grade-lab-$(LAB) $(GRADEFLAGS)
python grade-lab-$(LAB)
python3.12 ./grade-lab-$(LAB) $(GRADEFLAGS)
##
## FOR submissions

35
README
View File

@ -14,25 +14,22 @@ 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, Silas Boyd-Wickizer, Anton Burtsev, carlclone, Ian
Chen, Dan Cross, Cody Cutler, Mike CAT, Tej Chajed, Asami Doi,
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, Harry Porter, Greg Price, Jude
Rich, segfault, Ayan Shafqat, Eldar Sehayek, Yongming Shen, Fumiya
Shigemitsu, Cam Tenny, tyfkda, Warren Toomey, Stephen Tu, Rafael Ubal,
Amane Uehara, Pablo Ventura, Xi Wang, WaheedHafez, Keiichi Watanabe,
Nicolas Wolovick, wxdao, Grant Wu, 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.
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

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

@ -10,180 +10,180 @@ struct stat;
struct superblock;
// bio.c
void binit(void);
struct buf *bread(uint, uint);
void brelse(struct buf *);
void bwrite(struct buf *);
void bpin(struct buf *);
void bunpin(struct buf *);
void binit(void);
struct buf* bread(uint, uint);
void brelse(struct buf*);
void bwrite(struct buf*);
void bpin(struct buf*);
void bunpin(struct buf*);
// console.c
void consoleinit(void);
void consoleintr(int);
void consputc(int);
void consoleinit(void);
void consoleintr(int);
void consputc(int);
// exec.c
int exec(char *, char **);
int exec(char*, char**);
// file.c
struct file *filealloc(void);
void fileclose(struct file *);
struct file *filedup(struct file *);
void fileinit(void);
int fileread(struct file *, uint64, int n);
int filestat(struct file *, uint64 addr);
int filewrite(struct file *, uint64, int n);
struct file* filealloc(void);
void fileclose(struct file*);
struct file* filedup(struct file*);
void fileinit(void);
int fileread(struct file*, uint64, int n);
int filestat(struct file*, uint64 addr);
int filewrite(struct file*, uint64, int n);
// fs.c
void fsinit(int);
int dirlink(struct inode *, char *, uint);
struct inode *dirlookup(struct inode *, char *, uint *);
struct inode *ialloc(uint, short);
struct inode *idup(struct inode *);
void iinit();
void ilock(struct inode *);
void iput(struct inode *);
void iunlock(struct inode *);
void iunlockput(struct inode *);
void iupdate(struct inode *);
int namecmp(const char *, const char *);
struct inode *namei(char *);
struct inode *nameiparent(char *, char *);
int readi(struct inode *, int, uint64, uint, uint);
void stati(struct inode *, struct stat *);
int writei(struct inode *, int, uint64, uint, uint);
void itrunc(struct inode *);
void fsinit(int);
int dirlink(struct inode*, char*, uint);
struct inode* dirlookup(struct inode*, char*, uint*);
struct inode* ialloc(uint, short);
struct inode* idup(struct inode*);
void iinit();
void ilock(struct inode*);
void iput(struct inode*);
void iunlock(struct inode*);
void iunlockput(struct inode*);
void iupdate(struct inode*);
int namecmp(const char*, const char*);
struct inode* namei(char*);
struct inode* nameiparent(char*, char*);
int readi(struct inode*, int, uint64, uint, uint);
void stati(struct inode*, struct stat*);
int writei(struct inode*, int, uint64, uint, uint);
void itrunc(struct inode*);
// ramdisk.c
void ramdiskinit(void);
void ramdiskintr(void);
void ramdiskrw(struct buf *);
void ramdiskinit(void);
void ramdiskintr(void);
void ramdiskrw(struct buf*);
// kalloc.c
void *kalloc(void);
void kfree(void *);
void kinit(void);
void* kalloc(void);
void kfree(void *);
void kinit(void);
// log.c
void initlog(int, struct superblock *);
void log_write(struct buf *);
void begin_op(void);
void end_op(void);
void initlog(int, struct superblock*);
void log_write(struct buf*);
void begin_op(void);
void end_op(void);
// pipe.c
int pipealloc(struct file **, struct file **);
void pipeclose(struct pipe *, int);
int piperead(struct pipe *, uint64, int);
int pipewrite(struct pipe *, uint64, int);
int pipealloc(struct file**, struct file**);
void pipeclose(struct pipe*, int);
int piperead(struct pipe*, uint64, int);
int pipewrite(struct pipe*, uint64, int);
// printf.c
void printf(char *, ...);
void panic(char *) __attribute__((noreturn));
void printfinit(void);
int printf(char*, ...) __attribute__ ((format (printf, 1, 2)));
void panic(char*) __attribute__((noreturn));
void printfinit(void);
// proc.c
int cpuid(void);
void exit(int);
int fork(void);
int growproc(int);
void proc_mapstacks(pagetable_t);
pagetable_t proc_pagetable(struct proc *);
void proc_freepagetable(pagetable_t, uint64);
int kill(int);
int killed(struct proc *);
void setkilled(struct proc *);
struct cpu *mycpu(void);
struct cpu *getmycpu(void);
struct proc *myproc();
void procinit(void);
void scheduler(void) __attribute__((noreturn));
void sched(void);
void sleep(void *, struct spinlock *);
void userinit(void);
int wait(uint64);
void wakeup(void *);
void yield(void);
int either_copyout(int user_dst, uint64 dst, void *src, uint64 len);
int either_copyin(void *dst, int user_src, uint64 src, uint64 len);
void procdump(void);
int cpuid(void);
void exit(int);
int fork(void);
int growproc(int);
void proc_mapstacks(pagetable_t);
pagetable_t proc_pagetable(struct proc *);
void proc_freepagetable(pagetable_t, uint64);
int kill(int);
int killed(struct proc*);
void setkilled(struct proc*);
struct cpu* mycpu(void);
struct cpu* getmycpu(void);
struct proc* myproc();
void procinit(void);
void scheduler(void) __attribute__((noreturn));
void sched(void);
void sleep(void*, struct spinlock*);
void userinit(void);
int wait(uint64);
void wakeup(void*);
void yield(void);
int either_copyout(int user_dst, uint64 dst, void *src, uint64 len);
int either_copyin(void *dst, int user_src, uint64 src, uint64 len);
void procdump(void);
// swtch.S
void swtch(struct context *, struct context *);
void swtch(struct context*, struct context*);
// spinlock.c
void acquire(struct spinlock *);
int holding(struct spinlock *);
void initlock(struct spinlock *, char *);
void release(struct spinlock *);
void push_off(void);
void pop_off(void);
void acquire(struct spinlock*);
int holding(struct spinlock*);
void initlock(struct spinlock*, char*);
void release(struct spinlock*);
void push_off(void);
void pop_off(void);
// sleeplock.c
void acquiresleep(struct sleeplock *);
void releasesleep(struct sleeplock *);
int holdingsleep(struct sleeplock *);
void initsleeplock(struct sleeplock *, char *);
void acquiresleep(struct sleeplock*);
void releasesleep(struct sleeplock*);
int holdingsleep(struct sleeplock*);
void initsleeplock(struct sleeplock*, char*);
// string.c
int memcmp(const void *, const void *, uint);
void *memmove(void *, const void *, uint);
void *memset(void *, int, uint);
char *safestrcpy(char *, const char *, int);
int strlen(const char *);
int strncmp(const char *, const char *, uint);
char *strncpy(char *, const char *, int);
int memcmp(const void*, const void*, uint);
void* memmove(void*, const void*, uint);
void* memset(void*, int, uint);
char* safestrcpy(char*, const char*, int);
int strlen(const char*);
int strncmp(const char*, const char*, uint);
char* strncpy(char*, const char*, int);
// syscall.c
void argint(int, int *);
int argstr(int, char *, int);
void argaddr(int, uint64 *);
int fetchstr(uint64, char *, int);
int fetchaddr(uint64, uint64 *);
void syscall();
void argint(int, int*);
int argstr(int, char*, int);
void argaddr(int, uint64 *);
int fetchstr(uint64, char*, int);
int fetchaddr(uint64, uint64*);
void syscall();
// trap.c
extern uint ticks;
void trapinit(void);
void trapinithart(void);
extern uint ticks;
void trapinit(void);
void trapinithart(void);
extern struct spinlock tickslock;
void usertrapret(void);
void usertrapret(void);
// uart.c
void uartinit(void);
void uartintr(void);
void uartputc(int);
void uartputc_sync(int);
int uartgetc(void);
void uartinit(void);
void uartintr(void);
void uartputc(int);
void uartputc_sync(int);
int uartgetc(void);
// vm.c
void kvminit(void);
void kvminithart(void);
void kvmmap(pagetable_t, uint64, uint64, uint64, int);
int mappages(pagetable_t, uint64, uint64, uint64, int);
pagetable_t uvmcreate(void);
void uvmfirst(pagetable_t, uchar *, uint);
uint64 uvmalloc(pagetable_t, uint64, uint64, int);
uint64 uvmdealloc(pagetable_t, uint64, uint64);
int uvmcopy(pagetable_t, pagetable_t, uint64);
void uvmfree(pagetable_t, uint64);
void uvmunmap(pagetable_t, uint64, uint64, int);
void uvmclear(pagetable_t, uint64);
pte_t *walk(pagetable_t, uint64, int);
uint64 walkaddr(pagetable_t, uint64);
int copyout(pagetable_t, uint64, char *, uint64);
int copyin(pagetable_t, char *, uint64, uint64);
int copyinstr(pagetable_t, char *, uint64, uint64);
void kvminit(void);
void kvminithart(void);
void kvmmap(pagetable_t, uint64, uint64, uint64, int);
int mappages(pagetable_t, uint64, uint64, uint64, int);
pagetable_t uvmcreate(void);
void uvmfirst(pagetable_t, uchar *, uint);
uint64 uvmalloc(pagetable_t, uint64, uint64, int);
uint64 uvmdealloc(pagetable_t, uint64, uint64);
int uvmcopy(pagetable_t, pagetable_t, uint64);
void uvmfree(pagetable_t, uint64);
void uvmunmap(pagetable_t, uint64, uint64, int);
void uvmclear(pagetable_t, uint64);
pte_t * walk(pagetable_t, uint64, int);
uint64 walkaddr(pagetable_t, uint64);
int copyout(pagetable_t, uint64, char *, uint64);
int copyin(pagetable_t, char *, uint64, uint64);
int copyinstr(pagetable_t, char *, uint64, uint64);
// plic.c
void plicinit(void);
void plicinithart(void);
int plic_claim(void);
void plic_complete(int);
void plicinit(void);
void plicinithart(void);
int plic_claim(void);
void plic_complete(int);
// virtio_disk.c
void virtio_disk_init(void);
void virtio_disk_rw(struct buf *, int);
void virtio_disk_intr(void);
void virtio_disk_init(void);
void virtio_disk_rw(struct buf *, int);
void virtio_disk_intr(void);
// number of elements in fixed-size array
#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
#define NELEM(x) (sizeof(x)/sizeof((x)[0]))

View File

@ -75,17 +75,17 @@ exec(char *path, char **argv)
p = myproc();
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.
// Use the second as the user stack.
// Use the rest as the user stack.
sz = PGROUNDUP(sz);
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;
sz = sz1;
uvmclear(pagetable, sz-2*PGSIZE);
uvmclear(pagetable, sz-(USERSTACK+1)*PGSIZE);
sp = sz;
stackbase = sp - PGSIZE;
stackbase = sp - USERSTACK*PGSIZE;
// Push argument strings, prepare rest of stack in ustack.
for(argc = 0; argv[argc]; argc++) {

View File

@ -1,9 +1,9 @@
// On-disk file system format.
// Both the kernel and user programs use this header file.
#include "kernel/types.h"
#define ROOTINO 1 // root i-number
#define BSIZE 1024 // block size
#define ROOTINO 1 // root i-number
#define BSIZE 1024 // block size
// Disk layout:
// [ boot block | super block | log | inode blocks |
@ -12,14 +12,14 @@
// mkfs computes the super block and builds an initial file system. The
// super block describes the disk layout:
struct superblock {
uint magic; // Must be FSMAGIC
uint size; // Size of file system image (blocks)
uint nblocks; // Number of data blocks
uint ninodes; // Number of inodes.
uint nlog; // Number of log blocks
uint logstart; // Block number of first log block
uint inodestart; // Block number of first inode block
uint bmapstart; // Block number of first free map block
uint magic; // Must be FSMAGIC
uint size; // Size of file system image (blocks)
uint nblocks; // Number of data blocks
uint ninodes; // Number of inodes.
uint nlog; // Number of log blocks
uint logstart; // Block number of first log block
uint inodestart; // Block number of first inode block
uint bmapstart; // Block number of first free map block
};
#define FSMAGIC 0x10203040
@ -30,25 +30,25 @@ struct superblock {
// On-disk inode structure
struct dinode {
short type; // File type
short major; // Major device number (T_DEVICE only)
short minor; // Minor device number (T_DEVICE only)
short nlink; // Number of links to inode in file system
uint size; // Size of file (bytes)
uint addrs[NDIRECT + 1]; // Data block addresses
short type; // File type
short major; // Major device number (T_DEVICE only)
short minor; // Minor device number (T_DEVICE only)
short nlink; // Number of links to inode in file system
uint size; // Size of file (bytes)
uint addrs[NDIRECT+1]; // Data block addresses
};
// Inodes per block.
#define IPB (BSIZE / sizeof(struct dinode))
#define IPB (BSIZE / sizeof(struct dinode))
// Block containing inode i
#define IBLOCK(i, sb) ((i) / IPB + sb.inodestart)
#define IBLOCK(i, sb) ((i) / IPB + sb.inodestart)
// Bitmap bits per block
#define BPB (BSIZE * 8)
#define BPB (BSIZE*8)
// Block of free map containing bit for block b
#define BBLOCK(b, sb) ((b) / BPB + sb.bmapstart)
#define BBLOCK(b, sb) ((b)/BPB + sb.bmapstart)
// Directory is a file containing a sequence of dirent structures.
#define DIRSIZ 14
@ -57,3 +57,4 @@ struct dirent {
ushort inum;
char name[DIRSIZ];
};

View File

@ -9,6 +9,12 @@
#include "riscv.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);
extern char end[]; // first address after kernel.
@ -23,10 +29,25 @@ struct {
struct run *freelist;
} 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
kinit()
{
initlock(&kmem.lock, "kmem");
for(int i = 0; i < NPAGE; i++)
refcnt[i] = 0;
freerange(end, (void*)PHYSTOP);
}
@ -51,6 +72,16 @@ kfree(void *pa)
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
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.
memset(pa, 1, PGSIZE);
@ -76,7 +107,10 @@ kalloc(void)
kmem.freelist = r->next;
release(&kmem.lock);
if(r)
if(r) {
memset((char*)r, 5, PGSIZE); // fill with junk
int idx = pa2idx((void*)r);
refcnt[idx] = 1;
}
return (void*)r;
}

View File

@ -3,7 +3,7 @@
# mode come here.
#
# the current stack is a kernel stack.
# push all registers, call kerneltrap().
# push registers, call kerneltrap().
# when kerneltrap() returns, restore registers, return.
#
.globl kerneltrap
@ -13,7 +13,7 @@ kernelvec:
# make room to save registers.
addi sp, sp, -256
# save the registers.
# save caller-saved registers.
sd ra, 0(sp)
sd sp, 8(sp)
sd gp, 16(sp)
@ -21,8 +21,6 @@ kernelvec:
sd t0, 32(sp)
sd t1, 40(sp)
sd t2, 48(sp)
sd s0, 56(sp)
sd s1, 64(sp)
sd a0, 72(sp)
sd a1, 80(sp)
sd a2, 88(sp)
@ -31,16 +29,6 @@ kernelvec:
sd a5, 112(sp)
sd a6, 120(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 t4, 224(sp)
sd t5, 232(sp)
@ -57,8 +45,6 @@ kernelvec:
ld t0, 32(sp)
ld t1, 40(sp)
ld t2, 48(sp)
ld s0, 56(sp)
ld s1, 64(sp)
ld a0, 72(sp)
ld a1, 80(sp)
ld a2, 88(sp)
@ -67,16 +53,6 @@ kernelvec:
ld a5, 112(sp)
ld a6, 120(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 t4, 224(sp)
ld t5, 232(sp)
@ -86,39 +62,3 @@ kernelvec:
# return to whatever we were doing in the kernel.
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_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.
#define PLIC 0x0c000000L
#define PLIC_PRIORITY (PLIC + 0x0)

View File

@ -11,3 +11,5 @@
#define NBUF (MAXOPBLOCKS*3) // size of disk block cache
#define FSSIZE 2000 // size of file system in blocks
#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 void
printint(int xx, int base, int sign)
printint(long long xx, int base, int sign)
{
char buf[16];
int i;
uint x;
unsigned long long x;
if(sign && (sign = xx < 0))
if(sign && (sign = (xx < 0)))
x = -xx;
else
x = xx;
@ -59,30 +59,71 @@ printptr(uint64 x)
consputc(digits[x >> (sizeof(uint64) * 8 - 4)]);
}
// Print to the console. only understands %d, %x, %p, %s.
void
// Print to the console.
int
printf(char *fmt, ...)
{
va_list ap;
int i, c, locking;
int i, cx, c0, c1, c2, locking;
char *s;
locking = pr.locking;
if(locking)
acquire(&pr.lock);
if (fmt == 0)
panic("null fmt");
va_start(ap, fmt);
for(i = 0; (c = fmt[i] & 0xff) != 0; i++){
if(c != '%'){
consputc(c);
for(i = 0; (cx = fmt[i] & 0xff) != 0; i++){
if(cx != '%'){
consputc(cx);
continue;
}
c = fmt[++i] & 0xff;
if(c == 0)
i++;
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;
} else {
// Print unknown % sequence to draw attention.
consputc('%');
consputc(c0);
}
#if 0
switch(c){
case 'd':
printint(va_arg(ap, int), 10, 1);
@ -108,11 +149,14 @@ printf(char *fmt, ...)
consputc(c);
break;
}
#endif
}
va_end(ap);
if(locking)
release(&pr.lock);
return 0;
}
void
@ -120,8 +164,7 @@ panic(char *s)
{
pr.locking = 0;
printf("panic: ");
printf(s);
printf("\n");
printf("%s\n", s);
panicked = 1; // freeze uart output from other CPUs
for(;;)
;

View File

@ -454,6 +454,7 @@ scheduler(void)
// processes are waiting.
intr_on();
int found = 0;
for(p = proc; p < &proc[NPROC]; p++) {
acquire(&p->lock);
if(p->state == RUNNABLE) {
@ -467,9 +468,15 @@ scheduler(void)
// Process is done running for now.
// It should have changed its p->state before coming back.
c->proc = 0;
found = 1;
}
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
#define MIE_MEIE (1L << 11) // external
#define MIE_MTIE (1L << 7) // timer
#define MIE_MSIE (1L << 3) // software
#define MIE_STIE (1L << 5) // supervisor timer
static inline uint64
r_mie()
{
@ -176,11 +174,38 @@ r_stvec()
return x;
}
// Machine-mode interrupt vector
static inline void
w_mtvec(uint64 x)
// Supervisor Timer Comparison Register
static inline uint64
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
@ -217,12 +242,6 @@ r_satp()
return x;
}
static inline void
w_mscratch(uint64 x)
{
asm volatile("csrw mscratch, %0" : : "r" (x));
}
// Supervisor Trap Cause
static inline uint64
r_scause()
@ -343,6 +362,7 @@ typedef uint64 *pagetable_t; // 512 PTEs
#define PTE_W (1L << 2)
#define PTE_X (1L << 3)
#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.
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)

View File

@ -10,12 +10,6 @@ void timerinit();
// entry.S needs one stack per CPU.
__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.
void
start()
@ -54,36 +48,19 @@ start()
asm volatile("mret");
}
// arrange to receive 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.
// ask each hart to generate timer interrupts.
void
timerinit()
{
// each CPU has a separate source of timer interrupts.
int id = r_mhartid();
// ask the CLINT for a timer interrupt.
int interval = 1000000; // cycles; about 1/10th second in qemu.
*(uint64*)CLINT_MTIMECMP(id) = *(uint64*)CLINT_MTIME + interval;
// prepare information in scratch[] for timervec.
// scratch[0..2] : space for timervec to save registers.
// 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.
w_mtvec((uint64)timervec);
// enable machine-mode interrupts.
w_mstatus(r_mstatus() | MSTATUS_MIE);
// enable machine-mode timer interrupts.
w_mie(r_mie() | MIE_MTIE);
// enable supervisor-mode timer interrupts.
w_mie(r_mie() | MIE_STIE);
// enable the sstc extension (i.e. stimecmp).
w_menvcfg(r_menvcfg() | (1L << 63));
// allow supervisor to use stimecmp and time.
w_mcounteren(r_mcounteren() | 2);
// ask for the very first timer interrupt.
w_stimecmp(r_time() + 1000000);
}

View File

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

View File

@ -16,6 +16,9 @@ void kernelvec();
extern int devintr();
typedef uint64 pte_t;
pte_t *walk(pagetable_t pagetable, uint64 va, int alloc);
void
trapinit(void)
{
@ -50,7 +53,10 @@ usertrap(void)
// save user program counter.
p->trapframe->epc = r_sepc();
if(r_scause() == 8){
uint64 scause = r_scause();
uint64 stval = r_stval();
if(scause == 8){
// system call
if(killed(p))
@ -67,9 +73,26 @@ usertrap(void)
syscall();
} else if((which_dev = devintr()) != 0){
// 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 {
memmove(mem, (void*)pa, PGSIZE);
*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 %p pid=%d\n", r_scause(), p->pid);
printf(" sepc=%p stval=%p\n", r_sepc(), r_stval());
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);
}
@ -145,13 +168,13 @@ kerneltrap()
panic("kerneltrap: interrupts enabled");
if((which_dev = devintr()) == 0){
printf("scause %p\n", scause);
printf("sepc=%p stval=%p\n", r_sepc(), r_stval());
// interrupt or trap from an unknown source
printf("scause=0x%lx sepc=0x%lx stval=0x%lx\n", scause, r_sepc(), r_stval());
panic("kerneltrap");
}
// 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();
// the yield() may have caused some traps to occur,
@ -163,10 +186,17 @@ kerneltrap()
void
clockintr()
{
acquire(&tickslock);
ticks++;
wakeup(&ticks);
release(&tickslock);
if(cpuid() == 0){
acquire(&tickslock);
ticks++;
wakeup(&ticks);
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,
@ -179,8 +209,7 @@ devintr()
{
uint64 scause = r_scause();
if((scause & 0x8000000000000000L) &&
(scause & 0xff) == 9){
if(scause == 0x8000000000000009L){
// this is a supervisor external interrupt, via PLIC.
// irq indicates which device interrupted.
@ -201,21 +230,15 @@ devintr()
plic_complete(irq);
return 1;
} else if(scause == 0x8000000000000001L){
// software interrupt from a machine-mode timer interrupt,
// forwarded by timervec in kernelvec.S.
if(cpuid() == 0){
clockintr();
}
// acknowledge the software interrupt by clearing
// the SSIP bit in sip.
w_sip(r_sip() & ~2);
} else if(scause == 0x8000000000000005L){
// timer interrupt.
clockintr();
return 2;
} else {
return 0;
}
}
void kfree(void *pa);
void *kalloc(void);

View File

@ -1,10 +1,10 @@
typedef unsigned int uint;
typedef unsigned int uint;
typedef unsigned short ushort;
typedef unsigned char uchar;
typedef unsigned char uchar;
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned int uint32;
typedef unsigned long uint64;
typedef uint64 pde_t;

View File

@ -13,7 +13,7 @@
// the UART control registers are memory-mapped
// at address UART0. this macro returns the
// 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.
// some have different meanings for
@ -136,6 +136,7 @@ uartstart()
while(1){
if(uart_tx_w == uart_tx_r){
// transmit buffer is empty.
ReadReg(ISR);
return;
}

View File

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

View File

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

View File

@ -1 +1 @@
5
9

View File

@ -1,35 +1,38 @@
#include "kernel/fcntl.h"
#include "kernel/stat.h"
#include "kernel/types.h"
#include "kernel/fcntl.h"
#include "user/user.h"
char buf[512];
void cat(int fd) {
void
cat(int fd)
{
int n;
while ((n = read(fd, buf, sizeof(buf))) > 0) {
while((n = read(fd, buf, sizeof(buf))) > 0) {
if (write(1, buf, n) != n) {
fprintf(2, "cat: write error\n");
exit(1);
}
}
if (n < 0) {
if(n < 0){
fprintf(2, "cat: read error\n");
exit(1);
}
}
int main(int argc, char *argv[]) {
int
main(int argc, char *argv[])
{
int fd, i;
if (argc <= 1) {
if(argc <= 1){
cat(0);
exit(0);
}
for (i = 1; i < argc; i++) {
if ((fd = open(argv[i], O_RDONLY)) < 0) {
for(i = 1; i < argc; i++){
if((fd = open(argv[i], O_RDONLY)) < 0){
fprintf(2, "cat: cannot open %s\n", argv[i]);
exit(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 };
.p2align 2
argv:
.long init
.long 0
.quad init
.quad 0

View File

@ -1,81 +1,87 @@
#include "kernel/fcntl.h"
#include "kernel/fs.h"
#include "kernel/stat.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
#include "kernel/fcntl.h"
char *fmtname(char *path) {
static char buf[DIRSIZ + 1];
char*
fmtname(char *path)
{
static char buf[DIRSIZ+1];
char *p;
// Find first character after last slash.
for (p = path + strlen(path); p >= path && *p != '/'; p--)
for(p=path+strlen(path); p >= path && *p != '/'; p--)
;
p++;
// Return blank-padded name.
if (strlen(p) >= DIRSIZ)
if(strlen(p) >= DIRSIZ)
return p;
memmove(buf, p, strlen(p));
memset(buf + strlen(p), ' ', DIRSIZ - strlen(p));
memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));
return buf;
}
void ls(char *path) {
void
ls(char *path)
{
char buf[512], *p;
int fd;
struct dirent de;
struct stat st;
if ((fd = open(path, O_RDONLY)) < 0) {
if((fd = open(path, O_RDONLY)) < 0){
fprintf(2, "ls: cannot open %s\n", path);
return;
}
if (fstat(fd, &st) < 0) {
if(fstat(fd, &st) < 0){
fprintf(2, "ls: cannot stat %s\n", path);
close(fd);
return;
}
switch (st.type) {
switch(st.type){
case T_DEVICE:
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;
case T_DIR:
if (strlen(path) + 1 + DIRSIZ + 1 > sizeof buf) {
if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
printf("ls: path too long\n");
break;
}
strcpy(buf, path);
p = buf + strlen(buf);
p = buf+strlen(buf);
*p++ = '/';
while (read(fd, &de, sizeof(de)) == sizeof(de)) {
if (de.inum == 0)
while(read(fd, &de, sizeof(de)) == sizeof(de)){
if(de.inum == 0)
continue;
memmove(p, de.name, DIRSIZ);
p[DIRSIZ] = 0;
if (stat(buf, &st) < 0) {
if(stat(buf, &st) < 0){
printf("ls: cannot stat %s\n", buf);
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;
}
close(fd);
}
int main(int argc, char *argv[]) {
int
main(int argc, char *argv[])
{
int i;
if (argc < 2) {
if(argc < 2){
ls(".");
exit(0);
}
for (i = 1; i < argc; i++)
for(i=1; i<argc; i++)
ls(argv[i]);
exit(0);
}

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,20 +1,26 @@
#include "kernel/stat.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include <stdarg.h>
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];
int i, neg;
uint x;
neg = 0;
if (sgn && xx < 0) {
if(sgn && xx < 0){
neg = 1;
x = -xx;
} else {
@ -22,17 +28,18 @@ static void printint(int fd, int xx, int base, int sgn) {
}
i = 0;
do {
do{
buf[i++] = digits[x % base];
} while ((x /= base) != 0);
if (neg)
}while((x /= base) != 0);
if(neg)
buf[i++] = '-';
while (--i >= 0)
while(--i >= 0)
putc(fd, buf[i]);
}
static void printptr(int fd, uint64 x) {
static void
printptr(int fd, uint64 x) {
int i;
putc(fd, '0');
putc(fd, 'x');
@ -41,58 +48,108 @@ static void printptr(int fd, uint64 x) {
}
// 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;
int c, i, state;
int c0, c1, c2, i, state;
state = 0;
for (i = 0; fmt[i]; i++) {
c = fmt[i] & 0xff;
if (state == 0) {
if (c == '%') {
for(i = 0; fmt[i]; i++){
c0 = fmt[i] & 0xff;
if(state == 0){
if(c0 == '%'){
state = '%';
} else {
putc(fd, c);
putc(fd, c0);
}
} else if (state == '%') {
if (c == 'd') {
} 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 (c == 'l') {
} 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);
} else if (c == 'x') {
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 (c == 'p') {
} 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 (c == 's') {
s = va_arg(ap, char *);
if (s == 0)
} else if(c0 == 's'){
if((s = va_arg(ap, char*)) == 0)
s = "(null)";
while (*s != 0) {
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'){
printint(fd, va_arg(ap, int), 10, 1);
} else if(c == 'l') {
printint(fd, va_arg(ap, uint64), 10, 0);
} else if(c == 'x') {
printint(fd, va_arg(ap, int), 16, 0);
} else if(c == 'p') {
printptr(fd, va_arg(ap, uint64));
} else if(c == 's'){
s = va_arg(ap, char*);
if(s == 0)
s = "(null)";
while(*s != 0){
putc(fd, *s);
s++;
}
} else if (c == 'c') {
} else if(c == 'c'){
putc(fd, va_arg(ap, uint));
} else if (c == '%') {
} else if(c == '%'){
putc(fd, c);
} else {
// Unknown % sequence. Print it to draw attention.
putc(fd, '%');
putc(fd, c);
}
#endif
state = 0;
}
}
}
void fprintf(int fd, const char *fmt, ...) {
void
fprintf(int fd, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintf(fd, fmt, ap);
}
void printf(const char *fmt, ...) {
void
printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);

243
user/sh.c
View File

@ -1,16 +1,15 @@
// Shell.
#include "kernel/fcntl.h"
#include "kernel/fs.h"
#include "kernel/types.h"
#include "user/user.h"
#include "kernel/fcntl.h"
// Parsed command representation
#define EXEC 1
#define EXEC 1
#define REDIR 2
#define PIPE 3
#define LIST 4
#define BACK 5
#define PIPE 3
#define LIST 4
#define BACK 5
#define MAXARGS 10
@ -50,15 +49,15 @@ struct backcmd {
struct cmd *cmd;
};
int fork1(void); // Fork but panics on failure.
void panic(char *);
struct cmd *parsecmd(char *);
void runcmd(struct cmd *) __attribute__((noreturn));
// void handle_tab_completion(char *buf, int *i, int nbuf);
// 尝试添加tab补全功能
int fork1(void); // Fork but panics on failure.
void panic(char*);
struct cmd *parsecmd(char*);
void runcmd(struct cmd*) __attribute__((noreturn));
// Execute cmd. Never returns.
void runcmd(struct cmd *cmd) {
void
runcmd(struct cmd *cmd)
{
int p[2];
struct backcmd *bcmd;
struct execcmd *ecmd;
@ -66,25 +65,25 @@ void runcmd(struct cmd *cmd) {
struct pipecmd *pcmd;
struct redircmd *rcmd;
if (cmd == 0)
if(cmd == 0)
exit(1);
switch (cmd->type) {
switch(cmd->type){
default:
panic("runcmd");
case EXEC:
ecmd = (struct execcmd *)cmd;
if (ecmd->argv[0] == 0)
ecmd = (struct execcmd*)cmd;
if(ecmd->argv[0] == 0)
exit(1);
exec(ecmd->argv[0], ecmd->argv);
fprintf(2, "exec %s failed\n", ecmd->argv[0]);
break;
case REDIR:
rcmd = (struct redircmd *)cmd;
rcmd = (struct redircmd*)cmd;
close(rcmd->fd);
if (open(rcmd->file, rcmd->mode) < 0) {
if(open(rcmd->file, rcmd->mode) < 0){
fprintf(2, "open %s failed\n", rcmd->file);
exit(1);
}
@ -92,25 +91,25 @@ void runcmd(struct cmd *cmd) {
break;
case LIST:
lcmd = (struct listcmd *)cmd;
if (fork1() == 0)
lcmd = (struct listcmd*)cmd;
if(fork1() == 0)
runcmd(lcmd->left);
wait(0);
runcmd(lcmd->right);
break;
case PIPE:
pcmd = (struct pipecmd *)cmd;
if (pipe(p) < 0)
pcmd = (struct pipecmd*)cmd;
if(pipe(p) < 0)
panic("pipe");
if (fork1() == 0) {
if(fork1() == 0){
close(1);
dup(p[1]);
close(p[0]);
close(p[1]);
runcmd(pcmd->left);
}
if (fork1() == 0) {
if(fork1() == 0){
close(0);
dup(p[0]);
close(p[0]);
@ -124,82 +123,90 @@ void runcmd(struct cmd *cmd) {
break;
case BACK:
bcmd = (struct backcmd *)cmd;
if (fork1() == 0)
bcmd = (struct backcmd*)cmd;
if(fork1() == 0)
runcmd(bcmd->cmd);
break;
}
exit(0);
}
int getcmd(char *buf, int nbuf) {
int
getcmd(char *buf, int nbuf)
{
write(2, "$ ", 2);
memset(buf, 0, nbuf);
gets(buf, nbuf);
if (buf[0] == 0) // EOF
if(buf[0] == 0) // EOF
return -1;
return 0;
}
int main(void) {
int
main(void)
{
static char buf[100];
int fd;
// Ensure that three file descriptors are open.
while ((fd = open("console", O_RDWR)) >= 0) {
if (fd >= 3) {
while((fd = open("console", O_RDWR)) >= 0){
if(fd >= 3){
close(fd);
break;
}
}
// Read and run input commands.
while (getcmd(buf, sizeof(buf)) >= 0) {
if (strcmp(buf, "exit\n") == 0) {
exit(0);
}
if (buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' ') {
while(getcmd(buf, sizeof(buf)) >= 0){
if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
// Chdir must be called by the parent, not the child.
buf[strlen(buf) - 1] = 0; // chop \n
if (chdir(buf + 3) < 0)
fprintf(2, "cannot cd %s\n", buf + 3);
buf[strlen(buf)-1] = 0; // chop \n
if(chdir(buf+3) < 0)
fprintf(2, "cannot cd %s\n", buf+3);
continue;
}
if (fork1() == 0)
if(fork1() == 0)
runcmd(parsecmd(buf));
wait(0);
}
exit(0);
}
void panic(char *s) {
void
panic(char *s)
{
fprintf(2, "%s\n", s);
exit(1);
}
int fork1(void) {
int
fork1(void)
{
int pid;
pid = fork();
if (pid == -1)
if(pid == -1)
panic("fork");
return pid;
}
// PAGEBREAK!
// Constructors
//PAGEBREAK!
// Constructors
struct cmd *execcmd(void) {
struct cmd*
execcmd(void)
{
struct execcmd *cmd;
cmd = malloc(sizeof(*cmd));
memset(cmd, 0, sizeof(*cmd));
cmd->type = EXEC;
return (struct cmd *)cmd;
return (struct cmd*)cmd;
}
struct cmd *redircmd(struct cmd *subcmd, char *file, char *efile, int mode,
int fd) {
struct cmd*
redircmd(struct cmd *subcmd, char *file, char *efile, int mode, int fd)
{
struct redircmd *cmd;
cmd = malloc(sizeof(*cmd));
@ -210,10 +217,12 @@ struct cmd *redircmd(struct cmd *subcmd, char *file, char *efile, int mode,
cmd->efile = efile;
cmd->mode = mode;
cmd->fd = fd;
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;
cmd = malloc(sizeof(*cmd));
@ -221,10 +230,12 @@ struct cmd *pipecmd(struct cmd *left, struct cmd *right) {
cmd->type = PIPE;
cmd->left = left;
cmd->right = 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;
cmd = malloc(sizeof(*cmd));
@ -232,35 +243,39 @@ struct cmd *listcmd(struct cmd *left, struct cmd *right) {
cmd->type = LIST;
cmd->left = left;
cmd->right = right;
return (struct cmd *)cmd;
return (struct cmd*)cmd;
}
struct cmd *backcmd(struct cmd *subcmd) {
struct cmd*
backcmd(struct cmd *subcmd)
{
struct backcmd *cmd;
cmd = malloc(sizeof(*cmd));
memset(cmd, 0, sizeof(*cmd));
cmd->type = BACK;
cmd->cmd = subcmd;
return (struct cmd *)cmd;
return (struct cmd*)cmd;
}
// PAGEBREAK!
// Parsing
//PAGEBREAK!
// Parsing
char whitespace[] = " \t\r\n\v";
char symbols[] = "<|>&;()";
int gettoken(char **ps, char *es, char **q, char **eq) {
int
gettoken(char **ps, char *es, char **q, char **eq)
{
char *s;
int ret;
s = *ps;
while (s < es && strchr(whitespace, *s))
while(s < es && strchr(whitespace, *s))
s++;
if (q)
if(q)
*q = s;
ret = *s;
switch (*s) {
switch(*s){
case 0:
break;
case '|':
@ -273,49 +288,53 @@ int gettoken(char **ps, char *es, char **q, char **eq) {
break;
case '>':
s++;
if (*s == '>') {
if(*s == '>'){
ret = '+';
s++;
}
break;
default:
ret = 'a';
while (s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
while(s < es && !strchr(whitespace, *s) && !strchr(symbols, *s))
s++;
break;
}
if (eq)
if(eq)
*eq = s;
while (s < es && strchr(whitespace, *s))
while(s < es && strchr(whitespace, *s))
s++;
*ps = s;
return ret;
}
int peek(char **ps, char *es, char *toks) {
int
peek(char **ps, char *es, char *toks)
{
char *s;
s = *ps;
while (s < es && strchr(whitespace, *s))
while(s < es && strchr(whitespace, *s))
s++;
*ps = s;
return *s && strchr(toks, *s);
}
struct cmd *parseline(char **, char *);
struct cmd *parsepipe(char **, char *);
struct cmd *parseexec(char **, char *);
struct cmd *nulterminate(struct cmd *);
struct cmd *parseline(char**, char*);
struct cmd *parsepipe(char**, char*);
struct cmd *parseexec(char**, char*);
struct cmd *nulterminate(struct cmd*);
struct cmd *parsecmd(char *s) {
struct cmd*
parsecmd(char *s)
{
char *es;
struct cmd *cmd;
es = s + strlen(s);
cmd = parseline(&s, es);
peek(&s, es, "");
if (s != es) {
if(s != es){
fprintf(2, "leftovers: %s\n", s);
panic("syntax");
}
@ -323,92 +342,102 @@ struct cmd *parsecmd(char *s) {
return cmd;
}
struct cmd *parseline(char **ps, char *es) {
struct cmd*
parseline(char **ps, char *es)
{
struct cmd *cmd;
cmd = parsepipe(ps, es);
while (peek(ps, es, "&")) {
while(peek(ps, es, "&")){
gettoken(ps, es, 0, 0);
cmd = backcmd(cmd);
}
if (peek(ps, es, ";")) {
if(peek(ps, es, ";")){
gettoken(ps, es, 0, 0);
cmd = listcmd(cmd, parseline(ps, es));
}
return cmd;
}
struct cmd *parsepipe(char **ps, char *es) {
struct cmd*
parsepipe(char **ps, char *es)
{
struct cmd *cmd;
cmd = parseexec(ps, es);
if (peek(ps, es, "|")) {
if(peek(ps, es, "|")){
gettoken(ps, es, 0, 0);
cmd = pipecmd(cmd, parsepipe(ps, es));
}
return cmd;
}
struct cmd *parseredirs(struct cmd *cmd, char **ps, char *es) {
struct cmd*
parseredirs(struct cmd *cmd, char **ps, char *es)
{
int tok;
char *q, *eq;
while (peek(ps, es, "<>")) {
while(peek(ps, es, "<>")){
tok = gettoken(ps, es, 0, 0);
if (gettoken(ps, es, &q, &eq) != 'a')
if(gettoken(ps, es, &q, &eq) != 'a')
panic("missing file for redirection");
switch (tok) {
switch(tok){
case '<':
cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
break;
case '>':
cmd = redircmd(cmd, q, eq, O_WRONLY | O_CREATE | O_TRUNC, 1);
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE|O_TRUNC, 1);
break;
case '+': // >>
cmd = redircmd(cmd, q, eq, O_WRONLY | O_CREATE, 1);
case '+': // >>
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
break;
}
}
return cmd;
}
struct cmd *parseblock(char **ps, char *es) {
struct cmd*
parseblock(char **ps, char *es)
{
struct cmd *cmd;
if (!peek(ps, es, "("))
if(!peek(ps, es, "("))
panic("parseblock");
gettoken(ps, es, 0, 0);
cmd = parseline(ps, es);
if (!peek(ps, es, ")"))
if(!peek(ps, es, ")"))
panic("syntax - missing )");
gettoken(ps, es, 0, 0);
cmd = parseredirs(cmd, ps, es);
return cmd;
}
struct cmd *parseexec(char **ps, char *es) {
struct cmd*
parseexec(char **ps, char *es)
{
char *q, *eq;
int tok, argc;
struct execcmd *cmd;
struct cmd *ret;
if (peek(ps, es, "("))
if(peek(ps, es, "("))
return parseblock(ps, es);
ret = execcmd();
cmd = (struct execcmd *)ret;
cmd = (struct execcmd*)ret;
argc = 0;
ret = parseredirs(ret, ps, es);
while (!peek(ps, es, "|)&;")) {
if ((tok = gettoken(ps, es, &q, &eq)) == 0)
while(!peek(ps, es, "|)&;")){
if((tok=gettoken(ps, es, &q, &eq)) == 0)
break;
if (tok != 'a')
if(tok != 'a')
panic("syntax");
cmd->argv[argc] = q;
cmd->eargv[argc] = eq;
argc++;
if (argc >= MAXARGS)
if(argc >= MAXARGS)
panic("too many args");
ret = parseredirs(ret, ps, es);
}
@ -418,7 +447,9 @@ struct cmd *parseexec(char **ps, char *es) {
}
// NUL-terminate all the counted strings.
struct cmd *nulterminate(struct cmd *cmd) {
struct cmd*
nulterminate(struct cmd *cmd)
{
int i;
struct backcmd *bcmd;
struct execcmd *ecmd;
@ -426,36 +457,36 @@ struct cmd *nulterminate(struct cmd *cmd) {
struct pipecmd *pcmd;
struct redircmd *rcmd;
if (cmd == 0)
if(cmd == 0)
return 0;
switch (cmd->type) {
switch(cmd->type){
case EXEC:
ecmd = (struct execcmd *)cmd;
for (i = 0; ecmd->argv[i]; i++)
ecmd = (struct execcmd*)cmd;
for(i=0; ecmd->argv[i]; i++)
*ecmd->eargv[i] = 0;
break;
case REDIR:
rcmd = (struct redircmd *)cmd;
rcmd = (struct redircmd*)cmd;
nulterminate(rcmd->cmd);
*rcmd->efile = 0;
break;
case PIPE:
pcmd = (struct pipecmd *)cmd;
pcmd = (struct pipecmd*)cmd;
nulterminate(pcmd->left);
nulterminate(pcmd->right);
break;
case LIST:
lcmd = (struct listcmd *)cmd;
lcmd = (struct listcmd*)cmd;
nulterminate(lcmd->left);
nulterminate(lcmd->right);
break;
case BACK:
bcmd = (struct backcmd *)cmd;
bcmd = (struct backcmd*)cmd;
nulterminate(bcmd->cmd);
break;
}

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,133 +1,134 @@
#include "kernel/fcntl.h"
#include "kernel/stat.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "kernel/fcntl.h"
#include "user/user.h"
//
// wrapper so that it's OK if main() does not call exit().
//
void _main() {
void
start()
{
extern int main();
main();
exit(0);
}
char *strcpy(char *s, const char *t) {
char*
strcpy(char *s, const char *t)
{
char *os;
os = s;
while ((*s++ = *t++) != 0)
while((*s++ = *t++) != 0)
;
return os;
}
char *strncpy(char *s, const char *t, int n) {
char *os;
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)
int
strcmp(const char *p, const char *q)
{
while(*p && *p == *q)
p++, q++;
return (uchar)*p - (uchar)*q;
}
int strncmp(const char *p, const char *q, int n) {
while (n > 0 && *p && *p == *q)
p++, q++, n--;
if (n == 0)
return 0;
return (uchar)*p - (uchar)*q;
}
uint strlen(const char *s) {
uint
strlen(const char *s)
{
int n;
for (n = 0; s[n]; n++)
for(n = 0; s[n]; n++)
;
return n;
}
void *memset(void *dst, int c, uint n) {
char *cdst = (char *)dst;
void*
memset(void *dst, int c, uint n)
{
char *cdst = (char *) dst;
int i;
for (i = 0; i < n; i++) {
for(i = 0; i < n; i++){
cdst[i] = c;
}
return dst;
}
char *strchr(const char *s, char c) {
for (; *s; s++)
if (*s == c)
return (char *)s;
char*
strchr(const char *s, char c)
{
for(; *s; s++)
if(*s == c)
return (char*)s;
return 0;
}
char *gets(char *buf, int max) {
char*
gets(char *buf, int max)
{
int i, cc;
char c;
for (i = 0; i + 1 < max;) {
for(i=0; i+1 < max; ){
cc = read(0, &c, 1);
if (cc < 1)
if(cc < 1)
break;
buf[i++] = c;
if (c == '\n' || c == '\r')
if(c == '\n' || c == '\r')
break;
}
buf[i] = '\0';
return buf;
}
int stat(const char *n, struct stat *st) {
int
stat(const char *n, struct stat *st)
{
int fd;
int r;
fd = open(n, O_RDONLY);
if (fd < 0)
if(fd < 0)
return -1;
r = fstat(fd, st);
close(fd);
return r;
}
int atoi(const char *s) {
int
atoi(const char *s)
{
int n;
n = 0;
while ('0' <= *s && *s <= '9')
n = n * 10 + *s++ - '0';
while('0' <= *s && *s <= '9')
n = n*10 + *s++ - '0';
return n;
}
void *memmove(void *vdst, const void *vsrc, int n) {
void*
memmove(void *vdst, const void *vsrc, int n)
{
char *dst;
const char *src;
dst = vdst;
src = vsrc;
if (src > dst) {
while (n-- > 0)
while(n-- > 0)
*dst++ = *src++;
} else {
dst += n;
src += n;
while (n-- > 0)
while(n-- > 0)
*--dst = *--src;
}
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;
while (n-- > 0) {
if (*p1 != *p2) {
@ -139,6 +140,8 @@ int memcmp(const void *s1, const void *s2, uint n) {
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);
}

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,44 +1,43 @@
#include "kernel/types.h"
struct stat;
// system calls
int fork(void);
int exit(int) __attribute__((noreturn));
int wait(int *);
int pipe(int *);
int write(int, const void *, int);
int read(int, void *, int);
int wait(int*);
int pipe(int*);
int write(int, const void*, int);
int read(int, void*, int);
int close(int);
int kill(int);
int exec(const char *, char **);
int open(const char *, int);
int mknod(const char *, short, short);
int unlink(const char *);
int fstat(int fd, struct stat *);
int link(const char *, const char *);
int mkdir(const char *);
int chdir(const char *);
int exec(const char*, char**);
int open(const char*, int);
int mknod(const char*, short, short);
int unlink(const char*);
int fstat(int fd, struct stat*);
int link(const char*, const char*);
int mkdir(const char*);
int chdir(const char*);
int dup(int);
int getpid(void);
char *sbrk(int);
char* sbrk(int);
int sleep(int);
int uptime(void);
// ulib.c
int stat(const char *, struct stat *);
char *strcpy(char *, const char *);
char *strncpy(char *, const char *, int);
void *memmove(void *, const void *, int);
char *strchr(const char *, char c);
int strcmp(const char *, const char *);
int strncmp(const char *, const char *, int);
void fprintf(int, const char *, ...);
void printf(const char *, ...);
char *gets(char *, int max);
uint strlen(const char *);
void *memset(void *, int, uint);
void *malloc(uint);
void free(void *);
int atoi(const char *);
int stat(const char*, struct stat*);
char* strcpy(char*, const char*);
void *memmove(void*, const void*, int);
char* strchr(const char*, char c);
int strcmp(const char*, const char*);
void fprintf(int, const char*, ...) __attribute__ ((format (printf, 2, 3)));
void printf(const char*, ...) __attribute__ ((format (printf, 1, 2)));
char* gets(char*, int max);
uint strlen(const char*);
void* memset(void*, int, uint);
int atoi(const char*);
int memcmp(const 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" )
ENTRY( _main )
SECTIONS
{
@ -15,9 +13,14 @@ SECTIONS
*(.srodata .srodata.*) /* do not need to distinguish this from .rodata */
. = ALIGN(16);
*(.rodata .rodata.*)
. = ALIGN(0x1000);
}
.eh_frame : {
*(.eh_frame)
*(.eh_frame.*)
}
. = ALIGN(0x1000);
.data : {
. = ALIGN(16);
*(.sdata .sdata.*) /* do not need to distinguish this from .data */

View File

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