Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c8bae855c5 | |||
| 66657d1ca0 | |||
| bc8921a77f | |||
| c6fa25504f | |||
| 7c42fbed17 | |||
| 70ee668b9b | |||
| c7c962ffef | |||
| 4c08583743 | |||
| b63d0c9147 | |||
| 028cf61d61 | |||
| 2a8fad821b | |||
| ccc7f1ac12 | |||
| 7b2491c658 | |||
| e12b8c1d32 | |||
| 19e38dc598 | |||
| b4bdc3e1db | |||
| 8fb0212778 | |||
| f0aaffb0b6 | |||
| bd21012f73 | |||
| 5292fdc6ac | |||
| 38997cbef6 | |||
| 0e751d690f | |||
| 2001e8e478 | |||
| e66ab82e63 | |||
| 992f76ca30 | |||
| a087b429df | |||
| d92eea9e49 | |||
| e33ff43dd6 | |||
| 07fc8a52bd | |||
| 962a7083da | |||
| a226786836 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -24,3 +24,5 @@ ph
|
||||
barrier
|
||||
/lab-*.json
|
||||
.DS_Store
|
||||
compile_commands.json
|
||||
|
||||
|
||||
5
.lldbinit
Normal file
5
.lldbinit
Normal 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
|
||||
2
LICENSE
2
LICENSE
@ -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
|
||||
|
||||
63
Makefile
63
Makefile
@ -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,15 +194,18 @@ UPROGS=\
|
||||
$U/_grind\
|
||||
$U/_wc\
|
||||
$U/_zombie\
|
||||
$U/_sleep\
|
||||
$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
|
||||
@ -229,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)
|
||||
@ -255,7 +264,7 @@ endif
|
||||
|
||||
ifeq ($(LAB),net)
|
||||
UPROGS += \
|
||||
$U/_nettests
|
||||
$U/_nettest
|
||||
endif
|
||||
|
||||
UEXTRA=
|
||||
@ -269,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
|
||||
@ -292,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
|
||||
@ -300,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
|
||||
|
||||
@ -318,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
|
||||
|
||||
##
|
||||
@ -340,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
35
README
@ -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
46
README.md
Normal 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".
|
||||
@ -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"
|
||||
}
|
||||
]
|
||||
@ -1 +1 @@
|
||||
LAB=util
|
||||
LAB=cow
|
||||
|
||||
159
cowlab.md
Normal file
159
cowlab.md
Normal 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 释放页时直接调用 kfree,kfree 内部已处理引用计数。
|
||||
|
||||
### 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
59
grade-lab-cow
Normal 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()
|
||||
@ -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()
|
||||
268
kernel/defs.h
268
kernel/defs.h
@ -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]))
|
||||
|
||||
@ -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++) {
|
||||
|
||||
43
kernel/fs.h
43
kernel/fs.h
@ -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];
|
||||
};
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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(;;)
|
||||
;
|
||||
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
53
kernel/vm.c
53
kernel/vm.c
@ -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)
|
||||
|
||||
@ -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));
|
||||
|
||||
21
user/cat.c
21
user/cat.c
@ -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
240
user/cowtest.c
Normal 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);
|
||||
}
|
||||
64
user/find.c
64
user/find.c
@ -1,64 +0,0 @@
|
||||
#include "kernel/fs.h"
|
||||
#include "kernel/stat.h"
|
||||
#include "kernel/types.h"
|
||||
#include "user/user.h"
|
||||
|
||||
void find(char *path, char *filename) {
|
||||
int fd = open(path, 0);
|
||||
char buf[512], *p;
|
||||
struct dirent de;
|
||||
struct stat st;
|
||||
|
||||
if (fd < 0 || strlen(path) + 1 + DIRSIZ + 1 >= sizeof(buf)) {
|
||||
fprintf(2, "find: Invalid path: %s\n", path);
|
||||
// close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fstat(fd, &st) < 0) {
|
||||
fprintf(2, "find: Failed to 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;
|
||||
}
|
||||
|
||||
strncpy(buf, path, strlen(path) + 1);
|
||||
p = buf + strlen(path);
|
||||
*p++ = '/';
|
||||
while (read(fd, &de, sizeof(de)) == sizeof(de)) {
|
||||
if (de.inum == 0)
|
||||
continue;
|
||||
if (!strcmp(de.name, ".") || !strcmp(de.name, ".."))
|
||||
continue;
|
||||
|
||||
memmove(p, de.name, DIRSIZ);
|
||||
p[DIRSIZ] = 0;
|
||||
|
||||
if (stat(buf, &st) < 0) {
|
||||
fprintf(2, "find: Failed to stat %s\n", buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (st.type == T_DIR) {
|
||||
find(buf, filename);
|
||||
} else if (st.type == T_FILE) {
|
||||
if (!strcmp(filename, "*") || !strcmp(filename, de.name)) {
|
||||
printf("%s\n", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc != 3) {
|
||||
printf("Usage: find path filename\n");
|
||||
exit(1);
|
||||
}
|
||||
find(argv[1], argv[2]);
|
||||
exit(0);
|
||||
}
|
||||
@ -24,5 +24,5 @@ init:
|
||||
# char *argv[] = { init, 0 };
|
||||
.p2align 2
|
||||
argv:
|
||||
.long init
|
||||
.long 0
|
||||
.quad init
|
||||
.quad 0
|
||||
|
||||
50
user/ls.c
50
user/ls.c
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
115
user/printf.c
115
user/printf.c
@ -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);
|
||||
|
||||
13
user/sleep.c
13
user/sleep.c
@ -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);
|
||||
}
|
||||
105
user/ulib.c
105
user/ulib.c
@ -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);
|
||||
}
|
||||
|
||||
57
user/user.h
57
user/user.h
@ -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*);
|
||||
|
||||
@ -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 */
|
||||
|
||||
123
user/usertests.c
123
user/usertests.c
@ -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");
|
||||
|
||||
|
||||
59
user/xargs.c
59
user/xargs.c
@ -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);
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
mkdir a
|
||||
echo hello > a/b
|
||||
mkdir c
|
||||
echo hello > c/b
|
||||
echo hello > b
|
||||
find . b | xargs grep hello
|
||||
Reference in New Issue
Block a user