From 8654300ef4e4968d7f39c1a024a3fdacb664d6c5 Mon Sep 17 00:00:00 2001 From: minhtrannhat Date: Sat, 1 Mar 2025 00:01:05 -0500 Subject: [PATCH] initial commit --- .gitignore | 2 + CHANGES | 1986 +++++++++++++ Makefile | 72 + common/gcc-millicode/README | 7 + common/gcc-millicode/adddi3.c | 56 + common/gcc-millicode/anddi3.c | 53 + common/gcc-millicode/ashldi3.c | 61 + common/gcc-millicode/ashrdi3.c | 73 + common/gcc-millicode/cmpdi2.c | 54 + common/gcc-millicode/divdi3.c | 62 + common/gcc-millicode/iordi3.c | 53 + common/gcc-millicode/longlong.h | 144 + common/gcc-millicode/lshldi3.c | 61 + common/gcc-millicode/lshrdi3.c | 60 + common/gcc-millicode/moddi3.c | 62 + common/gcc-millicode/muldi3.c | 241 ++ common/gcc-millicode/negdi2.c | 52 + common/gcc-millicode/notdi2.c | 53 + common/gcc-millicode/qdivrem.c | 279 ++ common/gcc-millicode/subdi3.c | 55 + common/gcc-millicode/ucmpdi2.c | 53 + common/gcc-millicode/udivdi3.c | 48 + common/gcc-millicode/umoddi3.c | 50 + common/gcc-millicode/xordi3.c | 53 + common/libc/arch/mips/setjmp.S | 104 + common/libc/printf/__printf.c | 592 ++++ common/libc/printf/snprintf.c | 157 + common/libc/stdlib/atoi.c | 101 + common/libc/string/bzero.c | 76 + common/libc/string/memcpy.c | 86 + common/libc/string/memmove.c | 117 + common/libc/string/memset.c | 52 + common/libc/string/strcat.c | 54 + common/libc/string/strchr.c | 68 + common/libc/string/strcmp.c | 90 + common/libc/string/strcpy.c | 63 + common/libc/string/strlen.c | 55 + common/libc/string/strrchr.c | 69 + common/libc/string/strtok_r.c | 96 + configure | 199 ++ defs.mk | 22 + design/assignments.txt | 120 + design/shell.txt | 55 + design/usermalloc.txt | 24 + kern/Makefile | 17 + kern/arch/mips/conf/conf.arch | 79 + kern/arch/mips/conf/ldscript | 98 + kern/arch/mips/include/current.h | 73 + kern/arch/mips/include/elf.h | 58 + kern/arch/mips/include/kern/endian.h | 44 + kern/arch/mips/include/kern/regdefs.h | 74 + kern/arch/mips/include/kern/setjmp.h | 47 + kern/arch/mips/include/kern/signal.h | 45 + kern/arch/mips/include/kern/types.h | 78 + kern/arch/mips/include/membar.h | 63 + kern/arch/mips/include/specialreg.h | 117 + kern/arch/mips/include/spinlock.h | 122 + kern/arch/mips/include/thread.h | 48 + kern/arch/mips/include/tlb.h | 105 + kern/arch/mips/include/trapframe.h | 108 + kern/arch/mips/include/types.h | 46 + kern/arch/mips/include/vm.h | 129 + kern/arch/mips/locore/cache-mips161.S | 49 + kern/arch/mips/locore/exception-mips1.S | 366 +++ kern/arch/mips/locore/trap.c | 438 +++ kern/arch/mips/syscall/syscall.c | 161 + kern/arch/mips/thread/cpu.c | 309 ++ kern/arch/mips/thread/switch.S | 99 + kern/arch/mips/thread/switchframe.c | 98 + kern/arch/mips/thread/switchframe.h | 52 + kern/arch/mips/thread/thread_machdep.c | 49 + kern/arch/mips/thread/threadstart.S | 68 + kern/arch/mips/vm/dumbvm.c | 427 +++ kern/arch/mips/vm/ram.c | 153 + kern/arch/mips/vm/tlb-mips161.S | 204 ++ kern/arch/sys161/conf/conf.arch | 34 + kern/arch/sys161/dev/lamebus_machdep.c | 344 +++ kern/arch/sys161/include/bus.h | 60 + kern/arch/sys161/include/maxcpus.h | 44 + kern/arch/sys161/main/start.S | 335 +++ kern/conf/DUMBVM | 34 + kern/conf/DUMBVM-OPT | 37 + kern/conf/GENERIC | 35 + kern/conf/GENERIC-OPT | 37 + kern/conf/conf.kern | 443 +++ kern/conf/config | 1068 +++++++ kern/conf/newvers.sh | 67 + kern/dev/generic/beep.c | 71 + kern/dev/generic/beep.h | 43 + kern/dev/generic/console.c | 397 +++ kern/dev/generic/console.h | 68 + kern/dev/generic/random.c | 158 + kern/dev/generic/random.h | 46 + kern/dev/generic/rtclock.c | 70 + kern/dev/generic/rtclock.h | 45 + kern/dev/lamebus/beep_ltimer.c | 55 + kern/dev/lamebus/con_lscreen.c | 59 + kern/dev/lamebus/con_lser.c | 61 + kern/dev/lamebus/conf.lamebus | 57 + kern/dev/lamebus/emu.c | 1357 +++++++++ kern/dev/lamebus/emu.h | 62 + kern/dev/lamebus/emu_att.c | 66 + kern/dev/lamebus/lamebus.c | 665 +++++ kern/dev/lamebus/lamebus.h | 182 ++ kern/dev/lamebus/lhd.c | 308 ++ kern/dev/lamebus/lhd.h | 64 + kern/dev/lamebus/lhd_att.c | 69 + kern/dev/lamebus/lnet.c | 46 + kern/dev/lamebus/lnet_att.c | 52 + kern/dev/lamebus/lrandom.c | 85 + kern/dev/lamebus/lrandom.h | 46 + kern/dev/lamebus/lrandom_att.c | 62 + kern/dev/lamebus/lscreen.c | 225 ++ kern/dev/lamebus/lscreen.h | 59 + kern/dev/lamebus/lscreen_att.c | 70 + kern/dev/lamebus/lser.c | 192 ++ kern/dev/lamebus/lser.h | 57 + kern/dev/lamebus/lser_att.c | 63 + kern/dev/lamebus/ltimer.c | 187 ++ kern/dev/lamebus/ltimer.h | 56 + kern/dev/lamebus/ltimer_att.c | 70 + kern/dev/lamebus/ltrace.c | 116 + kern/dev/lamebus/ltrace.h | 90 + kern/dev/lamebus/ltrace_att.c | 69 + kern/dev/lamebus/random_lrandom.c | 57 + kern/dev/lamebus/rtclock_ltimer.c | 66 + kern/fs/semfs/semfs.h | 123 + kern/fs/semfs/semfs_fsops.c | 226 ++ kern/fs/semfs/semfs_obj.c | 145 + kern/fs/semfs/semfs_vnops.c | 799 +++++ kern/fs/sfs/sfs_balloc.c | 103 + kern/fs/sfs/sfs_bmap.c | 303 ++ kern/fs/sfs/sfs_dir.c | 239 ++ kern/fs/sfs/sfs_fsops.c | 481 +++ kern/fs/sfs/sfs_inode.c | 320 ++ kern/fs/sfs/sfs_io.c | 480 +++ kern/fs/sfs/sfs_vnops.c | 650 +++++ kern/fs/sfs/sfsprivate.h | 81 + kern/gdbscripts/array | 79 + kern/gdbscripts/mips-userland | 40 + kern/gdbscripts/wchan | 85 + kern/include/addrspace.h | 132 + kern/include/array.h | 269 ++ kern/include/bitmap.h | 59 + kern/include/cdefs.h | 141 + kern/include/clock.h | 83 + kern/include/copyinout.h | 73 + kern/include/cpu.h | 176 ++ kern/include/current.h | 93 + kern/include/device.h | 87 + kern/include/elf.h | 200 ++ kern/include/emufs.h | 58 + kern/include/endian.h | 55 + kern/include/fs.h | 91 + kern/include/hangman.h | 84 + kern/include/kern/endian.h | 50 + kern/include/kern/errmsg.h | 114 + kern/include/kern/errno.h | 111 + kern/include/kern/fcntl.h | 100 + kern/include/kern/ioctl.h | 39 + kern/include/kern/iovec.h | 68 + kern/include/kern/limits.h | 109 + kern/include/kern/reboot.h | 45 + kern/include/kern/resource.h | 92 + kern/include/kern/seek.h | 47 + kern/include/kern/sfs.h | 101 + kern/include/kern/signal.h | 131 + kern/include/kern/socket.h | 116 + kern/include/kern/stat.h | 71 + kern/include/kern/stattypes.h | 55 + kern/include/kern/syscall.h | 203 ++ kern/include/kern/time.h | 70 + kern/include/kern/types.h | 92 + kern/include/kern/unistd.h | 39 + kern/include/kern/wait.h | 79 + kern/include/lib.h | 198 ++ kern/include/limits.h | 52 + kern/include/mainbus.h | 73 + kern/include/membar.h | 93 + kern/include/proc.h | 101 + kern/include/setjmp.h | 44 + kern/include/sfs.h | 80 + kern/include/signal.h | 39 + kern/include/spinlock.h | 95 + kern/include/spl.h | 109 + kern/include/stat.h | 50 + kern/include/stdarg.h | 79 + kern/include/synch.h | 142 + kern/include/syscall.h | 62 + kern/include/test.h | 108 + kern/include/thread.h | 173 ++ kern/include/threadlist.h | 105 + kern/include/threadprivate.h | 78 + kern/include/types.h | 155 + kern/include/uio.h | 142 + kern/include/version.h | 45 + kern/include/vfs.h | 205 ++ kern/include/vm.h | 62 + kern/include/vnode.h | 316 ++ kern/include/wchan.h | 80 + kern/lib/array.c | 135 + kern/lib/bitmap.c | 176 ++ kern/lib/bswap.c | 161 + kern/lib/kgets.c | 113 + kern/lib/kprintf.c | 216 ++ kern/lib/misc.c | 62 + kern/lib/time.c | 69 + kern/lib/uio.c | 164 ++ kern/main/main.c | 216 ++ kern/main/menu.c | 827 ++++++ kern/proc/proc.c | 320 ++ kern/syscall/loadelf.c | 307 ++ kern/syscall/runprogram.c | 109 + kern/syscall/time_syscalls.c | 58 + kern/test/arraytest.c | 220 ++ kern/test/bitmaptest.c | 106 + kern/test/fstest.c | 784 +++++ kern/test/kmalloctest.c | 380 +++ kern/test/nettest.c | 44 + kern/test/semunit.c | 820 ++++++ kern/test/synchtest.c | 401 +++ kern/test/threadlisttest.c | 343 +++ kern/test/threadtest.c | 146 + kern/test/tt3.c | 276 ++ kern/thread/clock.c | 121 + kern/thread/hangman.c | 182 ++ kern/thread/spinlock.c | 156 + kern/thread/spl.c | 160 + kern/thread/synch.c | 269 ++ kern/thread/thread.c | 1212 ++++++++ kern/thread/threadlist.c | 240 ++ kern/vfs/device.c | 388 +++ kern/vfs/devnull.c | 124 + kern/vfs/vfscwd.c | 184 ++ kern/vfs/vfsfail.c | 264 ++ kern/vfs/vfslist.c | 786 +++++ kern/vfs/vfslookup.c | 300 ++ kern/vfs/vfspath.c | 316 ++ kern/vfs/vnode.c | 178 ++ kern/vm/addrspace.c | 182 ++ kern/vm/copyinout.c | 321 ++ kern/vm/kmalloc.c | 1224 ++++++++ man/Makefile | 16 + man/bin/Makefile | 13 + man/bin/cat.html | 81 + man/bin/cp.html | 88 + man/bin/false.html | 69 + man/bin/index.html | 67 + man/bin/ln.html | 99 + man/bin/ls.html | 110 + man/bin/mkdir.html | 81 + man/bin/mv.html | 98 + man/bin/pwd.html | 77 + man/bin/rm.html | 91 + man/bin/rmdir.html | 90 + man/bin/sh.html | 77 + man/bin/sync.html | 66 + man/bin/tac.html | 87 + man/bin/true.html | 69 + man/dev/Makefile | 13 + man/dev/beep.html | 62 + man/dev/con.html | 73 + man/dev/emu.html | 83 + man/dev/index.html | 67 + man/dev/lamebus.html | 68 + man/dev/lhd.html | 65 + man/dev/lnet.html | 62 + man/dev/lrandom.html | 64 + man/dev/lscreen.html | 72 + man/dev/lser.html | 67 + man/dev/ltimer.html | 65 + man/dev/ltrace.html | 74 + man/dev/null.html | 55 + man/dev/random.html | 73 + man/dev/rtclock.html | 65 + man/index.html | 50 + man/libc/Makefile | 17 + man/libc/__vprintf.html | 97 + man/libc/abort.html | 68 + man/libc/assert.html | 74 + man/libc/atoi.html | 73 + man/libc/bzero.html | 71 + man/libc/calloc.html | 84 + man/libc/err.html | 104 + man/libc/execvp.html | 100 + man/libc/exit.html | 69 + man/libc/free.html | 104 + man/libc/getchar.html | 76 + man/libc/getcwd.html | 100 + man/libc/getenv.html | 82 + man/libc/index.html | 96 + man/libc/malloc.html | 108 + man/libc/memcmp.html | 81 + man/libc/memcpy.html | 76 + man/libc/memmove.html | 75 + man/libc/memset.html | 82 + man/libc/printf.html | 143 + man/libc/putchar.html | 75 + man/libc/puts.html | 76 + man/libc/random.html | 89 + man/libc/realloc.html | 104 + man/libc/setjmp.html | 85 + man/libc/snprintf.html | 84 + man/libc/stdarg.html | 126 + man/libc/strcat.html | 80 + man/libc/strchr.html | 72 + man/libc/strcmp.html | 80 + man/libc/strcpy.html | 80 + man/libc/strerror.html | 75 + man/libc/strlen.html | 63 + man/libc/strrchr.html | 72 + man/libc/strtok.html | 101 + man/libc/strtok_r.html | 81 + man/libc/system.html | 91 + man/libc/time.html | 88 + man/libc/warn.html | 99 + man/man.css | 93 + man/manindex.css | 78 + man/misc/Makefile | 10 + man/misc/index.html | 54 + man/misc/semfs.html | 87 + man/sbin/Makefile | 10 + man/sbin/dumpsfs.html | 102 + man/sbin/halt.html | 82 + man/sbin/index.html | 60 + man/sbin/mksfs.html | 113 + man/sbin/poweroff.html | 73 + man/sbin/reboot.html | 73 + man/sbin/sfsck.html | 113 + man/syscall/Makefile | 16 + man/syscall/__getcwd.html | 109 + man/syscall/__time.html | 89 + man/syscall/_exit.html | 78 + man/syscall/chdir.html | 97 + man/syscall/close.html | 96 + man/syscall/dup2.html | 134 + man/syscall/errno.html | 435 +++ man/syscall/execv.html | 171 ++ man/syscall/fork.html | 112 + man/syscall/fstat.html | 99 + man/syscall/fsync.html | 90 + man/syscall/ftruncate.html | 99 + man/syscall/getdirentry.html | 125 + man/syscall/getpid.html | 67 + man/syscall/index.html | 91 + man/syscall/ioctl.html | 106 + man/syscall/link.html | 106 + man/syscall/lseek.html | 135 + man/syscall/lstat.html | 112 + man/syscall/mkdir.html | 106 + man/syscall/open.html | 176 ++ man/syscall/pipe.html | 120 + man/syscall/read.html | 115 + man/syscall/readlink.html | 104 + man/syscall/reboot.html | 93 + man/syscall/remove.html | 107 + man/syscall/rename.html | 155 + man/syscall/rmdir.html | 133 + man/syscall/sbrk.html | 144 + man/syscall/stat.html | 103 + man/syscall/symlink.html | 107 + man/syscall/sync.html | 73 + man/syscall/waitpid.html | 204 ++ man/syscall/write.html | 120 + man/testbin/Makefile | 17 + man/testbin/add.html | 67 + man/testbin/argtest.html | 68 + man/testbin/badcall.html | 101 + man/testbin/bigexec.html | 80 + man/testbin/bigfile.html | 79 + man/testbin/bigfork.html | 88 + man/testbin/bigseek.html | 80 + man/testbin/bloat.html | 108 + man/testbin/conman.html | 68 + man/testbin/crash.html | 90 + man/testbin/ctest.html | 80 + man/testbin/dirconc.html | 90 + man/testbin/dirseek.html | 79 + man/testbin/dirtest.html | 71 + man/testbin/f_test.html | 92 + man/testbin/factorial.html | 89 + man/testbin/farm.html | 90 + man/testbin/faulter.html | 70 + man/testbin/filetest.html | 79 + man/testbin/forkbomb.html | 96 + man/testbin/forktest.html | 72 + man/testbin/frack.html | 160 + man/testbin/guzzle.html | 70 + man/testbin/hash.html | 84 + man/testbin/hog.html | 65 + man/testbin/huge.html | 72 + man/testbin/index.html | 110 + man/testbin/kitchen.html | 80 + man/testbin/malloctest.html | 116 + man/testbin/matmult.html | 76 + man/testbin/multiexec.html | 116 + man/testbin/palin.html | 76 + man/testbin/parallelvm.html | 115 + man/testbin/poisondisk.html | 98 + man/testbin/psort.html | 127 + man/testbin/quinthuge.html | 70 + man/testbin/quintmat.html | 71 + man/testbin/quintsort.html | 70 + man/testbin/randcall.html | 102 + man/testbin/redirect.html | 95 + man/testbin/rmdirtest.html | 85 + man/testbin/rmtest.html | 93 + man/testbin/sbrktest.html | 134 + man/testbin/schedpong.html | 149 + man/testbin/sink.html | 71 + man/testbin/sort.html | 70 + man/testbin/sparsefile.html | 77 + man/testbin/sty.html | 74 + man/testbin/tail.html | 79 + man/testbin/tictac.html | 69 + man/testbin/triplehuge.html | 70 + man/testbin/triplemat.html | 71 + man/testbin/triplesort.html | 70 + man/testbin/usemtest.html | 87 + man/testbin/userthreads.html | 75 + man/testbin/zero.html | 78 + mk/fixdepends.sh | 83 + mk/installheaders.sh | 20 + mk/os161.baserules.mk | 78 + mk/os161.compile.mk | 75 + mk/os161.config-mips.mk | 32 + mk/os161.config.mk | 485 +++ mk/os161.hostcompile.mk | 75 + mk/os161.hostlib.mk | 78 + mk/os161.hostprog.mk | 109 + mk/os161.includes.mk | 56 + mk/os161.kernel.mk | 217 ++ mk/os161.lib.mk | 84 + mk/os161.man.mk | 69 + mk/os161.mkdirs.mk | 59 + mk/os161.prog.mk | 85 + mk/os161.script.mk | 92 + mk/os161.subdir.mk | 51 + testscripts/Makefile | 12 + testscripts/runtest.py | 202 ++ testscripts/test.py | 113 + userland/Makefile | 28 + userland/bin/Makefile | 10 + userland/bin/cat/Makefile | 12 + userland/bin/cat/cat.c | 120 + userland/bin/cp/Makefile | 12 + userland/bin/cp/cp.c | 113 + userland/bin/false/Makefile | 12 + userland/bin/false/false.c | 45 + userland/bin/ln/Makefile | 12 + userland/bin/ln/ln.c | 93 + userland/bin/ls/Makefile | 12 + userland/bin/ls/ls.c | 345 +++ userland/bin/mkdir/Makefile | 12 + userland/bin/mkdir/mkdir.c | 53 + userland/bin/mv/Makefile | 12 + userland/bin/mv/mv.c | 64 + userland/bin/pwd/Makefile | 12 + userland/bin/pwd/pwd.c | 55 + userland/bin/rm/Makefile | 12 + userland/bin/rm/rm.c | 64 + userland/bin/rmdir/Makefile | 12 + userland/bin/rmdir/rmdir.c | 51 + userland/bin/sh/Makefile | 13 + userland/bin/sh/sh.c | 591 ++++ userland/bin/sync/Makefile | 12 + userland/bin/sync/sync.c | 43 + userland/bin/tac/Makefile | 12 + userland/bin/tac/tac.c | 292 ++ userland/bin/true/Makefile | 12 + userland/bin/true/true.c | 42 + userland/include/assert.h | 60 + userland/include/err.h | 58 + userland/include/errno.h | 39 + userland/include/fcntl.h | 31 + userland/include/limits.h | 53 + userland/include/setjmp.h | 52 + userland/include/signal.h | 30 + userland/include/stdarg.h | 54 + userland/include/stdbool.h | 37 + userland/include/stdint.h | 51 + userland/include/stdio.h | 72 + userland/include/stdlib.h | 85 + userland/include/string.h | 65 + userland/include/sys/cdefs.h | 45 + userland/include/sys/endian.h | 35 + userland/include/sys/ioctl.h | 31 + userland/include/sys/null.h | 39 + userland/include/sys/reboot.h | 31 + userland/include/sys/stat.h | 83 + userland/include/sys/types.h | 87 + userland/include/sys/wait.h | 31 + userland/include/test/quint.h | 30 + userland/include/test/triple.h | 30 + userland/include/time.h | 31 + userland/include/types/size_t.h | 36 + userland/include/unistd.h | 162 ++ userland/lib/Makefile | 13 + userland/lib/crt0/Makefile | 27 + userland/lib/crt0/mips/crt0.S | 97 + userland/lib/hostcompat/Makefile | 55 + userland/lib/hostcompat/err.c | 167 ++ userland/lib/hostcompat/host-err.h | 58 + userland/lib/hostcompat/hostcompat.c | 238 ++ userland/lib/hostcompat/hostcompat.h | 41 + userland/lib/hostcompat/ntohll.c | 53 + userland/lib/hostcompat/time.c | 54 + userland/lib/libc/Makefile | 132 + userland/lib/libc/arch/mips/syscalls-mips.S | 95 + userland/lib/libc/stdio/__puts.c | 53 + userland/lib/libc/stdio/getchar.c | 56 + userland/lib/libc/stdio/printf.c | 78 + userland/lib/libc/stdio/putchar.c | 50 + userland/lib/libc/stdio/puts.c | 42 + userland/lib/libc/stdlib/abort.c | 45 + userland/lib/libc/stdlib/exit.c | 83 + userland/lib/libc/stdlib/getenv.c | 78 + userland/lib/libc/stdlib/malloc.c | 591 ++++ userland/lib/libc/stdlib/qsort.c | 145 + userland/lib/libc/stdlib/random.c | 453 +++ userland/lib/libc/stdlib/system.c | 91 + userland/lib/libc/string/memcmp.c | 50 + userland/lib/libc/string/strerror.c | 43 + userland/lib/libc/string/strtok.c | 38 + userland/lib/libc/syscalls/gensyscalls.sh | 25 + userland/lib/libc/time/time.c | 42 + userland/lib/libc/unix/__assert.c | 50 + userland/lib/libc/unix/err.c | 191 ++ userland/lib/libc/unix/errno.c | 45 + userland/lib/libc/unix/execvp.c | 91 + userland/lib/libc/unix/getcwd.c | 56 + userland/lib/libtest/Makefile | 11 + userland/lib/libtest/triple.c | 111 + userland/sbin/Makefile | 10 + userland/sbin/dumpsfs/Makefile | 15 + userland/sbin/dumpsfs/dumpsfs.c | 607 ++++ userland/sbin/halt/Makefile | 12 + userland/sbin/halt/halt.c | 44 + userland/sbin/mksfs/Makefile | 13 + userland/sbin/mksfs/disk.c | 200 ++ userland/sbin/mksfs/disk.h | 38 + userland/sbin/mksfs/mksfs.c | 240 ++ userland/sbin/mksfs/support.c | 34 + userland/sbin/mksfs/support.h | 64 + userland/sbin/poweroff/Makefile | 11 + userland/sbin/poweroff/poweroff.c | 44 + userland/sbin/reboot/Makefile | 11 + userland/sbin/reboot/reboot.c | 44 + userland/sbin/sfsck/Makefile | 18 + userland/sbin/sfsck/compat.h | 64 + userland/sbin/sfsck/freemap.c | 310 ++ userland/sbin/sfsck/freemap.h | 67 + userland/sbin/sfsck/ibmacros.h | 159 + userland/sbin/sfsck/inode.c | 266 ++ userland/sbin/sfsck/inode.h | 65 + userland/sbin/sfsck/main.c | 118 + userland/sbin/sfsck/main.h | 48 + userland/sbin/sfsck/pass1.c | 496 ++++ userland/sbin/sfsck/pass2.c | 325 +++ userland/sbin/sfsck/passes.h | 51 + userland/sbin/sfsck/sb.c | 124 + userland/sbin/sfsck/sb.h | 55 + userland/sbin/sfsck/sfs.c | 464 +++ userland/sbin/sfsck/sfs.h | 81 + userland/sbin/sfsck/utils.c | 144 + userland/sbin/sfsck/utils.h | 52 + userland/testbin/Makefile | 19 + userland/testbin/add/Makefile | 11 + userland/testbin/add/add.c | 57 + userland/testbin/argtest/Makefile | 11 + userland/testbin/argtest/argtest.c | 57 + userland/testbin/badcall/Makefile | 43 + userland/testbin/badcall/bad_chdir.c | 61 + userland/testbin/badcall/bad_close.c | 40 + userland/testbin/badcall/bad_dup2.c | 142 + userland/testbin/badcall/bad_execv.c | 181 ++ userland/testbin/badcall/bad_fsync.c | 41 + userland/testbin/badcall/bad_ftruncate.c | 95 + userland/testbin/badcall/bad_getcwd.c | 40 + userland/testbin/badcall/bad_getdirentry.c | 41 + userland/testbin/badcall/bad_ioctl.c | 103 + userland/testbin/badcall/bad_link.c | 88 + userland/testbin/badcall/bad_lseek.c | 278 ++ userland/testbin/badcall/bad_mkdir.c | 87 + userland/testbin/badcall/bad_open.c | 78 + userland/testbin/badcall/bad_pipe.c | 86 + userland/testbin/badcall/bad_read.c | 42 + userland/testbin/badcall/bad_readlink.c | 92 + userland/testbin/badcall/bad_reboot.c | 62 + userland/testbin/badcall/bad_remove.c | 106 + userland/testbin/badcall/bad_rename.c | 111 + userland/testbin/badcall/bad_rmdir.c | 104 + userland/testbin/badcall/bad_sbrk.c | 125 + userland/testbin/badcall/bad_stat.c | 128 + userland/testbin/badcall/bad_symlink.c | 68 + userland/testbin/badcall/bad_time.c | 76 + userland/testbin/badcall/bad_waitpid.c | 423 +++ userland/testbin/badcall/bad_write.c | 41 + userland/testbin/badcall/common_buf.c | 219 ++ userland/testbin/badcall/common_fds.c | 234 ++ userland/testbin/badcall/common_path.c | 213 ++ userland/testbin/badcall/config.h | 60 + userland/testbin/badcall/driver.c | 289 ++ userland/testbin/badcall/report.c | 350 +++ userland/testbin/badcall/test.h | 124 + userland/testbin/bigexec/Makefile | 11 + userland/testbin/bigexec/bigexec.c | 387 +++ userland/testbin/bigfile/Makefile | 11 + userland/testbin/bigfile/bigfile.c | 107 + userland/testbin/bigfork/Makefile | 11 + userland/testbin/bigfork/bigfork.c | 239 ++ userland/testbin/bigseek/Makefile | 11 + userland/testbin/bigseek/bigseek.c | 270 ++ userland/testbin/bloat/Makefile | 11 + userland/testbin/bloat/bloat.c | 204 ++ userland/testbin/conman/Makefile | 11 + userland/testbin/conman/conman.c | 58 + userland/testbin/crash/Makefile | 11 + userland/testbin/crash/crash.c | 388 +++ userland/testbin/ctest/Makefile | 11 + userland/testbin/ctest/ctest.c | 101 + userland/testbin/dirconc/Makefile | 11 + userland/testbin/dirconc/dirconc.c | 362 +++ userland/testbin/dirseek/Makefile | 11 + userland/testbin/dirseek/dirseek.c | 555 ++++ userland/testbin/dirtest/Makefile | 11 + userland/testbin/dirtest/dirtest.c | 86 + userland/testbin/f_test/Makefile | 11 + userland/testbin/f_test/f_hdr.h | 31 + userland/testbin/f_test/f_read.c | 106 + userland/testbin/f_test/f_test.c | 348 +++ userland/testbin/f_test/f_write.c | 85 + userland/testbin/factorial/Makefile | 11 + userland/testbin/factorial/factorial.c | 263 ++ userland/testbin/farm/Makefile | 11 + userland/testbin/farm/farm.c | 111 + userland/testbin/faulter/Makefile | 11 + userland/testbin/faulter/faulter.c | 56 + userland/testbin/filetest/Makefile | 11 + userland/testbin/filetest/filetest.c | 108 + userland/testbin/forkbomb/Makefile | 11 + userland/testbin/forkbomb/forkbomb.c | 76 + userland/testbin/forktest/Makefile | 11 + userland/testbin/forktest/forktest.c | 217 ++ userland/testbin/frack/Makefile | 11 + userland/testbin/frack/check.c | 2911 +++++++++++++++++++ userland/testbin/frack/check.h | 51 + userland/testbin/frack/data.c | 227 ++ userland/testbin/frack/data.h | 41 + userland/testbin/frack/do.c | 251 ++ userland/testbin/frack/do.h | 48 + userland/testbin/frack/main.c | 196 ++ userland/testbin/frack/main.h | 32 + userland/testbin/frack/name.c | 93 + userland/testbin/frack/name.h | 33 + userland/testbin/frack/ops.c | 315 ++ userland/testbin/frack/ops.h | 48 + userland/testbin/frack/pool.c | 70 + userland/testbin/frack/pool.h | 57 + userland/testbin/frack/workloads.c | 1794 ++++++++++++ userland/testbin/frack/workloads.h | 153 + userland/testbin/hash/Makefile | 13 + userland/testbin/hash/hash.c | 83 + userland/testbin/hog/Makefile | 12 + userland/testbin/hog/hog.c | 53 + userland/testbin/huge/Makefile | 11 + userland/testbin/huge/huge.c | 84 + userland/testbin/malloctest/Makefile | 11 + userland/testbin/malloctest/malloctest.c | 694 +++++ userland/testbin/matmult/Makefile | 12 + userland/testbin/matmult/matmult-orig.c | 88 + userland/testbin/matmult/matmult.c | 90 + userland/testbin/multiexec/Makefile | 12 + userland/testbin/multiexec/multiexec.c | 272 ++ userland/testbin/palin/Makefile | 12 + userland/testbin/palin/palin.c | 198 ++ userland/testbin/parallelvm/Makefile | 12 + userland/testbin/parallelvm/parallelvm.c | 425 +++ userland/testbin/poisondisk/Makefile | 16 + userland/testbin/poisondisk/poisondisk.c | 74 + userland/testbin/psort/Makefile | 13 + userland/testbin/psort/psort.c | 1225 ++++++++ userland/testbin/randcall/Makefile | 24 + userland/testbin/randcall/callspecs.txt | 26 + userland/testbin/randcall/extern.h | 37 + userland/testbin/randcall/gencalls.sh | 143 + userland/testbin/randcall/main.c | 166 ++ userland/testbin/redirect/Makefile | 11 + userland/testbin/redirect/redirect.c | 197 ++ userland/testbin/rmdirtest/Makefile | 11 + userland/testbin/rmdirtest/rmdirtest.c | 404 +++ userland/testbin/rmtest/Makefile | 11 + userland/testbin/rmtest/rmtest.c | 163 ++ userland/testbin/sbrktest/Makefile | 11 + userland/testbin/sbrktest/sbrktest.c | 1148 ++++++++ userland/testbin/schedpong/Makefile | 11 + userland/testbin/schedpong/grind.c | 205 ++ userland/testbin/schedpong/main.c | 319 ++ userland/testbin/schedpong/pong.c | 211 ++ userland/testbin/schedpong/results.c | 169 ++ userland/testbin/schedpong/results.h | 36 + userland/testbin/schedpong/tasks.h | 38 + userland/testbin/schedpong/think.c | 55 + userland/testbin/schedpong/usem.c | 127 + userland/testbin/schedpong/usem.h | 53 + userland/testbin/sort/Makefile | 11 + userland/testbin/sort/sort.c | 135 + userland/testbin/sparsefile/Makefile | 11 + userland/testbin/sparsefile/sparsefile.c | 87 + userland/testbin/tail/Makefile | 11 + userland/testbin/tail/tail.c | 81 + userland/testbin/tictac/Makefile | 11 + userland/testbin/tictac/tictac.c | 397 +++ userland/testbin/triplehuge/Makefile | 12 + userland/testbin/triplehuge/triplehuge.c | 45 + userland/testbin/triplemat/Makefile | 11 + userland/testbin/triplemat/triplemat.c | 45 + userland/testbin/triplesort/Makefile | 11 + userland/testbin/triplesort/triplesort.c | 45 + userland/testbin/usemtest/Makefile | 13 + userland/testbin/usemtest/usemtest.c | 389 +++ userland/testbin/userthreads/Makefile | 11 + userland/testbin/userthreads/userthreads.c | 109 + userland/testbin/zero/Makefile | 11 + userland/testbin/zero/zero.c | 145 + 725 files changed, 94011 insertions(+) create mode 100644 .gitignore create mode 100644 CHANGES create mode 100644 Makefile create mode 100644 common/gcc-millicode/README create mode 100644 common/gcc-millicode/adddi3.c create mode 100644 common/gcc-millicode/anddi3.c create mode 100644 common/gcc-millicode/ashldi3.c create mode 100644 common/gcc-millicode/ashrdi3.c create mode 100644 common/gcc-millicode/cmpdi2.c create mode 100644 common/gcc-millicode/divdi3.c create mode 100644 common/gcc-millicode/iordi3.c create mode 100644 common/gcc-millicode/longlong.h create mode 100644 common/gcc-millicode/lshldi3.c create mode 100644 common/gcc-millicode/lshrdi3.c create mode 100644 common/gcc-millicode/moddi3.c create mode 100644 common/gcc-millicode/muldi3.c create mode 100644 common/gcc-millicode/negdi2.c create mode 100644 common/gcc-millicode/notdi2.c create mode 100644 common/gcc-millicode/qdivrem.c create mode 100644 common/gcc-millicode/subdi3.c create mode 100644 common/gcc-millicode/ucmpdi2.c create mode 100644 common/gcc-millicode/udivdi3.c create mode 100644 common/gcc-millicode/umoddi3.c create mode 100644 common/gcc-millicode/xordi3.c create mode 100644 common/libc/arch/mips/setjmp.S create mode 100644 common/libc/printf/__printf.c create mode 100644 common/libc/printf/snprintf.c create mode 100644 common/libc/stdlib/atoi.c create mode 100644 common/libc/string/bzero.c create mode 100644 common/libc/string/memcpy.c create mode 100644 common/libc/string/memmove.c create mode 100644 common/libc/string/memset.c create mode 100644 common/libc/string/strcat.c create mode 100644 common/libc/string/strchr.c create mode 100644 common/libc/string/strcmp.c create mode 100644 common/libc/string/strcpy.c create mode 100644 common/libc/string/strlen.c create mode 100644 common/libc/string/strrchr.c create mode 100644 common/libc/string/strtok_r.c create mode 100755 configure create mode 100644 defs.mk create mode 100644 design/assignments.txt create mode 100644 design/shell.txt create mode 100644 design/usermalloc.txt create mode 100644 kern/Makefile create mode 100644 kern/arch/mips/conf/conf.arch create mode 100644 kern/arch/mips/conf/ldscript create mode 100644 kern/arch/mips/include/current.h create mode 100644 kern/arch/mips/include/elf.h create mode 100644 kern/arch/mips/include/kern/endian.h create mode 100644 kern/arch/mips/include/kern/regdefs.h create mode 100644 kern/arch/mips/include/kern/setjmp.h create mode 100644 kern/arch/mips/include/kern/signal.h create mode 100644 kern/arch/mips/include/kern/types.h create mode 100644 kern/arch/mips/include/membar.h create mode 100644 kern/arch/mips/include/specialreg.h create mode 100644 kern/arch/mips/include/spinlock.h create mode 100644 kern/arch/mips/include/thread.h create mode 100644 kern/arch/mips/include/tlb.h create mode 100644 kern/arch/mips/include/trapframe.h create mode 100644 kern/arch/mips/include/types.h create mode 100644 kern/arch/mips/include/vm.h create mode 100644 kern/arch/mips/locore/cache-mips161.S create mode 100644 kern/arch/mips/locore/exception-mips1.S create mode 100644 kern/arch/mips/locore/trap.c create mode 100644 kern/arch/mips/syscall/syscall.c create mode 100644 kern/arch/mips/thread/cpu.c create mode 100644 kern/arch/mips/thread/switch.S create mode 100644 kern/arch/mips/thread/switchframe.c create mode 100644 kern/arch/mips/thread/switchframe.h create mode 100644 kern/arch/mips/thread/thread_machdep.c create mode 100644 kern/arch/mips/thread/threadstart.S create mode 100644 kern/arch/mips/vm/dumbvm.c create mode 100644 kern/arch/mips/vm/ram.c create mode 100644 kern/arch/mips/vm/tlb-mips161.S create mode 100644 kern/arch/sys161/conf/conf.arch create mode 100644 kern/arch/sys161/dev/lamebus_machdep.c create mode 100644 kern/arch/sys161/include/bus.h create mode 100644 kern/arch/sys161/include/maxcpus.h create mode 100644 kern/arch/sys161/main/start.S create mode 100644 kern/conf/DUMBVM create mode 100644 kern/conf/DUMBVM-OPT create mode 100644 kern/conf/GENERIC create mode 100644 kern/conf/GENERIC-OPT create mode 100644 kern/conf/conf.kern create mode 100755 kern/conf/config create mode 100755 kern/conf/newvers.sh create mode 100644 kern/dev/generic/beep.c create mode 100644 kern/dev/generic/beep.h create mode 100644 kern/dev/generic/console.c create mode 100644 kern/dev/generic/console.h create mode 100644 kern/dev/generic/random.c create mode 100644 kern/dev/generic/random.h create mode 100644 kern/dev/generic/rtclock.c create mode 100644 kern/dev/generic/rtclock.h create mode 100644 kern/dev/lamebus/beep_ltimer.c create mode 100644 kern/dev/lamebus/con_lscreen.c create mode 100644 kern/dev/lamebus/con_lser.c create mode 100644 kern/dev/lamebus/conf.lamebus create mode 100644 kern/dev/lamebus/emu.c create mode 100644 kern/dev/lamebus/emu.h create mode 100644 kern/dev/lamebus/emu_att.c create mode 100644 kern/dev/lamebus/lamebus.c create mode 100644 kern/dev/lamebus/lamebus.h create mode 100644 kern/dev/lamebus/lhd.c create mode 100644 kern/dev/lamebus/lhd.h create mode 100644 kern/dev/lamebus/lhd_att.c create mode 100644 kern/dev/lamebus/lnet.c create mode 100644 kern/dev/lamebus/lnet_att.c create mode 100644 kern/dev/lamebus/lrandom.c create mode 100644 kern/dev/lamebus/lrandom.h create mode 100644 kern/dev/lamebus/lrandom_att.c create mode 100644 kern/dev/lamebus/lscreen.c create mode 100644 kern/dev/lamebus/lscreen.h create mode 100644 kern/dev/lamebus/lscreen_att.c create mode 100644 kern/dev/lamebus/lser.c create mode 100644 kern/dev/lamebus/lser.h create mode 100644 kern/dev/lamebus/lser_att.c create mode 100644 kern/dev/lamebus/ltimer.c create mode 100644 kern/dev/lamebus/ltimer.h create mode 100644 kern/dev/lamebus/ltimer_att.c create mode 100644 kern/dev/lamebus/ltrace.c create mode 100644 kern/dev/lamebus/ltrace.h create mode 100644 kern/dev/lamebus/ltrace_att.c create mode 100644 kern/dev/lamebus/random_lrandom.c create mode 100644 kern/dev/lamebus/rtclock_ltimer.c create mode 100644 kern/fs/semfs/semfs.h create mode 100644 kern/fs/semfs/semfs_fsops.c create mode 100644 kern/fs/semfs/semfs_obj.c create mode 100644 kern/fs/semfs/semfs_vnops.c create mode 100644 kern/fs/sfs/sfs_balloc.c create mode 100644 kern/fs/sfs/sfs_bmap.c create mode 100644 kern/fs/sfs/sfs_dir.c create mode 100644 kern/fs/sfs/sfs_fsops.c create mode 100644 kern/fs/sfs/sfs_inode.c create mode 100644 kern/fs/sfs/sfs_io.c create mode 100644 kern/fs/sfs/sfs_vnops.c create mode 100644 kern/fs/sfs/sfsprivate.h create mode 100644 kern/gdbscripts/array create mode 100644 kern/gdbscripts/mips-userland create mode 100644 kern/gdbscripts/wchan create mode 100644 kern/include/addrspace.h create mode 100644 kern/include/array.h create mode 100644 kern/include/bitmap.h create mode 100644 kern/include/cdefs.h create mode 100644 kern/include/clock.h create mode 100644 kern/include/copyinout.h create mode 100644 kern/include/cpu.h create mode 100644 kern/include/current.h create mode 100644 kern/include/device.h create mode 100644 kern/include/elf.h create mode 100644 kern/include/emufs.h create mode 100644 kern/include/endian.h create mode 100644 kern/include/fs.h create mode 100644 kern/include/hangman.h create mode 100644 kern/include/kern/endian.h create mode 100644 kern/include/kern/errmsg.h create mode 100644 kern/include/kern/errno.h create mode 100644 kern/include/kern/fcntl.h create mode 100644 kern/include/kern/ioctl.h create mode 100644 kern/include/kern/iovec.h create mode 100644 kern/include/kern/limits.h create mode 100644 kern/include/kern/reboot.h create mode 100644 kern/include/kern/resource.h create mode 100644 kern/include/kern/seek.h create mode 100644 kern/include/kern/sfs.h create mode 100644 kern/include/kern/signal.h create mode 100644 kern/include/kern/socket.h create mode 100644 kern/include/kern/stat.h create mode 100644 kern/include/kern/stattypes.h create mode 100644 kern/include/kern/syscall.h create mode 100644 kern/include/kern/time.h create mode 100644 kern/include/kern/types.h create mode 100644 kern/include/kern/unistd.h create mode 100644 kern/include/kern/wait.h create mode 100644 kern/include/lib.h create mode 100644 kern/include/limits.h create mode 100644 kern/include/mainbus.h create mode 100644 kern/include/membar.h create mode 100644 kern/include/proc.h create mode 100644 kern/include/setjmp.h create mode 100644 kern/include/sfs.h create mode 100644 kern/include/signal.h create mode 100644 kern/include/spinlock.h create mode 100644 kern/include/spl.h create mode 100644 kern/include/stat.h create mode 100644 kern/include/stdarg.h create mode 100644 kern/include/synch.h create mode 100644 kern/include/syscall.h create mode 100644 kern/include/test.h create mode 100644 kern/include/thread.h create mode 100644 kern/include/threadlist.h create mode 100644 kern/include/threadprivate.h create mode 100644 kern/include/types.h create mode 100644 kern/include/uio.h create mode 100644 kern/include/version.h create mode 100644 kern/include/vfs.h create mode 100644 kern/include/vm.h create mode 100644 kern/include/vnode.h create mode 100644 kern/include/wchan.h create mode 100644 kern/lib/array.c create mode 100644 kern/lib/bitmap.c create mode 100644 kern/lib/bswap.c create mode 100644 kern/lib/kgets.c create mode 100644 kern/lib/kprintf.c create mode 100644 kern/lib/misc.c create mode 100644 kern/lib/time.c create mode 100644 kern/lib/uio.c create mode 100644 kern/main/main.c create mode 100644 kern/main/menu.c create mode 100644 kern/proc/proc.c create mode 100644 kern/syscall/loadelf.c create mode 100644 kern/syscall/runprogram.c create mode 100644 kern/syscall/time_syscalls.c create mode 100644 kern/test/arraytest.c create mode 100644 kern/test/bitmaptest.c create mode 100644 kern/test/fstest.c create mode 100644 kern/test/kmalloctest.c create mode 100644 kern/test/nettest.c create mode 100644 kern/test/semunit.c create mode 100644 kern/test/synchtest.c create mode 100644 kern/test/threadlisttest.c create mode 100644 kern/test/threadtest.c create mode 100644 kern/test/tt3.c create mode 100644 kern/thread/clock.c create mode 100644 kern/thread/hangman.c create mode 100644 kern/thread/spinlock.c create mode 100644 kern/thread/spl.c create mode 100644 kern/thread/synch.c create mode 100644 kern/thread/thread.c create mode 100644 kern/thread/threadlist.c create mode 100644 kern/vfs/device.c create mode 100644 kern/vfs/devnull.c create mode 100644 kern/vfs/vfscwd.c create mode 100644 kern/vfs/vfsfail.c create mode 100644 kern/vfs/vfslist.c create mode 100644 kern/vfs/vfslookup.c create mode 100644 kern/vfs/vfspath.c create mode 100644 kern/vfs/vnode.c create mode 100644 kern/vm/addrspace.c create mode 100644 kern/vm/copyinout.c create mode 100644 kern/vm/kmalloc.c create mode 100644 man/Makefile create mode 100644 man/bin/Makefile create mode 100644 man/bin/cat.html create mode 100644 man/bin/cp.html create mode 100644 man/bin/false.html create mode 100644 man/bin/index.html create mode 100644 man/bin/ln.html create mode 100644 man/bin/ls.html create mode 100644 man/bin/mkdir.html create mode 100644 man/bin/mv.html create mode 100644 man/bin/pwd.html create mode 100644 man/bin/rm.html create mode 100644 man/bin/rmdir.html create mode 100644 man/bin/sh.html create mode 100644 man/bin/sync.html create mode 100644 man/bin/tac.html create mode 100644 man/bin/true.html create mode 100644 man/dev/Makefile create mode 100644 man/dev/beep.html create mode 100644 man/dev/con.html create mode 100644 man/dev/emu.html create mode 100644 man/dev/index.html create mode 100644 man/dev/lamebus.html create mode 100644 man/dev/lhd.html create mode 100644 man/dev/lnet.html create mode 100644 man/dev/lrandom.html create mode 100644 man/dev/lscreen.html create mode 100644 man/dev/lser.html create mode 100644 man/dev/ltimer.html create mode 100644 man/dev/ltrace.html create mode 100644 man/dev/null.html create mode 100644 man/dev/random.html create mode 100644 man/dev/rtclock.html create mode 100644 man/index.html create mode 100644 man/libc/Makefile create mode 100644 man/libc/__vprintf.html create mode 100644 man/libc/abort.html create mode 100644 man/libc/assert.html create mode 100644 man/libc/atoi.html create mode 100644 man/libc/bzero.html create mode 100644 man/libc/calloc.html create mode 100644 man/libc/err.html create mode 100644 man/libc/execvp.html create mode 100644 man/libc/exit.html create mode 100644 man/libc/free.html create mode 100644 man/libc/getchar.html create mode 100644 man/libc/getcwd.html create mode 100644 man/libc/getenv.html create mode 100644 man/libc/index.html create mode 100644 man/libc/malloc.html create mode 100644 man/libc/memcmp.html create mode 100644 man/libc/memcpy.html create mode 100644 man/libc/memmove.html create mode 100644 man/libc/memset.html create mode 100644 man/libc/printf.html create mode 100644 man/libc/putchar.html create mode 100644 man/libc/puts.html create mode 100644 man/libc/random.html create mode 100644 man/libc/realloc.html create mode 100644 man/libc/setjmp.html create mode 100644 man/libc/snprintf.html create mode 100644 man/libc/stdarg.html create mode 100644 man/libc/strcat.html create mode 100644 man/libc/strchr.html create mode 100644 man/libc/strcmp.html create mode 100644 man/libc/strcpy.html create mode 100644 man/libc/strerror.html create mode 100644 man/libc/strlen.html create mode 100644 man/libc/strrchr.html create mode 100644 man/libc/strtok.html create mode 100644 man/libc/strtok_r.html create mode 100644 man/libc/system.html create mode 100644 man/libc/time.html create mode 100644 man/libc/warn.html create mode 100644 man/man.css create mode 100644 man/manindex.css create mode 100644 man/misc/Makefile create mode 100644 man/misc/index.html create mode 100644 man/misc/semfs.html create mode 100644 man/sbin/Makefile create mode 100644 man/sbin/dumpsfs.html create mode 100644 man/sbin/halt.html create mode 100644 man/sbin/index.html create mode 100644 man/sbin/mksfs.html create mode 100644 man/sbin/poweroff.html create mode 100644 man/sbin/reboot.html create mode 100644 man/sbin/sfsck.html create mode 100644 man/syscall/Makefile create mode 100644 man/syscall/__getcwd.html create mode 100644 man/syscall/__time.html create mode 100644 man/syscall/_exit.html create mode 100644 man/syscall/chdir.html create mode 100644 man/syscall/close.html create mode 100644 man/syscall/dup2.html create mode 100644 man/syscall/errno.html create mode 100644 man/syscall/execv.html create mode 100644 man/syscall/fork.html create mode 100644 man/syscall/fstat.html create mode 100644 man/syscall/fsync.html create mode 100644 man/syscall/ftruncate.html create mode 100644 man/syscall/getdirentry.html create mode 100644 man/syscall/getpid.html create mode 100644 man/syscall/index.html create mode 100644 man/syscall/ioctl.html create mode 100644 man/syscall/link.html create mode 100644 man/syscall/lseek.html create mode 100644 man/syscall/lstat.html create mode 100644 man/syscall/mkdir.html create mode 100644 man/syscall/open.html create mode 100644 man/syscall/pipe.html create mode 100644 man/syscall/read.html create mode 100644 man/syscall/readlink.html create mode 100644 man/syscall/reboot.html create mode 100644 man/syscall/remove.html create mode 100644 man/syscall/rename.html create mode 100644 man/syscall/rmdir.html create mode 100644 man/syscall/sbrk.html create mode 100644 man/syscall/stat.html create mode 100644 man/syscall/symlink.html create mode 100644 man/syscall/sync.html create mode 100644 man/syscall/waitpid.html create mode 100644 man/syscall/write.html create mode 100644 man/testbin/Makefile create mode 100644 man/testbin/add.html create mode 100644 man/testbin/argtest.html create mode 100644 man/testbin/badcall.html create mode 100644 man/testbin/bigexec.html create mode 100644 man/testbin/bigfile.html create mode 100644 man/testbin/bigfork.html create mode 100644 man/testbin/bigseek.html create mode 100644 man/testbin/bloat.html create mode 100644 man/testbin/conman.html create mode 100644 man/testbin/crash.html create mode 100644 man/testbin/ctest.html create mode 100644 man/testbin/dirconc.html create mode 100644 man/testbin/dirseek.html create mode 100644 man/testbin/dirtest.html create mode 100644 man/testbin/f_test.html create mode 100644 man/testbin/factorial.html create mode 100644 man/testbin/farm.html create mode 100644 man/testbin/faulter.html create mode 100644 man/testbin/filetest.html create mode 100644 man/testbin/forkbomb.html create mode 100644 man/testbin/forktest.html create mode 100644 man/testbin/frack.html create mode 100644 man/testbin/guzzle.html create mode 100644 man/testbin/hash.html create mode 100644 man/testbin/hog.html create mode 100644 man/testbin/huge.html create mode 100644 man/testbin/index.html create mode 100644 man/testbin/kitchen.html create mode 100644 man/testbin/malloctest.html create mode 100644 man/testbin/matmult.html create mode 100644 man/testbin/multiexec.html create mode 100644 man/testbin/palin.html create mode 100644 man/testbin/parallelvm.html create mode 100644 man/testbin/poisondisk.html create mode 100644 man/testbin/psort.html create mode 100644 man/testbin/quinthuge.html create mode 100644 man/testbin/quintmat.html create mode 100644 man/testbin/quintsort.html create mode 100644 man/testbin/randcall.html create mode 100644 man/testbin/redirect.html create mode 100644 man/testbin/rmdirtest.html create mode 100644 man/testbin/rmtest.html create mode 100644 man/testbin/sbrktest.html create mode 100644 man/testbin/schedpong.html create mode 100644 man/testbin/sink.html create mode 100644 man/testbin/sort.html create mode 100644 man/testbin/sparsefile.html create mode 100644 man/testbin/sty.html create mode 100644 man/testbin/tail.html create mode 100644 man/testbin/tictac.html create mode 100644 man/testbin/triplehuge.html create mode 100644 man/testbin/triplemat.html create mode 100644 man/testbin/triplesort.html create mode 100644 man/testbin/usemtest.html create mode 100644 man/testbin/userthreads.html create mode 100644 man/testbin/zero.html create mode 100755 mk/fixdepends.sh create mode 100755 mk/installheaders.sh create mode 100644 mk/os161.baserules.mk create mode 100644 mk/os161.compile.mk create mode 100644 mk/os161.config-mips.mk create mode 100644 mk/os161.config.mk create mode 100644 mk/os161.hostcompile.mk create mode 100644 mk/os161.hostlib.mk create mode 100644 mk/os161.hostprog.mk create mode 100644 mk/os161.includes.mk create mode 100644 mk/os161.kernel.mk create mode 100644 mk/os161.lib.mk create mode 100644 mk/os161.man.mk create mode 100644 mk/os161.mkdirs.mk create mode 100644 mk/os161.prog.mk create mode 100644 mk/os161.script.mk create mode 100644 mk/os161.subdir.mk create mode 100644 testscripts/Makefile create mode 100644 testscripts/runtest.py create mode 100755 testscripts/test.py create mode 100644 userland/Makefile create mode 100644 userland/bin/Makefile create mode 100644 userland/bin/cat/Makefile create mode 100644 userland/bin/cat/cat.c create mode 100644 userland/bin/cp/Makefile create mode 100644 userland/bin/cp/cp.c create mode 100644 userland/bin/false/Makefile create mode 100644 userland/bin/false/false.c create mode 100644 userland/bin/ln/Makefile create mode 100644 userland/bin/ln/ln.c create mode 100644 userland/bin/ls/Makefile create mode 100644 userland/bin/ls/ls.c create mode 100644 userland/bin/mkdir/Makefile create mode 100644 userland/bin/mkdir/mkdir.c create mode 100644 userland/bin/mv/Makefile create mode 100644 userland/bin/mv/mv.c create mode 100644 userland/bin/pwd/Makefile create mode 100644 userland/bin/pwd/pwd.c create mode 100644 userland/bin/rm/Makefile create mode 100644 userland/bin/rm/rm.c create mode 100644 userland/bin/rmdir/Makefile create mode 100644 userland/bin/rmdir/rmdir.c create mode 100644 userland/bin/sh/Makefile create mode 100644 userland/bin/sh/sh.c create mode 100644 userland/bin/sync/Makefile create mode 100644 userland/bin/sync/sync.c create mode 100644 userland/bin/tac/Makefile create mode 100644 userland/bin/tac/tac.c create mode 100644 userland/bin/true/Makefile create mode 100644 userland/bin/true/true.c create mode 100644 userland/include/assert.h create mode 100644 userland/include/err.h create mode 100644 userland/include/errno.h create mode 100644 userland/include/fcntl.h create mode 100644 userland/include/limits.h create mode 100644 userland/include/setjmp.h create mode 100644 userland/include/signal.h create mode 100644 userland/include/stdarg.h create mode 100644 userland/include/stdbool.h create mode 100644 userland/include/stdint.h create mode 100644 userland/include/stdio.h create mode 100644 userland/include/stdlib.h create mode 100644 userland/include/string.h create mode 100644 userland/include/sys/cdefs.h create mode 100644 userland/include/sys/endian.h create mode 100644 userland/include/sys/ioctl.h create mode 100644 userland/include/sys/null.h create mode 100644 userland/include/sys/reboot.h create mode 100644 userland/include/sys/stat.h create mode 100644 userland/include/sys/types.h create mode 100644 userland/include/sys/wait.h create mode 100644 userland/include/test/quint.h create mode 100644 userland/include/test/triple.h create mode 100644 userland/include/time.h create mode 100644 userland/include/types/size_t.h create mode 100644 userland/include/unistd.h create mode 100644 userland/lib/Makefile create mode 100644 userland/lib/crt0/Makefile create mode 100644 userland/lib/crt0/mips/crt0.S create mode 100644 userland/lib/hostcompat/Makefile create mode 100644 userland/lib/hostcompat/err.c create mode 100644 userland/lib/hostcompat/host-err.h create mode 100644 userland/lib/hostcompat/hostcompat.c create mode 100644 userland/lib/hostcompat/hostcompat.h create mode 100644 userland/lib/hostcompat/ntohll.c create mode 100644 userland/lib/hostcompat/time.c create mode 100644 userland/lib/libc/Makefile create mode 100644 userland/lib/libc/arch/mips/syscalls-mips.S create mode 100644 userland/lib/libc/stdio/__puts.c create mode 100644 userland/lib/libc/stdio/getchar.c create mode 100644 userland/lib/libc/stdio/printf.c create mode 100644 userland/lib/libc/stdio/putchar.c create mode 100644 userland/lib/libc/stdio/puts.c create mode 100644 userland/lib/libc/stdlib/abort.c create mode 100644 userland/lib/libc/stdlib/exit.c create mode 100644 userland/lib/libc/stdlib/getenv.c create mode 100644 userland/lib/libc/stdlib/malloc.c create mode 100644 userland/lib/libc/stdlib/qsort.c create mode 100644 userland/lib/libc/stdlib/random.c create mode 100644 userland/lib/libc/stdlib/system.c create mode 100644 userland/lib/libc/string/memcmp.c create mode 100644 userland/lib/libc/string/strerror.c create mode 100644 userland/lib/libc/string/strtok.c create mode 100755 userland/lib/libc/syscalls/gensyscalls.sh create mode 100644 userland/lib/libc/time/time.c create mode 100644 userland/lib/libc/unix/__assert.c create mode 100644 userland/lib/libc/unix/err.c create mode 100644 userland/lib/libc/unix/errno.c create mode 100644 userland/lib/libc/unix/execvp.c create mode 100644 userland/lib/libc/unix/getcwd.c create mode 100644 userland/lib/libtest/Makefile create mode 100644 userland/lib/libtest/triple.c create mode 100644 userland/sbin/Makefile create mode 100644 userland/sbin/dumpsfs/Makefile create mode 100644 userland/sbin/dumpsfs/dumpsfs.c create mode 100644 userland/sbin/halt/Makefile create mode 100644 userland/sbin/halt/halt.c create mode 100644 userland/sbin/mksfs/Makefile create mode 100644 userland/sbin/mksfs/disk.c create mode 100644 userland/sbin/mksfs/disk.h create mode 100644 userland/sbin/mksfs/mksfs.c create mode 100644 userland/sbin/mksfs/support.c create mode 100644 userland/sbin/mksfs/support.h create mode 100644 userland/sbin/poweroff/Makefile create mode 100644 userland/sbin/poweroff/poweroff.c create mode 100644 userland/sbin/reboot/Makefile create mode 100644 userland/sbin/reboot/reboot.c create mode 100644 userland/sbin/sfsck/Makefile create mode 100644 userland/sbin/sfsck/compat.h create mode 100644 userland/sbin/sfsck/freemap.c create mode 100644 userland/sbin/sfsck/freemap.h create mode 100644 userland/sbin/sfsck/ibmacros.h create mode 100644 userland/sbin/sfsck/inode.c create mode 100644 userland/sbin/sfsck/inode.h create mode 100644 userland/sbin/sfsck/main.c create mode 100644 userland/sbin/sfsck/main.h create mode 100644 userland/sbin/sfsck/pass1.c create mode 100644 userland/sbin/sfsck/pass2.c create mode 100644 userland/sbin/sfsck/passes.h create mode 100644 userland/sbin/sfsck/sb.c create mode 100644 userland/sbin/sfsck/sb.h create mode 100644 userland/sbin/sfsck/sfs.c create mode 100644 userland/sbin/sfsck/sfs.h create mode 100644 userland/sbin/sfsck/utils.c create mode 100644 userland/sbin/sfsck/utils.h create mode 100644 userland/testbin/Makefile create mode 100644 userland/testbin/add/Makefile create mode 100644 userland/testbin/add/add.c create mode 100644 userland/testbin/argtest/Makefile create mode 100644 userland/testbin/argtest/argtest.c create mode 100644 userland/testbin/badcall/Makefile create mode 100644 userland/testbin/badcall/bad_chdir.c create mode 100644 userland/testbin/badcall/bad_close.c create mode 100644 userland/testbin/badcall/bad_dup2.c create mode 100644 userland/testbin/badcall/bad_execv.c create mode 100644 userland/testbin/badcall/bad_fsync.c create mode 100644 userland/testbin/badcall/bad_ftruncate.c create mode 100644 userland/testbin/badcall/bad_getcwd.c create mode 100644 userland/testbin/badcall/bad_getdirentry.c create mode 100644 userland/testbin/badcall/bad_ioctl.c create mode 100644 userland/testbin/badcall/bad_link.c create mode 100644 userland/testbin/badcall/bad_lseek.c create mode 100644 userland/testbin/badcall/bad_mkdir.c create mode 100644 userland/testbin/badcall/bad_open.c create mode 100644 userland/testbin/badcall/bad_pipe.c create mode 100644 userland/testbin/badcall/bad_read.c create mode 100644 userland/testbin/badcall/bad_readlink.c create mode 100644 userland/testbin/badcall/bad_reboot.c create mode 100644 userland/testbin/badcall/bad_remove.c create mode 100644 userland/testbin/badcall/bad_rename.c create mode 100644 userland/testbin/badcall/bad_rmdir.c create mode 100644 userland/testbin/badcall/bad_sbrk.c create mode 100644 userland/testbin/badcall/bad_stat.c create mode 100644 userland/testbin/badcall/bad_symlink.c create mode 100644 userland/testbin/badcall/bad_time.c create mode 100644 userland/testbin/badcall/bad_waitpid.c create mode 100644 userland/testbin/badcall/bad_write.c create mode 100644 userland/testbin/badcall/common_buf.c create mode 100644 userland/testbin/badcall/common_fds.c create mode 100644 userland/testbin/badcall/common_path.c create mode 100644 userland/testbin/badcall/config.h create mode 100644 userland/testbin/badcall/driver.c create mode 100644 userland/testbin/badcall/report.c create mode 100644 userland/testbin/badcall/test.h create mode 100644 userland/testbin/bigexec/Makefile create mode 100644 userland/testbin/bigexec/bigexec.c create mode 100644 userland/testbin/bigfile/Makefile create mode 100644 userland/testbin/bigfile/bigfile.c create mode 100644 userland/testbin/bigfork/Makefile create mode 100644 userland/testbin/bigfork/bigfork.c create mode 100644 userland/testbin/bigseek/Makefile create mode 100644 userland/testbin/bigseek/bigseek.c create mode 100644 userland/testbin/bloat/Makefile create mode 100644 userland/testbin/bloat/bloat.c create mode 100644 userland/testbin/conman/Makefile create mode 100644 userland/testbin/conman/conman.c create mode 100644 userland/testbin/crash/Makefile create mode 100644 userland/testbin/crash/crash.c create mode 100644 userland/testbin/ctest/Makefile create mode 100644 userland/testbin/ctest/ctest.c create mode 100644 userland/testbin/dirconc/Makefile create mode 100644 userland/testbin/dirconc/dirconc.c create mode 100644 userland/testbin/dirseek/Makefile create mode 100644 userland/testbin/dirseek/dirseek.c create mode 100644 userland/testbin/dirtest/Makefile create mode 100644 userland/testbin/dirtest/dirtest.c create mode 100644 userland/testbin/f_test/Makefile create mode 100644 userland/testbin/f_test/f_hdr.h create mode 100644 userland/testbin/f_test/f_read.c create mode 100644 userland/testbin/f_test/f_test.c create mode 100644 userland/testbin/f_test/f_write.c create mode 100644 userland/testbin/factorial/Makefile create mode 100644 userland/testbin/factorial/factorial.c create mode 100644 userland/testbin/farm/Makefile create mode 100644 userland/testbin/farm/farm.c create mode 100644 userland/testbin/faulter/Makefile create mode 100644 userland/testbin/faulter/faulter.c create mode 100644 userland/testbin/filetest/Makefile create mode 100644 userland/testbin/filetest/filetest.c create mode 100644 userland/testbin/forkbomb/Makefile create mode 100644 userland/testbin/forkbomb/forkbomb.c create mode 100644 userland/testbin/forktest/Makefile create mode 100644 userland/testbin/forktest/forktest.c create mode 100644 userland/testbin/frack/Makefile create mode 100644 userland/testbin/frack/check.c create mode 100644 userland/testbin/frack/check.h create mode 100644 userland/testbin/frack/data.c create mode 100644 userland/testbin/frack/data.h create mode 100644 userland/testbin/frack/do.c create mode 100644 userland/testbin/frack/do.h create mode 100644 userland/testbin/frack/main.c create mode 100644 userland/testbin/frack/main.h create mode 100644 userland/testbin/frack/name.c create mode 100644 userland/testbin/frack/name.h create mode 100644 userland/testbin/frack/ops.c create mode 100644 userland/testbin/frack/ops.h create mode 100644 userland/testbin/frack/pool.c create mode 100644 userland/testbin/frack/pool.h create mode 100644 userland/testbin/frack/workloads.c create mode 100644 userland/testbin/frack/workloads.h create mode 100644 userland/testbin/hash/Makefile create mode 100644 userland/testbin/hash/hash.c create mode 100644 userland/testbin/hog/Makefile create mode 100644 userland/testbin/hog/hog.c create mode 100644 userland/testbin/huge/Makefile create mode 100644 userland/testbin/huge/huge.c create mode 100644 userland/testbin/malloctest/Makefile create mode 100644 userland/testbin/malloctest/malloctest.c create mode 100644 userland/testbin/matmult/Makefile create mode 100644 userland/testbin/matmult/matmult-orig.c create mode 100644 userland/testbin/matmult/matmult.c create mode 100644 userland/testbin/multiexec/Makefile create mode 100644 userland/testbin/multiexec/multiexec.c create mode 100644 userland/testbin/palin/Makefile create mode 100644 userland/testbin/palin/palin.c create mode 100644 userland/testbin/parallelvm/Makefile create mode 100644 userland/testbin/parallelvm/parallelvm.c create mode 100644 userland/testbin/poisondisk/Makefile create mode 100644 userland/testbin/poisondisk/poisondisk.c create mode 100644 userland/testbin/psort/Makefile create mode 100644 userland/testbin/psort/psort.c create mode 100644 userland/testbin/randcall/Makefile create mode 100644 userland/testbin/randcall/callspecs.txt create mode 100644 userland/testbin/randcall/extern.h create mode 100755 userland/testbin/randcall/gencalls.sh create mode 100644 userland/testbin/randcall/main.c create mode 100644 userland/testbin/redirect/Makefile create mode 100644 userland/testbin/redirect/redirect.c create mode 100644 userland/testbin/rmdirtest/Makefile create mode 100644 userland/testbin/rmdirtest/rmdirtest.c create mode 100644 userland/testbin/rmtest/Makefile create mode 100644 userland/testbin/rmtest/rmtest.c create mode 100644 userland/testbin/sbrktest/Makefile create mode 100644 userland/testbin/sbrktest/sbrktest.c create mode 100644 userland/testbin/schedpong/Makefile create mode 100644 userland/testbin/schedpong/grind.c create mode 100644 userland/testbin/schedpong/main.c create mode 100644 userland/testbin/schedpong/pong.c create mode 100644 userland/testbin/schedpong/results.c create mode 100644 userland/testbin/schedpong/results.h create mode 100644 userland/testbin/schedpong/tasks.h create mode 100644 userland/testbin/schedpong/think.c create mode 100644 userland/testbin/schedpong/usem.c create mode 100644 userland/testbin/schedpong/usem.h create mode 100644 userland/testbin/sort/Makefile create mode 100644 userland/testbin/sort/sort.c create mode 100644 userland/testbin/sparsefile/Makefile create mode 100644 userland/testbin/sparsefile/sparsefile.c create mode 100644 userland/testbin/tail/Makefile create mode 100644 userland/testbin/tail/tail.c create mode 100644 userland/testbin/tictac/Makefile create mode 100644 userland/testbin/tictac/tictac.c create mode 100644 userland/testbin/triplehuge/Makefile create mode 100644 userland/testbin/triplehuge/triplehuge.c create mode 100644 userland/testbin/triplemat/Makefile create mode 100644 userland/testbin/triplemat/triplemat.c create mode 100644 userland/testbin/triplesort/Makefile create mode 100644 userland/testbin/triplesort/triplesort.c create mode 100644 userland/testbin/usemtest/Makefile create mode 100644 userland/testbin/usemtest/usemtest.c create mode 100644 userland/testbin/userthreads/Makefile create mode 100644 userland/testbin/userthreads/userthreads.c create mode 100644 userland/testbin/zero/Makefile create mode 100644 userland/testbin/zero/zero.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a32ce6a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +kern/compile/ +build/ diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..5dde7e1 --- /dev/null +++ b/CHANGES @@ -0,0 +1,1986 @@ +OS/161 was written by David A. Holland, with contributions from + Amos Blackman + Alexandra Fedorova + Ada T. Lim + Georgi Matev + Jay Moorthi + Geoffrey Werner-Allen + +Additional small patches and bug reports have been contributed by +various other people, all of whom are (hopefully) listed below. + +------------------------------------------------------------ + + +OS/161 2.0.3 released 20160124 +------------------------------ + +20170124 dholland in base + - Remove obsolete, redundant, or not useful test programs: + guzzle (same as hog) + kitchen (equivalent to multiexec -n 4 sink) + sink (same as conman) + sty (equivalent to multiexec -n 6 hog) + quinthuge (offers little over triplehuge, can be done with multiexec) + quintmat, quintsort (ditto) + +20170118 dholland in base + - Make -g -Og the flags when "debug" is enabled in a kernel config + (which it is in the non-OPT ones) and add an additional kernel + config verb "debugonly" to get just -g in case that becomes + necessary. This should significantly improve the output code + quality from gcc without compromising debugging. (However, gcc + being gcc, it also sometimes leads to additional spurious + warnings that don't occur with either -g or -O2.) + +20170118 dholland in base + - Add a MI mainbus_debugger() function that goes through the right + MD paths to trigger the debugger hook in the ltrace device. Also + add a menu function "debug" to trigger it. + +20170118 dholland in base + - Add some bits to forktest to try to catch the case where the fork + child returns from the next system call instead of from fork. + (Which is a moderately common bug, caused by races copying the + trapframe information in the kernel.) + +20170117 dholland in base + - Add a menu command "deadlock" to intentionally deadlock. + +20170117 dholland in base, from Sam Fishman + - Fix parallelvm -w so that if one of the forks fails the whole + thing doesn't wedge. + +20170117 dholland in base, reported by Sam Fishman + - Don't do semfs I/O from NULL, or from/to insufficiently sized + buffers. Like the 20150615 change, except covering the rest of + the tests that use the semaphores that were doing it wrong: + multiexec, parallelvm, and schedpong. + +20170117 dholland in base, from Sam Fishman + - Add assembler directives to exception-mips1.S that tell gdb how + to read trap frames correctly. Garbage-collect old stuff left + over from making it work with a (much) older version of gdb a + long time back. This also usually makes it possible to trace back + through a syscall into a userlevel process; include a gdb script + with tools for making this useful. + +20170117 dholland in base + - Merge the deadlock detector into base. It was a success last year. + - Mention in the comments that the hangman hooks in locks need to + be called atomically. + +20170117 dholland in base, reported by Jeffrey Cai, patch from Sam Fishman + - Fix off-by-one in tac that makes it skip the first line of files. + +20170117 dholland in base, from Sam Fishman + - Make badcall's "pipe with unaligned pointer" test clean up after + itself if the operation succeeds. Otherwise it leaks fds and that + can intefere with other tests. + +20170116 dholland in base, reported by Sam Fishman + - Don't allow opening an entirely empty pathname to succeed, and + don't allow success for this case in badcall either. + +20170116 dholland in base, from Sasha Fedorova + - Fix write buffer size in filetest. + +20160325 dholland in base + - Fix macro parenthesis bug in ROUNDUP(). + +20160304 dholland in base, from Sam Fishman + - Make runtest.py handle spacing in the command strings it's given. + +20160216 dholland in base + - Fix spacing problems in ls -l output for large files. + +20160203 dholland in base + - Expand comments attached to cpustacks[]/cputhreads[], prompted by + James Mickens. + +20160125 dholland in base, from Nikhil Benesch. + - Fix stupid argument handling bug in test.py. + + +OS/161 2.0.2 released 20160112 +------------------------------ + +20160112 dholland in base + - Add vfs_swapon() and vfs_swapoff() functions. These are like + vfs_mount() and vfs_unmount(), except for devices to be used for + swap. Using these instead of just opening the raw device causes + them to be tagged busy, so that accidentally using the same disk + for swap and a file system will fail. + +20160112 dholland in base + - Kill off vm_tlbshootdown_all() and VM_TLBSHOOTDOWN_ALL. While + there's nothing wrong per se with doing a TLB shootdown that + invalidates all mappings, coalescing multiple pending TLB + shootdown requests into a single all-mappings request requires at + least MD logic, which the oversimplified scheme here didn't + support. In practice TLB shootdown requires synchronization, and + the coalescing scheme made it unsafe to put synchronization hooks + (that might get dropped) into struct tlbshootdown. Instead leave + behind a comment suggesting steps to take if the TLB shootdown + queue ever actually overflows in practice, which isn't that + likely. + +20160112 dholland in base, reported by Sam Fishman + - In thread_make_runnable, don't send unidle IPIs to curcpu. + +20160111 dholland in base + - Provide some simple test automation logic, and install it in + $(OSTREE)/testscripts. It uses Python and pexpect, so provide + some suitable infrastructure for handling that. + +20160111 dholland in base + - Have "make clean" in a man directory do nothing instead of failing. + +20160107 dholland in base + - Don't take vfs_biglock in vnode_check(). It isn't safe (e.g. it + can deadlock when paging once you have a VM system) and the + things vnode_check() looks at are supposed to be constant fields + anyway. If they aren't actually constant because of bugs, reading + a stale or even garbage value is not going to hurt more. + +20160107 dholland in deadlock-detector + - Add a deadlock detector. For now this will be supplied to + instructors as a supplementary patch, because it intrudes into + the synchronization primitives and affects what students do + there. We are planning to try it on our students this coming + semester; if that works out well, I'll probably merge it into + base. + +20160107 dholland in base + - In testbin/multiexec, if fork fails partway through, continue + with the forks we got. Otherwise the subprocesses we started hang + around forever, and there's no way to kill them. + +20160106 dholland in all + - New format for CHANGES that admits longer descriptions, and that + deals better with having many branches and patches. + - Merge all the branch CHANGES.* files into the main CHANGES, as + having multiple CHANGES files was never desirable. + + +OS/161 2.0.1 released 20150805 +------------------------------ + +20150804 dholland in base + - Improve multiexec's error reporting. + +20150804 dholland in base + - Minor fixes to frack check. + +20150722 dholland in base + - Add assertions to dumbvm to check that sleeping is ok in various + contexts where real VM systems typically sleep. + +20150722 dholland in base + - Initialize curcpu/curthread a bit earlier. + +20150721 dholland in base + - Remove proc->p_threads[] array. Just count the number of threads + in each proc. This is enough to get going on, and it's easy for + students to add and synchronize an explicit array of threads + themselves if they want it. (It needs a sleeplock; but by that + point they'll have those. We don't out of the box though.) + +20150713 dholland in base + - Make all sfs prints/panics include the volume name. + +20150713 dholland in base + - Have sfsck print invalid inode type values instead of just saying + "invalid". + +20150713 dholland in base + - Have forktest print ABCD instead of 1234 for clarity. + +20150713 dholland in base + - Kill off allwchans[]; in practice it isn't useful. + +20150710 dholland in base + - Split out the pieces of sfs_sync for reusability. + +20150706 dholland in base + - Add support for new sys161 profiler control registers. + +20150625 dholland in base + - Fix frack "writetruncseq" workload. + +20150605 dholland in base + - Have semfs update uio_offset; increases robustness. + - Don't do semfs I/O from NULL. It causes consternation. + +20150605 dholland in base + - Warn that copying threadlist structures breaks them. + +20150605 dholland in base + - New test: schedpong, an actual scheduler workload, now possible + because we have semfs. + +20150603 dholland in base + - Add example unit tests for the provided semaphores. + +20150603 dholland in base + - In panic, drop to the debugger before sync, not after. Otherwise, + the sync complicates postmortem analysis. Also, for file system + panics it often deadlocks. + +20150603 dholland in base + - Make "dumpsfs -i N -a image" work. + +20150603 dholland in base + - Make kernel config script reject duplicate .o names. + +20150603 dholland in base + - Improve the printouts of testbin/badcall. + - Improve printouts of testbin/crash for legibility. + +20150528 dholland in base + - Comment up testbin/frack/check.c. Badly needed. + +20150527 dholland in base, from Keno Fischer. + - Fix various minor bugs found by clang-static-analyzer. + +20150527 dholland in base + - Make the skeleton userland stdio less needlessly dumb. + +20150527 dholland in base + - New kernel menu test: at2; tests arrays > 1 page. + +20150519 dholland in base + - New test: bigfork, intended mostly for performance testing. + +20150513 dholland in base + - Fix "unexpected EOF" bug in frack check. + - Fix flagrantly wrong assert in frack check. + - Fix fd leaks in frack check. + +20150428 dholland in base, from Sam Fishman and Michelle Deng. + - Fix error-path assertions in sfs_domount. + +20150422 dholland in base + - Re-enable ftruncate in frack by default. + +20150417 dholland in base, from Nikhil Benesch. + - Fix configure test for ntohll. + +20150417 dholland in base, from Nikhil Benesch. + - Use printf instead of echo -n in shell scripts; it seems that + even in 2015 Mac OS X comes with a broken echo, and we don't care + about host OSes too old to have printf in sh. + +20150322 dholland in base, from Anne Madoff. + - Fix typos in non-dumbvm addrspace.h. + +20150322 dholland in base + - Fix some typos in comments. + +20150127 dholland in base + - Patch more Linux build problems caused by glibc bugs. + + +OS/161 2.0 released 20150115 +---------------------------- + +20150113 dholland in base + - Drop to the debugger on panic. + +20150113 dholland in base + - Document parallelvm -w. + +20150113 dholland in base, from Katherine Flavel. + - Better man page typesetting. + +20150108 dholland in base + - Fix FSOP_GETROOT signature/usage so it can fail. + +20150108 dholland in base + - Add several missing man pages for testbin programs. + +20150108 dholland in base + - Fix naming of semaphores in testbin/multiexec. + +20150107 dholland in base + - Rename kern/malloctest.c to kmalloctest.c for clarity. + - Also change malloctest* symbols to kmalloctest*. + +20140924 dholland in base + - Print the kernel build number after linking. + + +OS/161 1.99.08 released 20140924 +-------------------------------- +Consider this 2.0-RC1. + +20140924 dholland in base + - Make km3 rotate object sizes as originally intended. + +20140924 dholland in base + - Make frack print a visible divider when it syncs. + +20140922 dholland in base + - Add /bin/tac, which uses unlinked scratch files. + +20140919 dholland in base + - Allow giving testbin/bigfile the chunk size to write. + +20140919 dholland in base + - Add a design doc about the structure of assignments. + +20140919 dholland in base + - Make certain sfsck checks set the exit status properly. + +20140918 dholland in base + - Provide general-purpose metadata I/O function in sfs. + +20140916 dholland in base + - Remove size workaround in bigexec; the solution set is now fixed. + +20140904 dholland in base + - Fix problem with stray symlinks in $(OSTREE)/include. + +20140904 dholland in base + - Change sfs_vnode->sv_v to sv_absvn for consistency. + +20140904 dholland in base + - Add bloat test; it uses all available memory rapidly. + +20140904 dholland in base + - Fix testbin/crash for gcc 4.8. + +20140904 dholland in base + - Make testbin/filetest do something useful if given no argv. + +20140904 dholland in base + - Add sys/cdefs.h and move userland __DEAD there. + - Declare userland err* __DEAD. + +20140903 dholland in base + - Simplify ram.c interface as suggested by several of my students. + +20140829 dholland in base + - Add km4: a kmalloc test for multipage allocations. + +20140829 dholland in base + - Add multiexec test for lots of procs in exec at once. + +20140828 dholland in base + - Fix inlining for gcc 4.8, and a few other build issues. + - Tighten asm constraints for gcc 4.8. + +20140825 dholland in base + - Remove DEVOP_LASTCLOSE; nothing uses it and we will never add + rewind-on-close tape devices. + - Don't fsync in sfs_lastclose; it's outdated practice. + - Remove VOP_LASTCLOSE; nothing uses it any more. + - Remove vnode open count and VOP_INC/DECOPEN. + +20140825 dholland in base + - Use a separate spinlock for vnode refcounts. (Using vfs_biglock + causes sleeping while holding spinlocks.) + +20140825 dholland in base + - Don't use sfs_io() for directory entries. + +20140821 dholland in base + - Replace VOP_TRYSEEK with static VOP_ISSEEKABLE. + +20140821 dholland in base + - Make devices check seek position validity on the fly. + +20140806 dholland in base, from Anne Madoff. + - Make sfs_link reject directories. + +20140730 dholland in base + - Make testbin/hog run longer. + +20140729 dholland in base + - Make psort big enough to be useful as a fs test. + - Document psort's sizing knobs. + +20140729 dholland in base + - Add ARRAYCOUNT() macro for static array length. + +20140729 dholland in base + - Add array_preallocate(). + +20140729 dholland in base + - Make npages argument of alloc_kpages() unsigned. + +20140729 dholland in base + - Tidy up construction/destruction of struct sfs_fs. + +20140728 dholland in base + - Make sfs_read/writeblock take the buffer length. (One should + always do that, even if it's really the same everywhere.) + +20140728 dholland in base + - struct sfs_super -> struct sfs_superblock. + +20140728 dholland in base + - Adjust SFS code to make it more readily extensible. + +20140728 dholland in base + - Rename a bunch of the SFS constants for clarity. + - Always call SFS's free block bitmap the "freemap". + +20140725 dholland in base + - Add usemtest for checking the semfs semaphores. + +20140724 dholland in base + - Make failed SFS writes not increase the file size. + +20140724 dholland in base + - Distinguish MIPS 512M RAM limit and LAMEbus 508M limit. + +20140722 dholland in base + - sfs_dir -> sfs_direntry, by popular demand. + +20140722 dholland in base + - Add some notes about the atomicity of dup2(). + +20140722 dholland in base, from Jared Pochtar. + - Add notes about the limits of syscall atomicity in multithreaded + processes. + +20140722 dholland in base + - Add redirect test to check stdin/stdout redirection. + +20140722 dholland in base + - Add bigseek test for checking seeks beyond 2^32. + - Fix emufs handling of seek positions beyond 2^32. + +20140721 dholland in base + - Add file open mode checks to badcall. + +20140721 dholland in base + - Fix interaction of kmalloc guards and kmalloc labels. + +20140721 dholland in base + - Be more conservative about panic on stray interrupt. + +20140721 dholland in base + - Fix userland build to not belch on removed .h files. + - Fix userland build to not rebuild unnecessarily. + +20140721 dholland in base + - In badcall, don't shout if mkdir isn't implemented. + +20140717 dholland in base + - Fix misleading comments and variable names in proc.c. + +20140716 dholland in base + - Add -w option to parallelvm to wait for forking. + +20140716 dholland in base + - Replace a busywait in badcall with the new user semaphores. + +20140716 dholland in base + - Provide userlevel semaphores via semfs filesystem. Open + "sem:", then use read to P() and write to V(). + +20140716 dholland in base + - Move the just-fail vnode op stubs to VFS. + +20140710 dholland in base + - Added new test program: sbrktest. + +20140710 dholland in base + - Ship qsort() in libc, not in sfsck's compat code. + - Make the libc qsort() actually quicksort. + +20140709 dholland in base + - SWAP{S,L,LL} -> SWAP{16,32,64} in sfs tools. + +20140709 dholland in base + - Fix reversed found/expected printout in frack check. + +20140518 dholland in base + - Fix embarrasing sort bugs in native sfsck. + +20140430 dholland in base + - Add poisondisk tool for testing file system recovery. + +20140428 dholland in base + - Add hostcompat logic for 64-bit byte-swapping. + +20140417 dholland in base + - Fix testbin/zero to use page-sized sbrk calls. + +20140415 dholland in base + - Rewrite dumpsfs and make it much more useful. + +20140414 dholland in base + - Fix missing initialization of cpu->c_spinlocks. + +20140410 dholland in base + - Fix bug in malloc changes. Add assertion to malloctest. + +20140326 dholland in base + - Make userlevel malloc allocate in page-sized chunks. + +20140326 dholland in base + - Fix the (unused) 64-bit userlevel malloc code. + +20140314 dholland in base + - Make forktest show how much output is expected. + +20140220 dholland in base + - Add new sy4 test for CVs. + +20140211 dholland in base + - Tidy some logic in thread_make_runnable. + +20140211 dholland in base, from Anne Madoff. + - Mark threads READY when waking them. + +20140201 dholland in base, reported by Emmet Jao. + - Fix some outdated comments. + +20140128 dholland in base + - Fix default OSTREE in configure script. + + +OS/161 1.99.07 released 20140123 +-------------------------------- + +20140123 dholland in base + - Add "frack" test (filesystem recover and check). + +20140123 dholland in base + - Add factorial test that computes using execv. + +20140123 dholland in base + - Add fs6 test that creates lots of small files. + +20140122 dholland in base + - Mark enter_new_process and related code __DEAD. + +20140122 dholland in base + - Make the semaphore counter unsigned. + +20140122 dholland in base + - When kmalloc gets a page, assert that it's aligned. + +20140122 dholland in base, from Christian Anderson. + - Fix error leak in sfs_balloc. + +20140122 dholland in base + - Use ssize_t and pid_t more in unistd.h. + +20140122 dholland in base + - Add discussion of ARG_MAX to execv man page. + +20140122 dholland in base + - Add missing for userland. + +20140122 dholland in base + - Added sparsefile test program for making sparse files. + +20140122 dholland in base + - splx() needs to work before curcpu/curthread exists. + +20140122 dholland in base + - Clarify that proc_remthread requires splhigh. + +20140115 dholland in base + - Remove VOP_INIT/CLEANUP macros. Use vnode_init/cleanup. + +20140115 dholland in base + - Make device open/close eachopen/lastclose like vnodes. + +20140115 dholland in base + - Move vfs-level device ops to an ops table struct. + +20140115 dholland in base + - Clarify/correct comments pertaining to O_APPEND. + +20140114 dholland in base + - Reorganize SFS sources. + +20131112 dholland in base + - Reorganize sfsck sources; rework and improve sfsck. + - In SFS, always provide N{,D,T}INDIRECT macros. + +20131110 dholland in base + - Don't use uninitialized file permissions in badcall. + +20131110 dholland in base + - Provide __UNUSED along with __PF and __DEAD. + +20131108 dholland in base + - Rearrange (and fix) hacks for _exit() returning. It now faults on + "0xeeeee00f" if it can't exit. + +20131107 dholland in base + - Handle TLB pipeline hazards correctly. + +20131107 dholland in base + - Add some sample/experimental gdb scripts. + +20131107 dholland in base + - Make the console polling logic not use internal vars. + +20131107 dholland in base + - Have wchan_sleep assert if holding extra spinlocks. + +20131107 dholland in base + - Don't use (our) assignment numbers for kernel configs. + +20131107 dholland in base + - Remove the synch problems, and their support framework, from the + base system. Ship this material as a patch instead. + +20131107 dholland in base + - Rename src/user -> src/userland. Seems to be the best choice + among a number of unappealing alternatives. + +20131105 dholland in base + - Disallow EINVAL for "no such process" in badcall. + +20131105 dholland in base + - Clean up sh's use of exit codes. + +20131105 dholland in base + - Have testbin/crash check the signal numbers produced. + +20131105 dholland in base + - Create an array of all wchans for debug purposes. + +20131105 dholland in base + - Rearranged wchan API to make wchans more like CVs. + +20131105 dholland in base + - Print the processor ID and version correctly. + +20131105 dholland in base + - Fix boot on pre-multiprocessor System/161. + +20131105 dholland in base + - Parallelize the kernel depend logic. + +20131104 dholland in base + - Add and use memory barrier ops header. Minor impact. + +20131104 dholland in base + - Rename sfs_inode to sfs_dinode. + +20131101 dholland in base + - Edit and revise the man pages. Add some missing ones. + +20131101 dholland in base + - Update the docs and specs for waitpid. + +20131030 dholland in base + - Use execvp() in sh. Don't have to type /bin/cat now. + +20131030 dholland in base + - Provide getenv() and execvp() in libc. + +20131030 dholland in base + - enter_user_process() now accepts an environ pointer. + +20131030 dholland in base + - Add quinthuge, quintmat, quintsort tests. + +20131030 dholland in base + - Added a libtest with common stuff for testbin/. + +20131030 dholland in base + - Rewrite the .depend-munging script to be readable. + +20131030 dholland in base + - Use ENOSYS (standard) instead of EUNIMP (which isn't). + +20131030 dholland in base + - Fix badcall to expect wait with null status to succeed. + +20131030 dholland in base + - Don't use unportable function casts in sfs. + +20131029 dholland in base + - Add more kmalloc debugging modes and checks. + - Add a memory leak detection mode to kmalloc. + +20131028 dholland in base + - Move the whole-filesystem ops to an ops table struct. + +20131028 dholland in base + - Use designated initializers for the vnode ops tables. + +20131028 dholland in base + - Fix the way thread_panic zaps the run queue. + +20131028 dholland in base + - Move memset.c to common/ for use in the kernel. + +20131028 dholland in base + - Mark thread_exit() __DEAD. + +20131028 dholland in base + - Fix addrspace handling in proc_destroy(). + +20131025 dholland in base + - Add another kmalloc test (km3), this one of variable size. + - Improve kmalloc to support larger kernel heaps. + +20131025 dholland in base + - Make printf accept %zd/%zu for size_t. + +20130531 dholland in base + - Add tests for the threadlist code. + +20130531 dholland in base, from Steven Talbot. + - Fix threadlist iterators again. + +20130531 dholland in base + - Do thread migration *before* running the scheduler. + +20130531 dholland in base + - Add some more assertions to kfree. + +20130531 dholland in base + - Make badcall understand wait-for-any waitpid(). + +20130531 dholland in base + - Fix depends bug in os161.hostcompile.mk. + - Put .depend files in build tree where they belong. + - Provide a predepend: hook for makefiles. + +20130531 dholland in base + - Remove getinterval(); replace with timespec arithmetic. + +20130531 dholland in base + - Use struct timespec inside the kernel. + +20130531 dholland in base + - Move kern/startup -> kern/main, like it was in 1.x. + +20130531 dholland in base + - Add "zero" test; checks if the VM system zeros pages. + +20130531 dholland in base + - Change as_activate() to always activate curproc's AS. + +20130531 dholland in base + - Provide both thread and process structures by default. + +20130530 dholland in base + - Fix the scheme for probing LAMEbus device versions; don't require + lockstep upgrades for System/161 changes. + +20130530 dholland in base, from Saagar Deshpande. + - Fix typo in comment. + +20130530 dholland in base + - Add comment warning against borrowing from dumbvm. + +20130530 dholland in base + - Increase DUMBVM_STACKPAGES so 64K argv blocks will fit. + +20130514 dholland in base + - Teach sfsck to handle dirs with invalid inode numbers. + +20130503 dholland in base, reported by multiple students. + - Fix another problem in the inode array in sfsck. + +20130429 dholland in base + - Fix sfsck bitmap-checking problem. + +20130311 dholland in base + - Declare panic() and badassert() noreturn. + +20130308 dholland in base, found by George Kulakowski. + - Fix fd leak in badcall. + +20130306 dholland in base, found by David Palmer. + - Fix off_t printing in randcall. + +20110427 dholland in base, from Andy Brody. + - Fix typo in badcall. + +20110425 dholland in base, found by Jim Danz. + - Fix catastrophic bug in sfsck. + +20110420 dholland in base + - Add new bigexec test for checking large argvs. + +20110319 dholland in base + - Use va_copy() in __printf. (At least if available.) + +20110223 dholland in base, from Amy Tai. + - array.h needs cdefs.h and lib.h. + +20110127 dholland in base + - Fix host-psort build problem caused by glibc on Linux. + + +OS/161 1.99.06 released 20110126 +-------------------------------- + +20110126 dholland in base + - Fix some parallel build problems. + +20110126 dholland in base + - Rename fs5 test to "long stress test". + +20110126 dholland in base + - Clarify that struct tlbshootdown is a placeholder. + +20110126 dholland in base + - Fix randcall makefile to put calls.c in the build dir. + +20110126 dholland in base + - VOP_OPEN -> VOP_EACHOPEN; VOP_CLOSE -> VOP_LASTCLOSE. + +20110126 dholland in base + - Name struct spinlock's members splk_*, not lk_*. + +20110126 dholland in base + - sfs_fs.c -> sfs_fsops.c, sfs_vnode.c -> sfs_vnops.c + +20100819 dholland in base + - Fix the stray console IRQs problem properly. This requires + System/161 1.99.05 or higher. + +20100819 dholland in base + - Revert start/endpolling hack for stray console IRQs. (But keep + the code for masking interrupts.) + +20100819 dholland in base + - Don't leave the IPI spinlock dangling on a panic IPI. + + +OS/161 1.99.05 released 20100108 +-------------------------------- + +20100108 dholland in base + - Don't cut corners with relocs in mips-exception1.S. + +20100108 dholland in base + - Rearrange how curthread/curcpu get defined, so the mips gdb can + see curthread. + +20100108 dholland in base + - Disable BSS zeroing in loadelf, because VM systems should already + provide zeroed pages. Make dumbvm do so. + +20100108 dholland in base + - Add ASST3-OPT optimizing config. + +20100108 dholland in base + - Add the shell's design doc to design/. + - Add the usermalloc design doc to design/. + +20100108 dholland in base + - Fix outdated comment in start.S. + +20100108 dholland in base + - Move clocksleep() decl to . + +20100107 dholland in base + - Clarify various comments that seem lacking. + +20090427 dholland in base, from multiple students. + - Fix miscommented uio direction constants. Doh. + +20090424 dholland in base + - Add missing as_activate(NULL) during thread exit. + +20090416 dholland in base, mostly from Robert J. Helblin and Peter Salas. + - Fix err/warn vs. errx/warnx usage in various tests. + +20090413 dholland in base + - Use EFBIG, not EINVAL, for "file too large". + - Note that this and the following few changes were committed on a + separate branch for noncritical fixes that was merged after the + 1.99.04 release, which went to students as a mid-semester patch. + +20090402 dholland in base + - Make sbrk badcall "unaligned negative" really negative. + +20090402 dholland in base + - Add clarifying comments to struct tlbshootdown. + +20090320 dholland in base + - Fix DEBUG() so it accepts zero vararg parameters. + +20090214 dholland in base + - Remove some references to obsolete name "md_usermode". + +20090213 dholland in base + - Note that wchans don't promise to be FIFO. + +20090205 dholland in base + - Add missing 'volatile' to spinlock.h. + + +OS/161 1.99.04 released 20090414 +-------------------------------- + +20090414 dholland in base + - Fix typo in kern/sfs.h. + +20090414 dholland in base + - Fix up testbin/psort so it works adequately on sfs. + +20090413 dholland in base + - Make sfsck track indirect blocks in the free map right. + +20090413 dholland in base + - Fix bug where sfsck chokes on size 0 directories. + +20090413 dholland in base + - Fix case where sfsck can't add missing . and .. entries. + +20090413 dholland in base + - Add sfsck, simple check/recovery tool for sfs. + + +OS/161 1.99.03 released 20090402 +-------------------------------- + +20090402 dholland in base + - Fix build of testbin/malloctest. + +20090320 dholland in base + - Check CURCPU_EXISTS in spinlock_do_i_hold. + +20090313 dholland in base + - Fix threadlist iterator macros. + + +OS/161 1.99.02 released 20090219 +-------------------------------- + +20090219 dholland in base + - Add missing W* macros with waitpid in testbin progs. + +20090219 dholland in base + - Work around gcc tailcall bug affecting testbin/crash. + +20090219 dholland in base + - Fix missing vfs_biglock ops in vfs_getcwd(). + +20090219 dholland in base + - Fix bad userland declaration of lseek(). + +20090219 dholland in base + - Fix userland .depend file generation. + +20090219 dholland in base + - Add join32to64 and split64to32. + +20090219 dholland in base + - Clarify some comments in the mips syscall.c. + +20090219 dholland in base + - Make stack frames in assembly code 64-bit aligned. + +20090217 dholland in base + - Fix some glitches in the shell. + +20090210 dholland in base + - Fix interrupt level management in trap handling. + +20090209 dholland in base + - The on-chip timers can't be used for clocksleep(). + + +OS/161 1.99.01 released 20090203 +-------------------------------- + +20090202 dholland in base + - Don't ever migrate curthread to another cpu. + +20090202 dholland in base + - Use the W* wait macros in the shell. + +20090202 dholland in base + - Document the W* wait macros. + + +OS/161 1.99.00 released 20090202 +-------------------------------- + +20090201 dholland in base + - Implement kernel-side support for the GP register. + - Change kernel load address to waste less low memory. + - Add an input buffer to the console device. + - Fix some bugs. + +20090201 dholland in base + - Update man pages for 2.x. + +20090201 dholland in base + - Remove the built-in copy of make. Too much realism; it creates + unnecessary hassles. Just ship make with the toolchain. + +200901** dholland in base + - Assorted major hacking to prepare first pre-2.0 tree. + - Multiprocessor support. + - Improve organization of source tree. + - Add the shell (formerly in sol2) and user malloc (formerly in + sol3) to the base system. + +20081224 dholland in base + - Begin importing OS/161 1.x bits. (OS/161 2.x branches off from + what's projected to be OS/161 1.x release 1.12.) + + + + +OS/161 1.x change log +--------------------- + +20090115 dholland in base + - Fix wrong comment in lib.h. + +20090106 dholland in base + - Fix typo in error message in newvers.sh. + +20080825 dholland in base + - Fix typo in comment in start.S. + +20080825 dholland in base, reported by Melissa O'Neill a long time ago. + - Add curspl assertion to thread_yield. + + +OS/161 1.11 released 20050913 +----------------------------- + +20050907 dholland in base + - Minor changes for clean build under gcc 4.0.1. + +20050321 dholland in base, found by Qicheng Ma. + - Add volatile to testbin/ctest. + +20050307 dholland in base + - Create for vaddr_t/paddr_t. + +20050228 dholland in base, found by R.L. West. + - Some standards compliance. + +20040510 dholland in base, from Lukasz Strozek. + - Fix args handling in testbin/tail. + +20040204 dholland in base + - Be more consistent about refcounts in vfscwd.c. + + +OS/161 1.10 released 20040203 +----------------------------- + +20040203 dholland in base + - Support for hosting OS/161 on Solaris. + +20040202 dholland in base + - Update stdarg.h for gcc 3.x; remove machine/stdarg.h. + + +OS/161 1.09 released 20031227 +----------------------------- + +20031224 dholland in base + - Add missing man page for triplesort. + +20031224 dholland in base + - Fix failed compile in lnet.c, currently a null driver. + +20031224 dholland in base + - Fix badcall so it doesn't blow up on empty stdin. + +20031224 dholland in base, from Hassan Sultan. + - Fix argument handling in bin/ln. + +20031224 dholland in base, from Brian Greenberg. + - Fix link count leak in sfs_rename. + +20031224 dholland in base + - Fix silly use-after-free in an SFS mount error path. + +20031224 dholland in base, from Mike Hamburg. + - Fix unaligned sections in dumbvm. + +20031224 dholland in base + - Refer to assignments by content, not number, where possible. + - Change "asst1probs" to "synchprobs". + +20031224 dholland in base + - Fix some nonsensical but working code in /bin/pwd. + +20031224 dholland in base + - Update stack assertions in mips/trap.c for 4k stacks. + +20031224 dholland in base + - Install kernels using their configuration name. + +20031224 dholland in base + - Clarify some aspects of the locks/CVs API. + +20031224 dholland in base + - Fix assorted comment typos and glitches. + +20030626 dholland in base + - Commit the fix for a refcounting mistake in SFS. + +20030626 dholland in base + - Fix glitch in one of the dup2 tests in testbin/badcall. + +20030626 dholland in base + - Add missing sized type in mksfs/support.h. + +20030626 dholland in base + - Fix "make depend" glitch in dumpsfs. + +20030626 dholland in base + - Fix minor off-by-one error in menu code. + +20030421 dholland in base + - Fix assertion failure in kernel heap dump code. + +20030421 dholland in base + - Fix crash in testbin/dirconc. + + +OS/161 1.08 released 20030221 +----------------------------- +Apparently sol2-1.08 was not released until 20030310. + +20030309 dholland in sol2 + - Make shell accept being run with argc==0. + +20030309 dholland in sol2 + - Add support for WNOHANG to shell. + +20030221 dholland in base + - Fix broken hostcompat build with some Linux libcs. + +20030207 gwa/dholland in base + - Fix broken ASST1 build caused by rushed release. + + +OS/161 1.07 released 20030131 +----------------------------- + +20030131 gwa in base + - New assignment 1 problems for 2003. + +20030129 dholland in base + - Make console device full-duplex. + +20030129 dholland in base + - Check for short reads when loading executable headers. + +20030129 dholland in base + - Make rmtest a single standalone executable. + +20030129 dholland in base + - Make first thread stack also 4k rather than 8k. + +20030129 dholland in base + - Fix minor VFS bug handling multiple leading slashes. + +20030129 dholland in base + - Remove code duplication in triple* tests. + +20030129 dholland in base + - Add triplesort test (like triplemat). + +20030128 dholland in base + - Make f_test a single standalone executable. + +20030128 dholland in base + - Add t_ prefix to struct thread members for consistency. + +20030128 dholland in base + - bzero by words instead of bytes when properly aligned. + +20030128 dholland in base + - Add memcmp() to libc. + +20030127 dholland in base + - Minor fixes to parallelvm. + + +OS/161 1.06 released 20030117 +----------------------------- + +20030110 dholland in base + - Fix bug in setjmp/longjmp. + +20030110 dholland in base + - Add small explanatory comment to dev/lamebus/emu.c. + +20021120 dholland in base + - Have configure script provide NM and HOST_NM. + +20021120 dholland in base + - Merge hostcompat fixes for Mac OS X. + +20021001 dholland in base + - Avoid undefined C behavior in atoi(). + +20020920 dholland in base + - Provide string names for mips trap codes. + +20020920 dholland in base + - Fix handling of boot-time kernel memory faults. + + +OS/161 1.05 released 20020917 +----------------------------- + +20020913 dholland in base + - Created this changelog from CVS log data. + +20020904 dholland in base + - Cleanup/improvement for testbin/malloctest. + +20020904 dholland in sol2 + - Add code to shell to do timing of subprocesses. + +20020904 dholland in base + - Adjust prototype for __time() for hostcompat reasons. + +20020904 dholland in base + - Add parallelvm and dirconc to the default build. + +20020904 dholland in base + - Add mode to testbin/crash to fork and run everything. + +20020904 dholland in base + - Retry certain I/O errors in emufs and sfs. + +20020904 dholland in base + - Make vfs_close not fail. + +20020830 dholland in base + - Prohibit slashes and colons in volume names in mksfs. + +20020830 dholland in base + - _O_RDWRMASK -> O_ACCMODE, per POSIX. + +20020830 dholland in base + - Shrink kernel stacks from 8k to 4k. + +20020830 dholland in base + - Merge the code for the 'p' and 's' menu commands. + +20020830 dholland in base + - Don't use OPEN_MAX in the base system. + +20020829 dholland in base + - Include a copy of the error strings in the kernel. + +20020829 dholland in base + - Assert that spl is 0 on syscall entry and exit. + +20020829 dholland in base + - Fixes and new tests for testbin/badcall. + +20020829 dholland in base + - Add code and menu command for dumping kernel heap. + +20020827 dholland in base + - Close current directory at shutdown time. + +20020827 dholland in base + - Clear bootfs at shutdown time. + +20020827 dholland in base + - Remove extraneous magic argument from free_kpages(). + +20020827 dholland in base + - Fix dangling lock bug in emufs. + +20020826 dholland in base + - Man page fixes for read, write, waitpid. + +20020808 dholland in base + - Make Ant-32 port mostly work. + +20020625 dholland in base + - Kernel makefile tweak for stupid makes. + +20020618 dholland in base + - Fixes to the Ant-32 port. + +20020617 dholland in base + - Update the (unreleased) Ant-32 port. + +20020523 dholland in base + - Make matmult exit 1 on failure. + +20020523 dholland in base + - Fix various forking userlevel tests to wait properly. + +20020523 dholland in base + - Check for short reads when loading executables. + +20020523 dholland in base + - Fix bug in tt3 test. + +20020523 dholland in base + - Some make/build fixes. + +20020523 dholland in base + - More mips calling conventions fixes. + +20020522 dholland in base + - Fix bug in new mips exception code. + +20020522 dholland in base + - Revamp testbin/badcall. + +20020515 dholland in base + - Various accumulated minor cleanups and fixes. + +20020515 dholland in base + - New tests: dirconc, parallelvm. + +20020515 dholland in base + - Add missing V() in lhd driver. + +20020515 dholland in base + - Fixes for the thread code. + +20020515 dholland in base + - Tweak mips exception code for gdb's benefit. + +20020515 dholland in base + - Clean up dumbvm code. + +20020515 dholland in base + - Initialize mips stacks better, for gdb's benefit. + +20020425 dholland in base + - Fixes for testbin/f_test. + +20020424 dholland in base, found by Richard Eisenberg. + - Fix kmalloc bug. + +20020424 dholland in base + - Fix incorrect error codes in testbin/badcall. + +20020424 dholland in base + - Move stray assert in vfs code. + +20020407 dholland in base + - Fix off-by-one error in lhd driver. + +20020325 dholland in base + - Fix memory leak in malloctest. + +20020318 dholland in base + - Patch for race in thread_exit. (Fixed properly 5/15.) + +20020305 dholland in base + - Fix spl leak on thread_fork failure. + +20020305 dholland in base + - Fix for testbin/crash. + + +OS/161 1.04 released 20020216 +----------------------------- + +20020216 dholland in base + - Fix warning in kmalloc debugging code. + +20020216 dholland in base + - Adjust testbin/badcall to assignment 2 requirements. + +20020215 dholland in base + - Add cpu_halt() to supplement cpu_idle(), to fix crash. + +20020215 dholland in base + - Fixes for matmult. + +20020215 dholland in base + - Fix garbled comment in vm.h. + +20020215 dholland in base + - Fix prototype of _exit(). + +20020208 dholland in base + - Fix stack frame of mips __start for gdb's benefit. + +20020208 dholland in base + - Fix queue bug. + +20020208 dholland in base + - Fix bug in testbin/{badcall,crash,faulter}. + + +OS/161 1.03 released 20020131 +----------------------------- + +20020131 dholland in base + - Yield more on thread start (OPT_ASST1PROBS only). + +20020131 dholland in base + - Fix whalemating code to match assignment. + +20020131 dholland in base + - New synchronization problems for 2002. + +20020131 dholland in base + - Include fix in mips pcb.h. + +20020130 fedorova in base + - Adjust tt3 iteration counts/sizes. + +20020129 georgi in base + - Fix broken mksfs and dumpsfs build. + +20020124 dholland in base + - Put time() in libc; add __time() syscall. + +20020124 dholland in base + - Have hostcompat make stdout and stderr unbuffered. + +20020124 dholland in base + - Add sample optimizing config (ASST2-OPT). + +20020124 dholland in base + - New tests: dirseek, rmdirtest, triplemat. + +20020123 dholland in base + - Move matmult2 over original matmult. + +20020123 dholland in base + - Assert nobody's waiting when destroying a semaphore. + +20020123 dholland in base + - Add driver for new ltrace device. + +20020123 dholland in base + - Fix cosmetic bug in hardclock config. + +20020121 dholland in base + - Support ls over emufs. + +20020121 dholland in base + - Fix bug in copyinstr/copyoutstr code. + +20020121 dholland in base + - Fix broken Linux build of libhostcompat. + +20020119 dholland in base + - Alter dumbvm and loadelf for new toolchain. + +20020117 dholland in base + - Check for stack overflow during context switch. + +20020117 dholland in base + - Stop using -O2 with -g for mips. + +20020117 dholland in base + - More mips calling conventions fixes. + +20020117 dholland in base + - Correct the inline asm in spl.c. + +20020117 dholland in base + - Remove machine/inlineasm.h; fold into spl.c. + +20020117 dholland in base + - Avoid using default make-supplied CFLAGS. + +20020117 dholland in base + - Fix use of libhostcompat in mksfs and dumpsfs. + +20020117 dholland in base + - Fix cosmetic bug in configure script. + +20020116 dholland in base + - Adjust various things for new toolchain. + +20020110 dholland in base + - Install hostcompat includes properly. + +20020110 dholland in base + - Various fixes for new gcc (3.0.3) and binutils. + +20020104 dholland in base + - More man pages. + +20020103 dholland in base + - Remove excess register saves from mips context switch. + +20020103 dholland in base + - Move old getcwd to __getcwd; put POSIX getcwd in libc. + +20020103 dholland in base + - Tinker with tt3 test. + +20020102 dholland in base + - Change thread_fork so it can return errors. + +20020102 dholland in base + - Preallocate various things to avoid dying in mi_switch. + +20010925 dholland in base + - Add a bunch of consistency checks to sfs. + +20010925 dholland in base + - Fix bug in new panic code. + +20010925 dholland in base + - Add menu command to panic intentionally. + +20010925 dholland in base + - Fix bug in emufs. + +20010925 dholland in base + - memcpy by words instead of bytes when properly aligned. + +20010925 dholland in base + - Use setjmp() and longjmp() for aborting copyin/copyout. + +20010925 dholland in base + - Add code for setjmp() and longjmp(). + +20010921 dholland in base + - Add VOP_KILL (undoes VOP_INIT, which can now fail too.) + +20010921 dholland in base + - Fix race conditions in vnode reclaim. + +20010921 dholland in base + - Fix VFS behavior for things like "rmdir foo:". + + +OS/161 1.02 released 20010921 +----------------------------- + +20010921 dholland in base + - Revise device config/attach code. + +20010920 dholland in base + - Standards compliance fixes for strchr/strrchr. + +20010920 dholland in base + - Fix bug in system(). + +20010919 dholland in base + - More man pages. + +20010918 dholland in base + - Changed MAXNAMLEN to NAME_MAX. + +20010918 dholland in base + - Fix bug in kernel menu pwd command. + +20010918 dholland in base + - Panic handling improvements. + +20010918 dholland in base + - Kernel bootup and shutdown cleanup. + +20010918 dholland in base + - Fixes for testbin/badcall. + +20010824 dholland in base + - Make config script probe for . + +20010821 dholland in base + - Changes to queue code for consistent naming. + +20010808 dholland in base + - Add man pages. + +20010808 dholland in sol2 + - The shell can now use again, so do so. + +20010808 dholland in base + - Add explicit support for host-runnable programs. + +20010807 dholland in base + - Clean up -nostdinc/-nostdlib handling. + +20010807 dholland in base + - Fix bug in cp. + +20010807 dholland in base + - New test in testbin/crash. + +20010807 dholland in base + - Fixes for testbin/malloctest. + +20010806 dholland in base + - Fix glitch in testbin/badcall. + +20010806 dholland in base + - New test: randcall. + +20010804 dholland in base + - Add missing strrchr proto to . + +20010803 dholland in base + - Clean up ls; among other things, fix ls -R. + +20010803 dholland in base + - Fixes for testbin/badcall. + +20010803 dholland in base + - Add memset() to libc. + +20010803 dholland in base + - Split part of testbin/crash to new testbin/badcall. + +20010802 dholland in base + - Add comments to testbin describing intended uses. + +20010802 dholland in base + - Fix testbin/ctest to be large enough to be interesting. + +20010802 dholland in base + - Fix testbin/sort to be quicksort instead of bubblesort. + +20010802 dholland in base + - Various minor testbin fixes/cleanup. + +20010802 dholland in base + - Add dummy to make porting easier. + - Add dummy to make porting easier. + - Add dummy to make porting easier. + - Add dummy to make porting easier. + - Add dummy to make porting easier. + +20010802 dholland in base + - Have kfree deadbeef out free blocks. + +20010801 dholland in base + - Time execution of every kernel menu command. + +20010801 dholland in base + - Add getinterval() function for subtracting times. + +20010801 dholland in base + - Print commands as they execute from the command string. + +20010801 dholland in base + - New test tt3; add atoi from libc to kernel build. + +20010801 dholland in base + - Add memcpy from libc. + +20010801 dholland in base + - Fix size_t and add memcpy() to libc. + +20010801 dholland in base + - Reset mips TLB at boot time. + +20010801 dholland in base + - Revise kernel menu layout. + +20010801 dholland in base + - Add tests for arrays, bitmaps, queues, and semaphores. + +20010801 dholland in base + - Add "reconfig" rule to kernel makefiles. + +20010801 dholland in base + - Fix queue code. + +20010731 dholland in base + - Move main.c from kern/thread to kern/main. + +20010730 dholland in base + - Add kernel menu command to unmount things. + +20010730 dholland in base + - Add vfs_unmountall() for shutdown time. + +20010730 dholland in base + - Report mounts to the console as they happen. + +20010730 dholland in base + - Abolish pointless kernel shutdown functions. + +20010726 dholland in base + - Add config support for pseudo-devices. + - Add pseudorand device for when hardware is missing. + - Add random: device accessible through VFS. + +20010724 dholland in base + - Yield randomly at thread start if OPT_ASST1PROBS set. + +20010724 dholland in base + - Clarify comments in mips exception.S. + +20010724 dholland in base + - Don't allow calling P() from an interrupt handler. + +20010724 dholland in base + - Fixes for lser driver. + +20010723 dholland in base + - More mips calling conventions fixes. + +20010626 dholland in base + - Massive changes to kernel menu UI. + - Add pwd and sync to kernel menu. + +20010619 dholland in base + - Change as_copy so it can return error codes. + +20010619 dholland in base + - Merge bitmap_isset() from sol3. + +20010619 dholland in base + - Various fixes for new dumbvm. + +20010619 dholland in base + - Fix overly enthusiastic test in vnode_check(). + +20010619 dholland in base + - Provide a sketch of the skeleton for doing fork. + +20010618 dholland in base + - Add asserts to synch code. + +20010618 dholland in base + - Clean up/clarify syscall entry code. + +20010618 dholland in base + - New dumbvm supporting multiple address spaces. + +20010618 dholland in base + - Remove mips dependencies from loadelf.c. + +20010618 dholland in base + - Add hacks to prevent looping "Unknown syscall -1". + +20010615 dholland in base + - Merge the kmalloc and kfree from sol3. + +20010614 dholland in base + - Move kernel menu stuff to its own file. + +20010614 dholland in base + - Fixes for sfs and vfs layer. + +20010612 dholland in base + - Add sfs_rwblock to encapsulate sfs_device->d_io(). + +20010612 dholland in base + - Add lbolt and clocksleep() functionality to kernel. + +20010612 dholland in base + - Add -W to standard warning options. + +20010611 dholland in base + - Abolish rcsids. + +20010611 dholland in base + - Fix memory leak on error in thread_fork. + +20010611 dholland in base + - Don't panic if kmalloc fails. Add checks. + +20010611 dholland in base + - Add VOP_MAGIC to vnode ops tables, and lots of checks. + +20010611 dholland in base + - Add array_setguy(). + +20010608 dholland in base + - Add random() and srandom() to libc. + +20010608 dholland in base + - Add some framework for user-level malloc to libc. + +20010608 dholland in base + - Correct prototypes for read() and write(). + +20010608 dholland in base + - kprintf synchronization cleanups. + +20010523 dholland in sol2 + - Allow DEL as well as BS for backspacing in shell. + +20010523 dholland in base + - Add warning about the consequences of touching paddr 0. + +20010523 dholland in base + - Fix open count handling on VOP_CLOSE error. + +20010523 dholland in base + - New test: malloctest. + +20010428 dholland in base + - Handle multiple leading slashes on pathnames. + +20010423 dholland in base + - Fix deadlock in vfs layer. + +20010423 dholland in base + - Fix bug in testbin/dirtest. + +20010423 dholland in base + - Fix multiple bugs in ls. + +20010422 dholland in base + - Fix another bug in sfs. + +20010419 dholland in base, from Amos Blackman. + - Fix bug in sfs. + +20010416 dholland in base + - Fix fstest code. + +20010416 dholland in base + - Remove stray debug output from dumpsfs. + +20010414 dholland in base + - Makefile fix: build mksfs and dumpsfs by default. + - Fix host mksfs/dumpsfs build on DU. + +20010414 dholland in base, found by Dafina Toncheva. + - Fix bug in sfs. + +20010414 dholland in base + - Fix endianness bug in dumpsfs. + +20010414 dholland in base + - Do a sync at shutdown time. + +20010414 dholland in base + - Format depend.mk files consistently. + +20010414 dholland in base + - Fix memory leak in sfs. + +20010413 dholland in base + - Allow VOP_FSYNC on sfs directories. + +20010412 dholland in base + - Detect infinite loop triggerable by uio misuse. + +20010411 dholland in base + - Fix bug in bitmap code. + +20010406 dholland in base + - Fix calling conventions in mips asm code. + +20010323 dholland in base, found by Jeff DeSoto. + - Fix multi-sector lhd I/Os. + +20010322 dholland in base, found by Jeffrey Enos. + - Fix bug in comment in pcb.c. + +20010319 dholland in base + - Make matmult smaller. + +20010318 moorthi in base + - Fix bug in array code. + +20010314 dholland in base, found by Edward Lim. + - Fix bug in mv. + +20010314 dholland in base, found by Mike Vernal. + - Fix bug in testbin/crash. + +20010314 dholland in base + - Fix bug in bitmap code. + +20010308 moorthi in base + - Fix bug in sfs. + + +OS/161 1.01 released 20010226 +----------------------------- + +20010226 dholland in sol2 + - Shell fixes. + +20010226 dholland in base + - Add a lock to the console device. + +20010226 dholland in base + - Fix another bug in copyin/copyout code. + +20010226 dholland in base + - Use device name for FSes that don't return a volname. + - Add vfs_getdevname(). + +20010226 dholland in base + - Make /bin/pwd work in emufs. + - Fix two bugs in pwd. + +20010225 dholland in base + - Fix bug in mips copyin/copyout code. + - Fix bug in mips trap code. + +20010224 dholland in base + - Add appropriate volatile keywords in various places. + +20010224 dholland in base + - Fix synchronization in placeholder kmalloc. + +20010221 dholland in base + - Fix bug in CV code. + + +OS/161 1.00 released 20010208 +----------------------------- + +20010208 dholland in base + - Add EBADF to error list. + +20010208 dholland in base + - Fix specification of VOP_STAT. + +20010208 blackman in base + - Fix naming of queue functions. + +20010208 blackman in base + - Driver for lrandom device. + +20010207 dholland in base + - Check all calls to thread_fork for failure. + +20010206 dholland in base + - Fix comment in mips/specialreg.h. + +20010205 dholland in base + - Prevent recursive scheduler calls. (Fixes crash.) + +20010205 dholland in base + - Make syscall wrapper generation more robust. + +20010205 dholland in base + - Fix bug in cp. + + +OS/161 0.99 released 20010202 +----------------------------- + +20010202 dholland in base + - Add host-sh (host-runnable version) to sh makefile. + +20010202 dholland in base + - Add licensing boilerplate. + +20010201 dholland in base + - Switch from getfilesize() to fstat(). + +20010201 dholland in base + - Add system(). + +20010130 dholland in base + - Add strtok() and strtok_r(). + +20010129 dholland in base + - Add ELF code. + +20010111 dholland in base + - Fix bug in ls. + +20010103 dholland in base + - Initial checkin of development tree. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..37bfd2e --- /dev/null +++ b/Makefile @@ -0,0 +1,72 @@ +# +# Toplevel makefile for OS/161. +# +# +# Main rules: +# all (default): depend and compile system; install into staging area +# rebuild: likewise, but start with a clean slate. +# fullrebuild: likewise, but start with a very clean slate. +# +# What all does, in order: +# tools: depend and compile the tools used in build. +# includes: install header files. +# build: depend and compile the system. +# +# Other targets: +# depend: just update make dependency information. +# tags: generate/regenerate "tags" files. +# install: install into $(OSTREE). +# clean: remove generated files. +# distclean: remove all generated files. +# + +TOP=. +.include "$(TOP)/mk/os161.config.mk" + +all:; # make this first + +MKDIRS=$(OSTREE) + +.include "$(TOP)/mk/os161.mkdirs.mk" + +all: tools .WAIT includes .WAIT build + +rebuild: + $(MAKE) clean + $(MAKE) all + +fullrebuild: + $(MAKE) distclean + $(MAKE) all + +# currently no tools required, hence no tools/ dir or work to do +tools: + @true + +build: + (cd userland && $(MAKE) build) + (cd man && $(MAKE) install-staging) + (cd testscripts && $(MAKE) build) + +includes tags depend: + (cd kern && $(MAKE) $@) + (cd userland && $(MAKE) $@) + +clean: + (cd kern && $(MAKE) $@) + (cd userland && $(MAKE) $@) + rm -rf $(INSTALLTOP) + +distclean: clean + rm -rf $(WORKDIR) + +install: $(OSTREE) + (cd $(INSTALLTOP) && tar -cf - .) | (cd $(OSTREE) && tar -xvf -) + + +.PHONY: all rebuild fullrebuild tools build includes tags depend +.PHONY: clean distclean + +# old BSD name, same as distclean +cleandir: distclean +.PHONY: cleandir diff --git a/common/gcc-millicode/README b/common/gcc-millicode/README new file mode 100644 index 0000000..92913f3 --- /dev/null +++ b/common/gcc-millicode/README @@ -0,0 +1,7 @@ +These are support functions needed by gcc to perform operations on +64-bit integer types on 32-bit machines. The names are meaningful to +the gcc back end. The term "millicode" is sometimes used to describe +such compiler support code. + +This code was taken from NetBSD's src/common/lib/libc/quad, and +polished some for OS/161. diff --git a/common/gcc-millicode/adddi3.c b/common/gcc-millicode/adddi3.c new file mode 100644 index 0000000..af3b51e --- /dev/null +++ b/common/gcc-millicode/adddi3.c @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)adddi3.c 8.1 (Berkeley) 6/4/93 + * NetBSD: adddi3.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Add two long longs. This is trivial since a one-bit carry from a + * single unsigned int addition x+y occurs if and only if the sum x+y + * is less than either x or y (the choice to compare with x or y is + * arbitrary). + */ +long long +__adddi3(long long a, long long b) +{ + union uu aa, bb, sum; + + aa.ll = a; + bb.ll = b; + sum.ui[L] = aa.ui[L] + bb.ui[L]; + sum.ui[H] = aa.ui[H] + bb.ui[H] + (sum.ui[L] < bb.ui[L]); + return (sum.ll); +} diff --git a/common/gcc-millicode/anddi3.c b/common/gcc-millicode/anddi3.c new file mode 100644 index 0000000..007e0c5 --- /dev/null +++ b/common/gcc-millicode/anddi3.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)anddi3.c 8.1 (Berkeley) 6/4/93 + * NetBSD: anddi3.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Return a & b, in long long. + */ +long long +__anddi3(long long a, long long b) +{ + union uu aa, bb; + + aa.ll = a; + bb.ll = b; + aa.ui[0] &= bb.ui[0]; + aa.ui[1] &= bb.ui[1]; + return (aa.ll); +} diff --git a/common/gcc-millicode/ashldi3.c b/common/gcc-millicode/ashldi3.c new file mode 100644 index 0000000..4aa876e --- /dev/null +++ b/common/gcc-millicode/ashldi3.c @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)ashldi3.c 8.1 (Berkeley) 6/4/93 + * NetBSD: ashldi3.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Shift a (signed) long long value left (arithmetic shift left). + * This is the same as logical shift left! + */ +long long +__ashldi3(long long a, unsigned int shift) +{ + union uu aa; + + if (shift == 0) + return(a); + aa.ll = a; + if (shift >= INT_BITS) { + aa.ui[H] = aa.ui[L] << (shift - INT_BITS); + aa.ui[L] = 0; + } else { + aa.ui[H] = (aa.ui[H] << shift) | + (aa.ui[L] >> (INT_BITS - shift)); + aa.ui[L] <<= shift; + } + return (aa.ll); +} diff --git a/common/gcc-millicode/ashrdi3.c b/common/gcc-millicode/ashrdi3.c new file mode 100644 index 0000000..b143d6f --- /dev/null +++ b/common/gcc-millicode/ashrdi3.c @@ -0,0 +1,73 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)ashrdi3.c 8.1 (Berkeley) 6/4/93 + * NetBSD: ashrdi3.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Shift a (signed) long long value right (arithmetic shift right). + */ +long long +__ashrdi3(long long a, unsigned int shift) +{ + union uu aa; + + if (shift == 0) + return(a); + aa.ll = a; + if (shift >= INT_BITS) { + int s; + + /* + * Smear bits rightward using the machine's right-shift + * method, whether that is sign extension or zero fill, + * to get the `sign word' s. Note that shifting by + * INT_BITS is undefined, so we shift (INT_BITS-1), + * then 1 more, to get our answer. + */ + /* LINTED inherits machine dependency */ + s = (aa.si[H] >> (INT_BITS - 1)) >> 1; + /* LINTED inherits machine dependency*/ + aa.ui[L] = aa.si[H] >> (shift - INT_BITS); + aa.ui[H] = s; + } else { + aa.ui[L] = (aa.ui[L] >> shift) | + (aa.ui[H] << (INT_BITS - shift)); + /* LINTED inherits machine dependency */ + aa.si[H] >>= shift; + } + return (aa.ll); +} diff --git a/common/gcc-millicode/cmpdi2.c b/common/gcc-millicode/cmpdi2.c new file mode 100644 index 0000000..15e893e --- /dev/null +++ b/common/gcc-millicode/cmpdi2.c @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)cmpdi2.c 8.1 (Berkeley) 6/4/93 + * NetBSD: cmpdi2.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Return 0, 1, or 2 as a <, =, > b respectively. + * Both a and b are considered signed---which means only the high word is + * signed. + */ +int +__cmpdi2(long long a, long long b) +{ + union uu aa, bb; + + aa.ll = a; + bb.ll = b; + return (aa.si[H] < bb.si[H] ? 0 : aa.si[H] > bb.si[H] ? 2 : + aa.ui[L] < bb.ui[L] ? 0 : aa.ui[L] > bb.ui[L] ? 2 : 1); +} diff --git a/common/gcc-millicode/divdi3.c b/common/gcc-millicode/divdi3.c new file mode 100644 index 0000000..d1671dd --- /dev/null +++ b/common/gcc-millicode/divdi3.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)divdi3.c 8.1 (Berkeley) 6/4/93 + * NetBSD: divdi3.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Divide two signed long longs. + * ??? if -1/2 should produce -1 on this machine, this code is wrong + */ +long long +__divdi3(long long a, long long b) +{ + unsigned long long ua, ub, uq; + int neg = 0; + + ua = a; + ub = b; + + if (a < 0) + ua = -ua, neg ^= 1; + if (b < 0) + ub = -ub, neg ^= 1; + + uq = __qdivrem(ua, ub, NULL); + if (neg) + uq = - uq; + return uq; +} diff --git a/common/gcc-millicode/iordi3.c b/common/gcc-millicode/iordi3.c new file mode 100644 index 0000000..00ee2f2 --- /dev/null +++ b/common/gcc-millicode/iordi3.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)iordi3.c 8.1 (Berkeley) 6/4/93 + * NetBSD: iordi3.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Return a | b, in long long. + */ +long long +__iordi3(long long a, long long b) +{ + union uu aa, bb; + + aa.ll = a; + bb.ll = b; + aa.ui[0] |= bb.ui[0]; + aa.ui[1] |= bb.ui[1]; + return (aa.ll); +} diff --git a/common/gcc-millicode/longlong.h b/common/gcc-millicode/longlong.h new file mode 100644 index 0000000..ad33566 --- /dev/null +++ b/common/gcc-millicode/longlong.h @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)quad.h 8.1 (Berkeley) 6/4/93 + * NetBSD: quad.h,v 1.1 2005/12/20 20:29:40 christos Exp + */ + +/* + * Long long arithmetic. + * + * This library makes the following assumptions: + * + * - The type long long exists. + * + * - A long long variable is exactly twice as long as `int'. + * + * - The machine's arithmetic is two's complement. + * + * This library can provide 128-bit arithmetic on a machine with + * 128-bit long longs and 64-bit ints, for instance, or 96-bit + * arithmetic on machines with 48-bit ints. + * + * The names are built into gcc. + */ + +#if defined(_KERNEL) +#include +#include +#else +#include +#include +#endif + +#include + +/* + * Depending on the desired operation, we view a `long long' in + * one or more of the following formats. + */ +union uu { + long long ll; /* as a (signed) long long */ + unsigned long long ull; /* as an unsigned long long */ + int si[2]; /* as two (signed) ints */ + unsigned int ui[2]; /* as two unsigned ints */ +}; + +/* + * Define high and low parts of a long long. + */ +#if _BYTE_ORDER == _LITTLE_ENDIAN +#define H 1 +#define L 0 +#endif + +#if _BYTE_ORDER == _BIG_ENDIAN +#define H 0 +#define L 1 +#endif + + +/* + * Total number of bits in a long long and in the pieces that make it up. + * These are used for shifting, and also below for halfword extraction + * and assembly. + */ +#define LONGLONG_BITS (sizeof(long long) * CHAR_BIT) +#define INT_BITS (sizeof(int) * CHAR_BIT) +#define HALF_BITS (sizeof(int) * CHAR_BIT / 2) + +/* + * Extract high and low shortwords from longword, and move low shortword of + * longword to upper half of long, i.e., produce the upper longword of + * ((long long)(x) << (number_of_bits_in_int/2)). + * [`x' must actually be unsigned int.] + * + * These are used in the multiply code, to split a longword into upper + * and lower halves, and to reassemble a product as a long long, shifted + * left (sizeof(int)*CHAR_BIT/2). + */ +#define HHALF(x) ((unsigned int)(x) >> HALF_BITS) +#define LHALF(x) ((unsigned int)(x) & (((int)1 << HALF_BITS) - 1)) +#define LHUP(x) ((unsigned int)(x) << HALF_BITS) + +long long __adddi3 ( long long, long long); +long long __anddi3 ( long long, long long); +long long __ashldi3 ( long long, unsigned int); +long long __ashrdi3 ( long long, unsigned int); +int __cmpdi2 ( long long, long long); +long long __divdi3 ( long long, long long); +long long __iordi3 ( long long, long long); +long long __lshldi3 ( long long, unsigned int); +long long __lshrdi3 ( long long, unsigned int); +long long __moddi3 ( long long, long long); +long long __muldi3 ( long long, long long); +long long __negdi2 ( long long); +long long __one_cmpldi2 ( long long); +long long __subdi3 ( long long, long long); +int __ucmpdi2 (unsigned long long, unsigned long long); +unsigned long long __udivdi3 (unsigned long long, unsigned long long); +unsigned long long __umoddi3 (unsigned long long, unsigned long long); +long long __xordi3 ( long long, long long); + +#ifndef _KERNEL +long long __fixdfdi (double); +long long __fixsfdi (float); +unsigned long long __fixunsdfdi (double); +unsigned long long __fixunssfdi (float); +double __floatdidf (long long); +float __floatdisf (long long); +double __floatunsdidf(unsigned long long); +#endif + +unsigned long long __qdivrem (unsigned long long, unsigned long long, + unsigned long long *); diff --git a/common/gcc-millicode/lshldi3.c b/common/gcc-millicode/lshldi3.c new file mode 100644 index 0000000..dd96581 --- /dev/null +++ b/common/gcc-millicode/lshldi3.c @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)lshldi3.c 8.1 (Berkeley) 6/4/93 + * NetBSD: lshldi3.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Shift an (unsigned) long long value left (logical shift left). + * This is the same as arithmetic shift left! + */ +long long +__lshldi3(long long a, unsigned int shift) +{ + union uu aa; + + if (shift == 0) + return(a); + aa.ll = a; + if (shift >= INT_BITS) { + aa.ui[H] = aa.ui[L] << (shift - INT_BITS); + aa.ui[L] = 0; + } else { + aa.ui[H] = (aa.ui[H] << shift) | + (aa.ui[L] >> (INT_BITS - shift)); + aa.ui[L] <<= shift; + } + return (aa.ll); +} diff --git a/common/gcc-millicode/lshrdi3.c b/common/gcc-millicode/lshrdi3.c new file mode 100644 index 0000000..c555fea --- /dev/null +++ b/common/gcc-millicode/lshrdi3.c @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)lshrdi3.c 8.1 (Berkeley) 6/4/93 + * $NetBSD: lshrdi3.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Shift an (unsigned) long long value right (logical shift right). + */ +long long +__lshrdi3(long long a, unsigned int shift) +{ + union uu aa; + + if (shift == 0) + return(a); + aa.ll = a; + if (shift >= INT_BITS) { + aa.ui[L] = aa.ui[H] >> (shift - INT_BITS); + aa.ui[H] = 0; + } else { + aa.ui[L] = (aa.ui[L] >> shift) | + (aa.ui[H] << (INT_BITS - shift)); + aa.ui[H] >>= shift; + } + return (aa.ll); +} diff --git a/common/gcc-millicode/moddi3.c b/common/gcc-millicode/moddi3.c new file mode 100644 index 0000000..ac53705 --- /dev/null +++ b/common/gcc-millicode/moddi3.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)moddi3.c 8.1 (Berkeley) 6/4/93 + * NetBSD: moddi3.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Return remainder after dividing two signed long longs. + * + * XXX we assume a % b < 0 iff a < 0, but this is actually machine-dependent. + */ +long long +__moddi3(long long a, long long b) +{ + unsigned long long ua, ub, ur; + int neg = 0; + + ua = a; + ub = b; + + if (a < 0) + ua = -ua, neg ^= 1; + if (b < 0) + ub = -ub; + (void)__qdivrem(ua, ub, &ur); + if (neg) + ur = -ur; + return (ur); +} diff --git a/common/gcc-millicode/muldi3.c b/common/gcc-millicode/muldi3.c new file mode 100644 index 0000000..1cef86c --- /dev/null +++ b/common/gcc-millicode/muldi3.c @@ -0,0 +1,241 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)muldi3.c 8.1 (Berkeley) 6/4/93 + * NetBSD: muldi3.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Multiply two long longs. + * + * Our algorithm is based on the following. Split incoming long long + * values u and v (where u,v >= 0) into + * + * u = 2^n u1 * u0 (n = number of bits in `unsigned int', usu. 32) + * + * and + * + * v = 2^n v1 * v0 + * + * Then + * + * uv = 2^2n u1 v1 + 2^n u1 v0 + 2^n v1 u0 + u0 v0 + * = 2^2n u1 v1 + 2^n (u1 v0 + v1 u0) + u0 v0 + * + * Now add 2^n u1 v1 to the first term and subtract it from the middle, + * and add 2^n u0 v0 to the last term and subtract it from the middle. + * This gives: + * + * uv = (2^2n + 2^n) (u1 v1) + + * (2^n) (u1 v0 - u1 v1 + u0 v1 - u0 v0) + + * (2^n + 1) (u0 v0) + * + * Factoring the middle a bit gives us: + * + * uv = (2^2n + 2^n) (u1 v1) + [u1v1 = high] + * (2^n) (u1 - u0) (v0 - v1) + [(u1-u0)... = mid] + * (2^n + 1) (u0 v0) [u0v0 = low] + * + * The terms (u1 v1), (u1 - u0) (v0 - v1), and (u0 v0) can all be done + * in just half the precision of the original. (Note that either or both + * of (u1 - u0) or (v0 - v1) may be negative.) + * + * This algorithm is from Knuth vol. 2 (2nd ed), section 4.3.3, p. 278. + * + * Since C does not give us a `int * int = long long' operator, we split + * our input long longs into two ints, then split the two ints into two + * shorts. We can then calculate `short * short = int' in native + * arithmetic. + * + * Our product should, strictly speaking, be a `long long long', with + * 128 bits, but we are going to discard the upper 64. In other words, + * we are not interested in uv, but rather in (uv mod 2^2n). This + * makes some of the terms above vanish, and we get: + * + * (2^n)(high) + (2^n)(mid) + (2^n + 1)(low) + * + * or + * + * (2^n)(high + mid + low) + low + * + * Furthermore, `high' and `mid' can be computed mod 2^n, as any factor + * of 2^n in either one will also vanish. Only `low' need be computed + * mod 2^2n, and only because of the final term above. + */ +static long long __lmulq(unsigned int, unsigned int); + +long long +__muldi3(long long a, long long b) +{ + union uu u, v, low, prod; + unsigned int high, mid, udiff, vdiff; + int negall, negmid; +#define u1 u.ui[H] +#define u0 u.ui[L] +#define v1 v.ui[H] +#define v0 v.ui[L] + + /* + * Get u and v such that u, v >= 0. When this is finished, + * u1, u0, v1, and v0 will be directly accessible through the + * int fields. + */ + if (a >= 0) + u.ll = a, negall = 0; + else + u.ll = -a, negall = 1; + if (b >= 0) + v.ll = b; + else + v.ll = -b, negall ^= 1; + + if (u1 == 0 && v1 == 0) { + /* + * An (I hope) important optimization occurs when u1 and v1 + * are both 0. This should be common since most numbers + * are small. Here the product is just u0*v0. + */ + prod.ll = __lmulq(u0, v0); + } else { + /* + * Compute the three intermediate products, remembering + * whether the middle term is negative. We can discard + * any upper bits in high and mid, so we can use native + * unsigned int * unsigned int => unsigned int arithmetic. + */ + low.ll = __lmulq(u0, v0); + + if (u1 >= u0) + negmid = 0, udiff = u1 - u0; + else + negmid = 1, udiff = u0 - u1; + if (v0 >= v1) + vdiff = v0 - v1; + else + vdiff = v1 - v0, negmid ^= 1; + mid = udiff * vdiff; + + high = u1 * v1; + + /* + * Assemble the final product. + */ + prod.ui[H] = high + (negmid ? -mid : mid) + low.ui[L] + + low.ui[H]; + prod.ui[L] = low.ui[L]; + } + return (negall ? -prod.ll : prod.ll); +#undef u1 +#undef u0 +#undef v1 +#undef v0 +} + +/* + * Multiply two 2N-bit ints to produce a 4N-bit long long, where N is + * half the number of bits in an int (whatever that is---the code + * below does not care as long as the header file does its part of the + * bargain---but typically N==16). + * + * We use the same algorithm from Knuth, but this time the modulo refinement + * does not apply. On the other hand, since N is half the size of an int, + * we can get away with native multiplication---none of our input terms + * exceeds (UINT_MAX >> 1). + * + * Note that, for unsigned int l, the quad-precision (long long) result + * + * l << N + * + * splits into high and low ints as HHALF(l) and LHUP(l) respectively. + */ +static long long +__lmulq(unsigned int u, unsigned int v) +{ + unsigned int u1, u0, v1, v0, udiff, vdiff, high, mid, low; + unsigned int prodh, prodl, was; + union uu prod; + int neg; + + u1 = HHALF(u); + u0 = LHALF(u); + v1 = HHALF(v); + v0 = LHALF(v); + + low = u0 * v0; + + /* This is the same small-number optimization as before. */ + if (u1 == 0 && v1 == 0) + return (low); + + if (u1 >= u0) + udiff = u1 - u0, neg = 0; + else + udiff = u0 - u1, neg = 1; + if (v0 >= v1) + vdiff = v0 - v1; + else + vdiff = v1 - v0, neg ^= 1; + mid = udiff * vdiff; + + high = u1 * v1; + + /* prod = (high << 2N) + (high << N); */ + prodh = high + HHALF(high); + prodl = LHUP(high); + + /* if (neg) prod -= mid << N; else prod += mid << N; */ + if (neg) { + was = prodl; + prodl -= LHUP(mid); + prodh -= HHALF(mid) + (prodl > was); + } else { + was = prodl; + prodl += LHUP(mid); + prodh += HHALF(mid) + (prodl < was); + } + + /* prod += low << N */ + was = prodl; + prodl += LHUP(low); + prodh += HHALF(low) + (prodl < was); + /* ... + low; */ + if ((prodl += low) < low) + prodh++; + + /* return 4N-bit product */ + prod.ui[H] = prodh; + prod.ui[L] = prodl; + return (prod.ll); +} diff --git a/common/gcc-millicode/negdi2.c b/common/gcc-millicode/negdi2.c new file mode 100644 index 0000000..abb7973 --- /dev/null +++ b/common/gcc-millicode/negdi2.c @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)negdi2.c 8.1 (Berkeley) 6/4/93 + * NetBSD: negdi2.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Return -a (or, equivalently, 0 - a), in long long. See subdi3.c. + */ +long long +__negdi2(long long a) +{ + union uu aa, res; + + aa.ll = a; + res.ui[L] = -aa.ui[L]; + res.ui[H] = -aa.ui[H] - (res.ui[L] > 0); + return (res.ll); +} diff --git a/common/gcc-millicode/notdi2.c b/common/gcc-millicode/notdi2.c new file mode 100644 index 0000000..614cd32 --- /dev/null +++ b/common/gcc-millicode/notdi2.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)notdi2.c 8.1 (Berkeley) 6/4/93 + * NetBSD: notdi2.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Return ~a. For some reason gcc calls this `one's complement' rather + * than `not'. + */ +long long +__one_cmpldi2(long long a) +{ + union uu aa; + + aa.ll = a; + aa.ui[0] = ~aa.ui[0]; + aa.ui[1] = ~aa.ui[1]; + return (aa.ll); +} diff --git a/common/gcc-millicode/qdivrem.c b/common/gcc-millicode/qdivrem.c new file mode 100644 index 0000000..5c43da5 --- /dev/null +++ b/common/gcc-millicode/qdivrem.c @@ -0,0 +1,279 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)qdivrem.c 8.1 (Berkeley) 6/4/93 + * NetBSD: qdivrem.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +/* + * Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed), + * section 4.3.1, pp. 257--259. + */ + +#include "longlong.h" + +#define B ((int)1 << HALF_BITS) /* digit base */ + +/* Combine two `digits' to make a single two-digit number. */ +#define COMBINE(a, b) (((unsigned int)(a) << HALF_BITS) | (b)) + +/* select a type for digits in base B: use unsigned short if they fit */ +#if UINT_MAX == 0xffffffffU && USHRT_MAX >= 0xffff +typedef unsigned short digit; +#else +typedef unsigned int digit; +#endif + +static void shl(digit *p, int len, int sh); + +/* + * __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v. + * + * We do this in base 2-sup-HALF_BITS, so that all intermediate + * products fit within unsigned int. As a consequence, the maximum + * length dividend and divisor are 4 `digits' in this base (they are + * shorter if they have leading zeros). + */ +unsigned long long +__qdivrem(unsigned long long ull, unsigned long long vll, + unsigned long long *arq) +{ + union uu tmp; + digit *u, *v, *q; + digit v1, v2; + unsigned int qhat, rhat, t; + int m, n, d, j, i; + digit uspace[5], vspace[5], qspace[5]; + + /* + * Take care of special cases: divide by zero, and u < v. + */ + if (vll == 0) { + /* divide by zero. */ + static volatile const unsigned int zero = 0; + + tmp.ui[H] = tmp.ui[L] = 1 / zero; + if (arq) + *arq = ull; + return (tmp.ll); + } + if (ull < vll) { + if (arq) + *arq = ull; + return (0); + } + u = &uspace[0]; + v = &vspace[0]; + q = &qspace[0]; + + /* + * Break dividend and divisor into digits in base B, then + * count leading zeros to determine m and n. When done, we + * will have: + * u = (u[1]u[2]...u[m+n]) sub B + * v = (v[1]v[2]...v[n]) sub B + * v[1] != 0 + * 1 < n <= 4 (if n = 1, we use a different division algorithm) + * m >= 0 (otherwise u < v, which we already checked) + * m + n = 4 + * and thus + * m = 4 - n <= 2 + */ + tmp.ull = ull; + u[0] = 0; + u[1] = (digit)HHALF(tmp.ui[H]); + u[2] = (digit)LHALF(tmp.ui[H]); + u[3] = (digit)HHALF(tmp.ui[L]); + u[4] = (digit)LHALF(tmp.ui[L]); + tmp.ull = vll; + v[1] = (digit)HHALF(tmp.ui[H]); + v[2] = (digit)LHALF(tmp.ui[H]); + v[3] = (digit)HHALF(tmp.ui[L]); + v[4] = (digit)LHALF(tmp.ui[L]); + for (n = 4; v[1] == 0; v++) { + if (--n == 1) { + unsigned int rbj; /* r*B+u[j] (not root boy jim) */ + digit q1, q2, q3, q4; + + /* + * Change of plan, per exercise 16. + * r = 0; + * for j = 1..4: + * q[j] = floor((r*B + u[j]) / v), + * r = (r*B + u[j]) % v; + * We unroll this completely here. + */ + t = v[2]; /* nonzero, by definition */ + q1 = (digit)(u[1] / t); + rbj = COMBINE(u[1] % t, u[2]); + q2 = (digit)(rbj / t); + rbj = COMBINE(rbj % t, u[3]); + q3 = (digit)(rbj / t); + rbj = COMBINE(rbj % t, u[4]); + q4 = (digit)(rbj / t); + if (arq) + *arq = rbj % t; + tmp.ui[H] = COMBINE(q1, q2); + tmp.ui[L] = COMBINE(q3, q4); + return (tmp.ll); + } + } + + /* + * By adjusting q once we determine m, we can guarantee that + * there is a complete four-digit quotient at &qspace[1] when + * we finally stop. + */ + for (m = 4 - n; u[1] == 0; u++) + m--; + for (i = 4 - m; --i >= 0;) + q[i] = 0; + q += 4 - m; + + /* + * Here we run Program D, translated from MIX to C and acquiring + * a few minor changes. + * + * D1: choose multiplier 1 << d to ensure v[1] >= B/2. + */ + d = 0; + for (t = v[1]; t < B / 2; t <<= 1) + d++; + if (d > 0) { + shl(&u[0], m + n, d); /* u <<= d */ + shl(&v[1], n - 1, d); /* v <<= d */ + } + /* + * D2: j = 0. + */ + j = 0; + v1 = v[1]; /* for D3 -- note that v[1..n] are constant */ + v2 = v[2]; /* for D3 */ + do { + digit uj0, uj1, uj2; + + /* + * D3: Calculate qhat (\^q, in TeX notation). + * Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and + * let rhat = (u[j]*B + u[j+1]) mod v[1]. + * While rhat < B and v[2]*qhat > rhat*B+u[j+2], + * decrement qhat and increase rhat correspondingly. + * Note that if rhat >= B, v[2]*qhat < rhat*B. + */ + uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */ + uj1 = u[j + 1]; /* for D3 only */ + uj2 = u[j + 2]; /* for D3 only */ + if (uj0 == v1) { + qhat = B; + rhat = uj1; + goto qhat_too_big; + } else { + unsigned int nn = COMBINE(uj0, uj1); + qhat = nn / v1; + rhat = nn % v1; + } + while (v2 * qhat > COMBINE(rhat, uj2)) { + qhat_too_big: + qhat--; + if ((rhat += v1) >= B) + break; + } + /* + * D4: Multiply and subtract. + * The variable `t' holds any borrows across the loop. + * We split this up so that we do not require v[0] = 0, + * and to eliminate a final special case. + */ + for (t = 0, i = n; i > 0; i--) { + t = u[i + j] - v[i] * qhat - t; + u[i + j] = (digit)LHALF(t); + t = (B - HHALF(t)) & (B - 1); + } + t = u[j] - t; + u[j] = (digit)LHALF(t); + /* + * D5: test remainder. + * There is a borrow if and only if HHALF(t) is nonzero; + * in that (rare) case, qhat was too large (by exactly 1). + * Fix it by adding v[1..n] to u[j..j+n]. + */ + if (HHALF(t)) { + qhat--; + for (t = 0, i = n; i > 0; i--) { /* D6: add back. */ + t += u[i + j] + v[i]; + u[i + j] = (digit)LHALF(t); + t = HHALF(t); + } + u[j] = (digit)LHALF(u[j] + t); + } + q[j] = (digit)qhat; + } while (++j <= m); /* D7: loop on j. */ + + /* + * If caller wants the remainder, we have to calculate it as + * u[m..m+n] >> d (this is at most n digits and thus fits in + * u[m+1..m+n], but we may need more source digits). + */ + if (arq) { + if (d) { + for (i = m + n; i > m; --i) + u[i] = (digit)(((unsigned int)u[i] >> d) | + LHALF((unsigned int)u[i - 1] << + (HALF_BITS - d))); + u[i] = 0; + } + tmp.ui[H] = COMBINE(uspace[1], uspace[2]); + tmp.ui[L] = COMBINE(uspace[3], uspace[4]); + *arq = tmp.ll; + } + + tmp.ui[H] = COMBINE(qspace[1], qspace[2]); + tmp.ui[L] = COMBINE(qspace[3], qspace[4]); + return (tmp.ll); +} + +/* + * Shift p[0]..p[len] left `sh' bits, ignoring any bits that + * `fall out' the left (there never will be any such anyway). + * We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS. + */ +static void +shl(digit *p, int len, int sh) +{ + int i; + + for (i = 0; i < len; i++) + p[i] = (digit)(LHALF((unsigned int)p[i] << sh) | + ((unsigned int)p[i + 1] >> (HALF_BITS - sh))); + p[i] = (digit)(LHALF((unsigned int)p[i] << sh)); +} diff --git a/common/gcc-millicode/subdi3.c b/common/gcc-millicode/subdi3.c new file mode 100644 index 0000000..1e95350 --- /dev/null +++ b/common/gcc-millicode/subdi3.c @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)subdi3.c 8.1 (Berkeley) 6/4/93 + * NetBSD: subdi3.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Subtract two long long values. This is trivial since a one-bit + * carry from a single unsigned int difference x-y occurs if and only + * if (x-y) > x. + */ +long long +__subdi3(long long a, long long b) +{ + union uu aa, bb, diff; + + aa.ll = a; + bb.ll = b; + diff.ui[L] = aa.ui[L] - bb.ui[L]; + diff.ui[H] = aa.ui[H] - bb.ui[H] - (diff.ui[L] > aa.ui[L]); + return (diff.ll); +} diff --git a/common/gcc-millicode/ucmpdi2.c b/common/gcc-millicode/ucmpdi2.c new file mode 100644 index 0000000..b7e1a47 --- /dev/null +++ b/common/gcc-millicode/ucmpdi2.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)ucmpdi2.c 8.1 (Berkeley) 6/4/93 + * NetBSD: ucmpdi2.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Return 0, 1, or 2 as a <, =, > b respectively. + * Neither a nor b are considered signed. + */ +int +__ucmpdi2(unsigned long long a, unsigned long long b) +{ + union uu aa, bb; + + aa.ull = a; + bb.ull = b; + return (aa.ui[H] < bb.ui[H] ? 0 : aa.ui[H] > bb.ui[H] ? 2 : + aa.ui[L] < bb.ui[L] ? 0 : aa.ui[L] > bb.ui[L] ? 2 : 1); +} diff --git a/common/gcc-millicode/udivdi3.c b/common/gcc-millicode/udivdi3.c new file mode 100644 index 0000000..89cdf00 --- /dev/null +++ b/common/gcc-millicode/udivdi3.c @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)udivdi3.c 8.1 (Berkeley) 6/4/93 + * NetBSD: udivdi3.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Divide two unsigned long longs. + */ +unsigned long long +__udivdi3(unsigned long long a, unsigned long long b) +{ + + return __qdivrem(a, b, NULL); +} diff --git a/common/gcc-millicode/umoddi3.c b/common/gcc-millicode/umoddi3.c new file mode 100644 index 0000000..0e403d1 --- /dev/null +++ b/common/gcc-millicode/umoddi3.c @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)umoddi3.c 8.1 (Berkeley) 6/4/93 + * NetBSD: umoddi3.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Return remainder after dividing two unsigned long longs. + */ +unsigned long long +__umoddi3(unsigned long long a, unsigned long long b) +{ + unsigned long long r; + + (void)__qdivrem(a, b, &r); + return (r); +} diff --git a/common/gcc-millicode/xordi3.c b/common/gcc-millicode/xordi3.c new file mode 100644 index 0000000..010603b --- /dev/null +++ b/common/gcc-millicode/xordi3.c @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: + * @(#)xordi3.c 8.1 (Berkeley) 6/4/93 + * NetBSD: xordi3.c,v 1.1 2005/12/20 19:28:51 christos Exp + */ + +#include "longlong.h" + +/* + * Return a ^ b, in long long. + */ +long long +__xordi3(long long a, long long b) +{ + union uu aa, bb; + + aa.ll = a; + bb.ll = b; + aa.ui[0] ^= bb.ui[0]; + aa.ui[1] ^= bb.ui[1]; + return (aa.ll); +} diff --git a/common/libc/arch/mips/setjmp.S b/common/libc/arch/mips/setjmp.S new file mode 100644 index 0000000..3ad60df --- /dev/null +++ b/common/libc/arch/mips/setjmp.S @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * setjmp and longjmp for MIPS. + */ + +#include + + .text + .set noreorder + + /* + * int setjmp(jmp_buf jb); + * + * Save the current state so we can return again from the call later + * if/when longjmp is called. (If the function that called setjmp + * returns before longjmp is called, the results are undefined. We + * only need to save registers, not the whole contents of the stack.) + */ + + .globl setjmp + .type setjmp,@function + .ent setjmp +setjmp: + /* + * jmp_buf is in a0. We need to save s0-s8, sp, and ra in it. + * Don't store more registers without adjusting machine/setjmp.h. + */ + + sw sp, 0(a0) /* save registers */ + sw ra, 4(a0) + sw s0, 8(a0) + sw s1, 12(a0) + sw s2, 16(a0) + sw s3, 20(a0) + sw s4, 24(a0) + sw s5, 28(a0) + sw s6, 32(a0) + sw s7, 36(a0) + sw s8, 40(a0) + + j ra /* done */ + li v0, 0 /* return 0 (in delay slot) */ + .end setjmp + + + /* + * void longjmp(jmp_buf jb, int code); + */ + .globl longjmp + .type longjmp,@function + .ent longjmp +longjmp: + /* + * jmp_buf is in a0. Return code is in a1. + * We need to restore s0-s8, sp, and ra from the jmp_buf. + * The return code is forced to 1 if 0 is passed in. + */ + + sltiu t0, a1, 1 /* set t0 to 1 if return code is 0... otherwise 0 */ + addu a1, a1, t0 /* update the return code */ + + lw sp, 0(a0) /* restore registers */ + lw ra, 4(a0) + lw s0, 8(a0) + lw s1, 12(a0) + lw s2, 16(a0) + lw s3, 20(a0) + lw s4, 24(a0) + lw s5, 28(a0) + lw s6, 32(a0) + lw s7, 36(a0) + lw s8, 40(a0) + + j ra /* return, to where setjmp was called from */ + move v0, a1 /* set return value */ + .end longjmp diff --git a/common/libc/printf/__printf.c b/common/libc/printf/__printf.c new file mode 100644 index 0000000..b2476b4 --- /dev/null +++ b/common/libc/printf/__printf.c @@ -0,0 +1,592 @@ +/* + * Copyright (c) 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Guts of printf. + * + * This file is used in both libc and the kernel and needs to work in both + * contexts. This makes a few things a bit awkward. + * + * This is a slightly simplified version of the real-life printf + * originally used in the VINO kernel. + */ + +#ifdef _KERNEL +#include +#include +#define assert KASSERT +#else + +#include +#include +#include +#include +#include +#endif + +#include + + +/* + * Do we want to support "long long" types with %lld? + * + * Using 64-bit types with gcc causes gcc to emit calls to functions + * like __moddi3 and __divdi3. These need to be provided at link time, + * which can be a hassle; this switch is provided to help avoid + * needing them. + */ +#define USE_LONGLONG + +/* + * Define a type that holds the longest signed integer we intend to support. + */ +#ifdef USE_LONGLONG +#define INTTYPE long long +#else +#define INTTYPE long +#endif + + +/* + * Space for a long long in base 8, plus a NUL, plus one + * character extra for slop. + * + * CHAR_BIT is the number of bits in a char; thus sizeof(long long)*CHAR_BIT + * is the number of bits in a long long. Each octal digit prints 3 bits. + * Values printed in larger bases will be shorter strings. + */ +#define NUMBER_BUF_SIZE ((sizeof(INTTYPE) * CHAR_BIT) / 3 + 2) + +/* + * Structure holding the state for printf. + */ +typedef struct { + /* Callback for sending printed string data */ + void (*sendfunc)(void *clientdata, const char *str, size_t len); + void *clientdata; + + /* The varargs argument pointer */ + va_list ap; + + /* Total count of characters printed */ + int charcount; + + /* Flag that's true if we are currently looking in a %-format */ + int in_pct; + + /* Size of the integer argument to retrieve */ + enum { + INTSZ, + LONGSZ, +#ifdef USE_LONGLONG + LLONGSZ, +#endif + SIZETSZ, + } size; + + /* The value of the integer argument retrieved */ + unsigned INTTYPE num; + + /* Sign of the integer argument (0 = positive; -1 = negative) */ + int sign; + + /* Field width (number of spaces) */ + int spacing; + + /* Flag: align to left in field instead of right */ + int rightspc; + + /* Character to pad to field size with (space or 0) */ + int fillchar; + + /* Number base to print the integer argument in (8, 10, 16) */ + int base; + + /* Flag: if set, print 0x before hex and 0 before octal numbers */ + int baseprefix; + + /* Flag: alternative output format selected with %#... */ + int altformat; +} PF; + +/* + * Send some text onward to the output. + * + * We count the total length we send out so we can return it from __vprintf, + * since that's what most printf-like functions want to return. + */ +static +void +__pf_print(PF *pf, const char *txt, size_t len) +{ + pf->sendfunc(pf->clientdata, txt, len); + pf->charcount += len; +} + +/* + * Reset the state for the next %-field. + */ +static +void +__pf_endfield(PF *pf) +{ + pf->in_pct = 0; + pf->size = INTSZ; + pf->num = 0; + pf->sign = 0; + pf->spacing = 0; + pf->rightspc = 0; + pf->fillchar = ' '; + pf->base = 0; + pf->baseprefix = 0; + pf->altformat = 0; +} + +/* + * Process modifier chars (between the % and the type specifier) + * # use "alternate display format" + * - left align in field instead of right align + * l value is long (ll = long long) + * z value is size_t + * 0-9 field width + * leading 0 pad with zeros instead of spaces + */ +static +void +__pf_modifier(PF *pf, int ch) +{ + switch (ch) { + case '#': + pf->altformat = 1; + break; + case '-': + pf->rightspc = 1; + break; + case 'l': + if (pf->size==LONGSZ) { +#ifdef USE_LONGLONG + pf->size = LLONGSZ; +#endif + } + else { + pf->size = LONGSZ; + } + break; + case 'z': + pf->size = SIZETSZ; + break; + case '0': + if (pf->spacing>0) { + /* + * Already seen some digits; this is part of the + * field size. + */ + pf->spacing = pf->spacing*10; + } + else { + /* + * Leading zero; set the padding character to 0. + */ + pf->fillchar = '0'; + } + break; + default: + /* + * Invalid characters should be filtered out by a + * higher-level function, so if this assert goes off + * it's our fault. + */ + assert(ch>'0' && ch<='9'); + + /* + * Got a digit; accumulate the field size. + */ + pf->spacing = pf->spacing*10 + (ch-'0'); + break; + } +} + +/* + * Retrieve a numeric argument from the argument list and store it + * in pf->num, according to the size recorded in pf->size and using + * the numeric type specified by ch. + */ +static +void +__pf_getnum(PF *pf, int ch) +{ + if (ch=='p') { + /* + * Pointer. + * + * uintptr_t is a C99 standard type that's an unsigned + * integer the same size as a pointer. + */ + pf->num = (uintptr_t) va_arg(pf->ap, void *); + } + else if (ch=='d') { + /* signed integer */ + INTTYPE signednum=0; + switch (pf->size) { + case INTSZ: + /* %d */ + signednum = va_arg(pf->ap, int); + break; + case LONGSZ: + /* %ld */ + signednum = va_arg(pf->ap, long); + break; +#ifdef USE_LONGLONG + case LLONGSZ: + /* %lld */ + signednum = va_arg(pf->ap, long long); + break; +#endif + case SIZETSZ: + /* %zd */ + signednum = va_arg(pf->ap, ssize_t); + break; + } + + /* + * Check for negative numbers. + */ + if (signednum < 0) { + pf->sign = -1; + pf->num = -signednum; + } + else { + pf->num = signednum; + } + } + else { + /* unsigned integer */ + switch (pf->size) { + case INTSZ: + /* %u (or %o, %x) */ + pf->num = va_arg(pf->ap, unsigned int); + break; + case LONGSZ: + /* %lu (or %lo, %lx) */ + pf->num = va_arg(pf->ap, unsigned long); + break; +#ifdef USE_LONGLONG + case LLONGSZ: + /* %llu, %llo, %llx */ + pf->num = va_arg(pf->ap, unsigned long long); + break; +#endif + case SIZETSZ: + /* %zu, %zo, %zx */ + pf->num = va_arg(pf->ap, size_t); + break; + } + } +} + +/* + * Set the printing base based on the numeric type specified in ch. + * %o octal + * %d,%u decimal + * %x hex + * %p pointer (print as hex) + * + * If the "alternate format" was requested, or always for pointers, + * note to print the C prefix for the type. + */ +static +void +__pf_setbase(PF *pf, int ch) +{ + switch (ch) { + case 'd': + case 'u': + pf->base = 10; + break; + case 'x': + case 'p': + pf->base = 16; + break; + case 'o': + pf->base = 8; + break; + } + if (pf->altformat || ch=='p') { + pf->baseprefix = 1; + } +} + +/* + * Function to print "spc" instances of the fill character. + */ +static +void +__pf_fill(PF *pf, int spc) +{ + char f = pf->fillchar; + int i; + for (i=0; ispacing; + if (spc > len) { + spc -= len; + } + else { + spc = 0; + } + + /* If padding on left and the fill char is not 0, pad first. */ + if (spc > 0 && pf->rightspc==0 && pf->fillchar!='0') { + __pf_fill(pf, spc); + } + + /* Print the prefixes. */ + __pf_print(pf, prefix, strlen(prefix)); + __pf_print(pf, prefix2, strlen(prefix2)); + + /* If padding on left and the fill char *is* 0, pad here. */ + if (spc > 0 && pf->rightspc==0 && pf->fillchar=='0') { + __pf_fill(pf, spc); + } + + /* Print the actual string. */ + __pf_print(pf, stuff, strlen(stuff)); + + /* If padding on the right, pad afterwards. */ + if (spc > 0 && pf->rightspc!=0) { + __pf_fill(pf, spc); + } +} + +/* + * Function to convert a number to ascii and then print it. + * + * Works from right to left in a buffer of NUMBER_BUF_SIZE bytes. + * NUMBER_BUF_SIZE is set so that the longest number string we can + * generate (a long long printed in octal) will fit. See above. + */ +static +void +__pf_printnum(PF *pf) +{ + /* Digits to print with. */ + const char *const digits = "0123456789abcdef"; + + char buf[NUMBER_BUF_SIZE]; /* Accumulation buffer for string. */ + char *x; /* Current pointer into buf. */ + unsigned INTTYPE xnum; /* Current value to print. */ + const char *bprefix; /* Base prefix (0, 0x, or nothing) */ + const char *sprefix; /* Sign prefix (- or nothing) */ + + /* Start in the last slot of the buffer. */ + x = buf+sizeof(buf)-1; + + /* Insert null terminator. */ + *x-- = 0; + + /* Initialize value. */ + xnum = pf->num; + + /* + * Convert a single digit. + * Do this loop at least once - that way 0 prints as 0 and not "". + */ + do { + /* + * Get the digit character for the least significant + * part of xnum. + */ + *x = digits[xnum % pf->base]; + + /* + * Back up the pointer to point to the next space to the left. + */ + x--; + + /* + * Drop the value of the digit we just printed from xnum. + */ + xnum = xnum / pf->base; + + /* + * If xnum hits 0 there's no more number left. + */ + } while (xnum > 0); + + /* + * x points to the *next* slot in the buffer to use. + * However, we're done printing the number. So it's pointing + * one slot *before* the start of the actual number text. + * So advance it by one so it actually points at the number. + */ + x++; + + /* + * If a base prefix was requested, select it. + */ + if (pf->baseprefix && pf->base==16) { + bprefix = "0x"; + } + else if (pf->baseprefix && pf->base==8) { + bprefix = "0"; + } + else { + bprefix = ""; + } + + /* + * Choose the sign prefix. + */ + sprefix = pf->sign ? "-" : ""; + + /* + * Now actually print the string we just generated. + */ + __pf_printstuff(pf, sprefix, bprefix, x); +} + +/* + * Process a single character out of the format string. + */ +static +void +__pf_send(PF *pf, int ch) +{ + /* Cannot get NULs here. */ + assert(ch!=0); + + if (pf->in_pct==0 && ch!='%') { + /* + * Not currently in a format, and not a %. Just send + * the character on through. + */ + char c = ch; + __pf_print(pf, &c, 1); + } + else if (pf->in_pct==0) { + /* + * Not in a format, but got a %. Start a format. + */ + pf->in_pct = 1; + } + else if (strchr("#-lz0123456789", ch)) { + /* + * These are the modifier characters we recognize. + * (These are the characters between the % and the type.) + */ + __pf_modifier(pf, ch); + } + else if (strchr("doupx", ch)) { + /* + * Integer types. + * Fetch the number, set the base, print it, then + * reset for the next format. + */ + __pf_getnum(pf, ch); + __pf_setbase(pf, ch); + __pf_printnum(pf); + __pf_endfield(pf); + } + else if (ch=='s') { + /* + * Print a string. + */ + const char *str = va_arg(pf->ap, const char *); + if (str==NULL) { + str = "(null)"; + } + __pf_printstuff(pf, "", "", str); + __pf_endfield(pf); + } + else { + /* + * %%, %c, or illegal character. + * Illegal characters are printed like %%. + * for example, %5k prints " k". + */ + char x[2]; + if (ch=='c') { + x[0] = va_arg(pf->ap, int); + } + else { + x[0] = ch; + } + x[1] = 0; + __pf_printstuff(pf, "", "", x); + __pf_endfield(pf); + } +} + +/* + * Do a whole printf session. + * Create and initialize a printf state object, + * then send it each character from the format string. + */ +int +__vprintf(void (*func)(void *clientdata, const char *str, size_t len), + void *clientdata, const char *format, va_list ap) +{ + PF pf; + int i; + + pf.sendfunc = func; + pf.clientdata = clientdata; +#ifdef va_copy + va_copy(pf.ap, ap); +#else + pf.ap = ap; +#endif + pf.charcount = 0; + __pf_endfield(&pf); + + for (i=0; format[i]; i++) { + __pf_send(&pf, format[i]); + } + + return pf.charcount; +} diff --git a/common/libc/printf/snprintf.c b/common/libc/printf/snprintf.c new file mode 100644 index 0000000..a64b530 --- /dev/null +++ b/common/libc/printf/snprintf.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is shared between libc and the kernel, so don't put anything + * in here that won't work in both contexts. + */ + +#ifdef _KERNEL +#include +#include + +#else +#include + +#endif /* _KERNEL */ + +#include + +/* + * Standard C string/IO function: printf into a character buffer. + */ + + +/* + * Context structure for snprintf: buffer to print into, maximum + * length, and index of the next character to write. + * + * Note that while the length argument to snprintf includes space for + * a null terminator, SNP.buflen does not. This is to make something + * vaguely reasonable happen if a length of 0 is passed to snprintf. + */ + +typedef struct { + char *buf; + size_t buflen; + size_t bufpos; +} SNP; + +/* + * Send function for snprintf. This is the function handed to the + * printf guts. It gets called with mydata pointing to the context, + * and some string data of length LEN in DATA. DATA is not necessarily + * null-terminated. + */ + +static +void +__snprintf_send(void *mydata, const char *data, size_t len) +{ + SNP *snp = mydata; + unsigned i; + + /* For each character we're sent... */ + for (i=0; ibufpos < snp->buflen) { + + /* store the character */ + snp->buf[snp->bufpos] = data[i]; + + /* and increment the position. */ + snp->bufpos++; + } + } +} + +/* + * The va_list version of snprintf. + */ +int +vsnprintf(char *buf, size_t len, const char *fmt, va_list ap) +{ + int chars; + SNP snp; + + /* + * Fill in the context structure. + * We set snp.buflen to the number of characters that can be + * written (excluding the null terminator) so as not to have + * to special-case the possibility that we got passed a length + * of zero elsewhere. + */ + snp.buf = buf; + if (len==0) { + snp.buflen = 0; + } + else { + snp.buflen = len-1; + } + snp.bufpos = 0; + + /* Call __vprintf to do the actual work. */ + chars = __vprintf(__snprintf_send, &snp, fmt, ap); + + /* + * Add a null terminator. If the length *we were passed* is greater + * than zero, we reserved a space in the buffer for the terminator, + * so this won't overflow. If the length we were passed is zero, + * nothing will have been or should be written anyway, and buf + * might even be NULL. (C99 explicitly endorses this possibility.) + */ + if (len > 0) { + buf[snp.bufpos] = 0; + } + + /* + * Return the number of characters __vprintf processed. + * According to C99, snprintf should return this number, not + * the number of characters actually stored, and should not + * return -1 on overflow but only on other errors. (All none + * of them since we don't do multibyte characters...) + */ + return chars; +} + +/* + * snprintf - hand off to vsnprintf. + */ +int +snprintf(char *buf, size_t len, const char *fmt, ...) +{ + int chars; + va_list ap; + va_start(ap, fmt); + chars = vsnprintf(buf, len, fmt, ap); + va_end(ap); + return chars; +} + diff --git a/common/libc/stdlib/atoi.c b/common/libc/stdlib/atoi.c new file mode 100644 index 0000000..1bbeace --- /dev/null +++ b/common/libc/stdlib/atoi.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is shared between libc and the kernel, so don't put anything + * in here that won't work in both contexts. + */ + +#ifdef _KERNEL +#include +#include +#else +#include +#include +#endif + +/* + * Standard C function: parse a string that represents a decimal integer. + * Leading whitespace is allowed. Trailing gunk is allowed too. Doesn't + * really report syntax errors or overflow in any useful way. + */ + +int +atoi(const char *s) +{ + static const char digits[] = "0123456789"; /* legal digits in order */ + unsigned val=0; /* value we're accumulating */ + int neg=0; /* set to true if we see a minus sign */ + + /* skip whitespace */ + while (*s==' ' || *s=='\t') { + s++; + } + + /* check for sign */ + if (*s=='-') { + neg=1; + s++; + } + else if (*s=='+') { + s++; + } + + /* process each digit */ + while (*s) { + const char *where; + unsigned digit; + + /* look for the digit in the list of digits */ + where = strchr(digits, *s); + if (where==NULL) { + /* not found; not a digit, so stop */ + break; + } + + /* get the index into the digit list, which is the value */ + digit = (where - digits); + + /* could (should?) check for overflow here */ + + /* shift the number over and add in the new digit */ + val = val*10 + digit; + + /* look at the next character */ + s++; + } + + /* handle negative numbers */ + if (neg) { + return -val; + } + + /* done */ + return val; +} diff --git a/common/libc/string/bzero.c b/common/libc/string/bzero.c new file mode 100644 index 0000000..efd1552 --- /dev/null +++ b/common/libc/string/bzero.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is shared between libc and the kernel, so don't put anything + * in here that won't work in both contexts. + */ + +#ifdef _KERNEL +#include +#include +#else +#include +#include +#endif + +/* + * Standard (well, semi-standard) C string function - zero a block of + * memory. + */ + +void +bzero(void *vblock, size_t len) +{ + char *block = vblock; + size_t i; + + /* + * For performance, optimize the common case where the pointer + * and the length are word-aligned, and write word-at-a-time + * instead of byte-at-a-time. Otherwise, write bytes. + * + * The alignment logic here should be portable. We rely on the + * compiler to be reasonably intelligent about optimizing the + * divides and moduli out. Fortunately, it is. + */ + + if ((uintptr_t)block % sizeof(long) == 0 && + len % sizeof(long) == 0) { + long *lb = (long *)block; + for (i=0; i +#include +#else +#include +#include +#endif + +/* + * C standard function - copy a block of memory. + */ + +void * +memcpy(void *dst, const void *src, size_t len) +{ + size_t i; + + /* + * memcpy does not support overlapping buffers, so always do it + * forwards. (Don't change this without adjusting memmove.) + * + * For speedy copying, optimize the common case where both pointers + * and the length are word-aligned, and copy word-at-a-time instead + * of byte-at-a-time. Otherwise, copy by bytes. + * + * The alignment logic below should be portable. We rely on + * the compiler to be reasonably intelligent about optimizing + * the divides and modulos out. Fortunately, it is. + */ + + if ((uintptr_t)dst % sizeof(long) == 0 && + (uintptr_t)src % sizeof(long) == 0 && + len % sizeof(long) == 0) { + + long *d = dst; + const long *s = src; + + for (i=0; i +#include +#else +#include +#include +#endif + +/* + * C standard function - copy a block of memory, handling overlapping + * regions correctly. + */ + +void * +memmove(void *dst, const void *src, size_t len) +{ + size_t i; + + /* + * If the buffers don't overlap, it doesn't matter what direction + * we copy in. If they do, it does, so just assume they always do. + * We don't concern ourselves with the possibility that the region + * to copy might roll over across the top of memory, because it's + * not going to happen. + * + * If the destination is above the source, we have to copy + * back to front to avoid overwriting the data we want to + * copy. + * + * dest: dddddddd + * src: ssssssss ^ + * | ^ |___| + * |___| + * + * If the destination is below the source, we have to copy + * front to back. + * + * dest: dddddddd + * src: ^ ssssssss + * |___| ^ | + * |___| + */ + + if ((uintptr_t)dst < (uintptr_t)src) { + /* + * As author/maintainer of libc, take advantage of the + * fact that we know memcpy copies forwards. + */ + return memcpy(dst, src, len); + } + + /* + * Copy by words in the common case. Look in memcpy.c for more + * information. + */ + + if ((uintptr_t)dst % sizeof(long) == 0 && + (uintptr_t)src % sizeof(long) == 0 && + len % sizeof(long) == 0) { + + long *d = dst; + const long *s = src; + + /* + * The reason we copy index i-1 and test i>0 is that + * i is unsigned -- so testing i>=0 doesn't work. + */ + + for (i=len/sizeof(long); i>0; i--) { + d[i-1] = s[i-1]; + } + } + else { + char *d = dst; + const char *s = src; + + for (i=len; i>0; i--) { + d[i-1] = s[i-1]; + } + } + + return dst; +} diff --git a/common/libc/string/memset.c b/common/libc/string/memset.c new file mode 100644 index 0000000..8301ebd --- /dev/null +++ b/common/libc/string/memset.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef _KERNEL +#include +#include +#else +#include +#endif + +/* + * C standard function - initialize a block of memory + */ + +void * +memset(void *ptr, int ch, size_t len) +{ + char *p = ptr; + size_t i; + + for (i=0; i +#include +#else +#include +#endif + +/* + * Standard C string function: append one string to another. + */ + +char * +strcat(char *dest, const char *src) +{ + size_t offset; + + offset = strlen(dest); + strcpy(dest+offset, src); + return dest; +} diff --git a/common/libc/string/strchr.c b/common/libc/string/strchr.c new file mode 100644 index 0000000..1694bf8 --- /dev/null +++ b/common/libc/string/strchr.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is shared between libc and the kernel, so don't put anything + * in here that won't work in both contexts. + */ + +#ifdef _KERNEL +#include +#include +#else +#include +#endif + +/* + * C standard string function: find leftmost instance of a character + * in a string. + */ +char * +strchr(const char *s, int ch_arg) +{ + /* avoid sign-extension problems */ + const char ch = ch_arg; + + /* scan from left to right */ + while (*s) { + /* if we hit it, return it */ + if (*s == ch) { + return (char *)s; + } + s++; + } + + /* if we were looking for the 0, return that */ + if (*s == ch) { + return (char *)s; + } + + /* didn't find it */ + return NULL; +} diff --git a/common/libc/string/strcmp.c b/common/libc/string/strcmp.c new file mode 100644 index 0000000..09456f7 --- /dev/null +++ b/common/libc/string/strcmp.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is shared between libc and the kernel, so don't put anything + * in here that won't work in both contexts. + */ + +#ifdef _KERNEL +#include +#include +#else +#include +#endif + +/* + * Standard C string function: compare two strings and return their + * sort order. + */ + +int +strcmp(const char *a, const char *b) +{ + size_t i; + + /* + * Walk down both strings until either they're different + * or we hit the end of A. + * + * If A and B strings are not the same length, when the + * shorter one ends, the two will be different, and we'll + * stop before running off the end of either. + * + * If they *are* the same length, it's sufficient to check + * that we haven't run off the end of A, because that's the + * same as checking to make sure we haven't run off the end of + * B. + */ + + for (i=0; a[i]!=0 && a[i]==b[i]; i++) { + /* nothing */ + } + + /* + * If A is greater than B, return 1. If A is less than B, + * return -1. If they're the same, return 0. Since we have + * stopped at the first character of difference (or the end of + * both strings) checking the character under I accomplishes + * this. + * + * Note that strcmp does not handle accented characters, + * internationalization, or locale sort order; strcoll() does + * that. + * + * The rules say we compare order in terms of *unsigned* char. + */ + if ((unsigned char)a[i] > (unsigned char)b[i]) { + return 1; + } + else if (a[i] == b[i]) { + return 0; + } + return -1; +} diff --git a/common/libc/string/strcpy.c b/common/libc/string/strcpy.c new file mode 100644 index 0000000..88627ed --- /dev/null +++ b/common/libc/string/strcpy.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is shared between libc and the kernel, so don't put anything + * in here that won't work in both contexts. + */ + +#ifdef _KERNEL +#include +#include +#else +#include +#endif + +/* + * Standard C string function: copy one string to another. + */ +char * +strcpy(char *dest, const char *src) +{ + size_t i; + + /* + * Copy characters until we hit the null terminator. + */ + for (i=0; src[i]; i++) { + dest[i] = src[i]; + } + + /* + * Add null terminator to result. + */ + dest[i] = 0; + + return dest; +} diff --git a/common/libc/string/strlen.c b/common/libc/string/strlen.c new file mode 100644 index 0000000..0c5a248 --- /dev/null +++ b/common/libc/string/strlen.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is shared between libc and the kernel, so don't put anything + * in here that won't work in both contexts. + */ + +#ifdef _KERNEL +#include +#include +#else +#include +#endif + +/* + * C standard string function: get length of a string + */ + +size_t +strlen(const char *str) +{ + size_t ret = 0; + + while (str[ret]) { + ret++; + } + return ret; +} diff --git a/common/libc/string/strrchr.c b/common/libc/string/strrchr.c new file mode 100644 index 0000000..40cf255 --- /dev/null +++ b/common/libc/string/strrchr.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is shared between libc and the kernel, so don't put anything + * in here that won't work in both contexts. + */ + +#ifdef _KERNEL +#include +#include +#else +#include +#endif + +/* + * C standard string function: find rightmost instance of a character + * in a string. + */ +char * +strrchr(const char *s, int ch_arg) +{ + /* avoid sign-extension problems */ + const char ch = ch_arg; + + /* start one past the last character INCLUDING NULL TERMINATOR */ + size_t i = strlen(s)+1; + + /* go from right to left; stop at 0 */ + while (i > 0) { + + /* decrement first */ + i--; + + /* now check the character we're over */ + if (s[i] == ch) { + return (char *)(s+i); + } + } + + /* didn't find it */ + return NULL; +} diff --git a/common/libc/string/strtok_r.c b/common/libc/string/strtok_r.c new file mode 100644 index 0000000..033fc85 --- /dev/null +++ b/common/libc/string/strtok_r.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is shared between libc and the kernel, so don't put anything + * in here that won't work in both contexts. + */ + +#ifdef _KERNEL +#include +#include +#else +#include +#endif + +/* + * Standard C string function: tokenize a string splitting based on a + * list of separator characters. Reentrant version. + * + * The "context" argument should point to a "char *" that is preserved + * between calls to strtok_r that wish to operate on same string. + */ +char * +strtok_r(char *string, const char *seps, char **context) +{ + char *head; /* start of word */ + char *tail; /* end of word */ + + /* If we're starting up, initialize context */ + if (string) { + *context = string; + } + + /* Get potential start of this next word */ + head = *context; + if (head == NULL) { + return NULL; + } + + /* Skip any leading separators */ + while (*head && strchr(seps, *head)) { + head++; + } + + /* Did we hit the end? */ + if (*head == 0) { + /* Nothing left */ + *context = NULL; + return NULL; + } + + /* skip over word */ + tail = head; + while (*tail && !strchr(seps, *tail)) { + tail++; + } + + /* Save head for next time in context */ + if (*tail == 0) { + *context = NULL; + } + else { + *tail = 0; + tail++; + *context = tail; + } + + /* Return current word */ + return head; +} diff --git a/configure b/configure new file mode 100755 index 0000000..7ce7dc7 --- /dev/null +++ b/configure @@ -0,0 +1,199 @@ +#!/bin/sh +# +# Configure script for OS/161 tree. +# This generates the file "defs.mk" at the top level of the tree. +# +# Usage: ./configure [options] +# where you can get a list of the options by doing ./configure --help. +# +# Must be run with the top of the OS/161 tree as its current directory. +# +# Note: while this superficially acts like a GNU Autoconf configure +# script, it was not generated by autoconf. Scripts generated by +# autoconf are much harder to read. :-) +# +# If this script bombs out, you can create defs.mk by hand based on +# the comments in mk/os161.config.mk. +# + +# Target hardware platform and machine type. +PLATFORM='sys161' +MACHINE='mips' + +# Default optimize/debug flag: optimize. +DEBUG='-O2' + +# Default location of the root of the installed system. +# Note that we quote it such that the reference to the home directory +# is a make variable, not a shell variable. This means it gets expanded +# when make runs rather than when this script runs. +OSTREE='$(HOME)/os161/root' + +# By default don't explicitly configure a Python interpreter. +PYTHON_INTERPRETER= + +# Assume this +HOST_CC=gcc + +################################################## + +# +# Check to make sure we're in the right place. + +if [ ! -d kern/main ]; then + echo 'Please run configure from the top of the OS/161 tree.' + exit 1 +fi + +# +# Process the command-line options. + +while [ "x$1" != x ]; do + case "$1" in + --debug) DEBUG='-g';; + --ostree=*) OSTREE=`echo $1 | sed 's,^[^=]*=,,'`;; + --help|*) + more <. + +printf "Checking for ... " + +cat > __conftest.c < +int +main() +{ + err(0, "works"); + return 1; +} +EOF + +OK=0 +if $HOST_CC __conftest.c -o __conftest >/dev/null 2>&1; then + if ./__conftest >/dev/null 2>&1; then + OK=1 + fi +fi + +rm -f __conf* + +if [ $OK = 1 ]; then + echo 'yes' +else + echo 'no' + COMPAT_CFLAGS="${COMPATCFLAGS} -DNEED_ERR" + COMPAT_TARGETS="${HOSTTARGETS} install-errh" +fi + + +# Check if the host system has ntohll() and htonll(). + +printf "Checking for ntohll()..." + +cat > __conftest.c < +int +main() +{ + int ok = ntohll(0xbeefbeefbeefbeefULL) != 0; + return !ok; /* exit(0) for success */ +} +EOF + +OK=0 +if $HOST_CC __conftest.c -o __conftest >/dev/null 2>&1; then + if ./__conftest >/dev/null 2>&1; then + OK=1 + fi +fi + +rm -f __conf* + +if [ $OK = 1 ]; then + echo 'yes' +else + echo 'no' + COMPAT_CFLAGS="${COMPATCFLAGS} -DNEED_NTOHLL" + HOST_CFLAGS="${HOST_CFLAGS} -DDECLARE_NTOHLL" +fi + + +# Look for a Python interpreter. +PYTHON= +for PYNAME in \ + python python2.7 \ + /usr/local/bin/python /usr/local/bin/python2.7 \ + /usr/pkg/bin/python /usr/pkg/bin/python2.7 \ + /opt/bin/python /opt/bin/python2.7 \ + ; do + PYVERSION=`($PYNAME -V) 2>&1 || echo none` + case "$PYVERSION" in + Python\ 2.*|Python\ 3.*) PYTHON=$PYNAME;; + none) ;; + *) ;; # ? + esac +done +case "$PYTHON" in + python) ;; + /*) PYTHON_INTERPRETER="$PYTHON";; + *) PYTHON_INTERPRETER="/usr/bin/env $PYTHON";; +esac + +#################### + +# Now generate defs.mk. + +echo 'Generating defs.mk.' + +( + # First, put an explanatory comment at the top. + cat < defs.mk diff --git a/defs.mk b/defs.mk new file mode 100644 index 0000000..0f4e63e --- /dev/null +++ b/defs.mk @@ -0,0 +1,22 @@ +# This file was generated by configure. Edits will disappear if you rerun +# configure. If you find that you need to edit this file to make things +# work, let the course staff know and we'll try to fix the configure script. +# +# The purpose of this file is to hold all the makefile definitions +# needed to adjust the OS/161 build process to any particular +# environment. If I've done it right, all you need to do is rerun the +# configure script and make clean if you start working on a different +# host OS. If I've done it mostly right, you may need to edit this +# file but you still hopefully won't need to edit any of the +# makefiles. +# +# The things that can be set here are documented in mk/os161.config.mk. +# + +OSTREE=/root/os161/root +PLATFORM=sys161 +MACHINE=mips +COMPAT_CFLAGS= -DNEED_NTOHLL +COMPAT_TARGETS= +HOST_CFLAGS+= -DDECLARE_NTOHLL +PYTHON_INTERPRETER=/usr/bin/env diff --git a/design/assignments.txt b/design/assignments.txt new file mode 100644 index 0000000..4500af6 --- /dev/null +++ b/design/assignments.txt @@ -0,0 +1,120 @@ +The (potential) OS/161 assignments +---------------------------------- + +OS/161 is used by a wide variety of courses at a wide variety of +schools, no two of which have the exact same set of assignments and +assignment requirements. The code base has been (to the extent +reasonably possible) structured to allow this and not assume any +particular structure or (particularly) numbering of assignments. + +That said, in various places comments and documentation must (to be +helpful, at least) refer to particular assignments and things that are +(typically) done in particular assignments. These are written in +fairly general terms. This file is provided as an index for those +terms. + +*** Always refer to the course materials provided by your *** +*** instructors when trying to figure out what functionality *** +*** you are and are not required to implement. *** + +Note that the OS/161 code base you are given may include solutions for +some parts of the assignments described below, or even some whole +assignments. + +Also note that the text below refers to assorted technical terms and +OS concepts without much or any explanation; you may not be familiar +with most of them at first and that's perfectly ok. + + +OS/161 is intended to support six basic assignments, most of which can +be divided into smaller pieces. These six assignments are: + + - synchronization; + - basic system calls; + - virtual memory; + - basic file system functionality; + - file system recovery via journaling; + - some additional piece of OS functionality. + + +Synchronization. + +This assignment has (potentially) three parts: + - Implement (sleep) locks and condition variables. + - Implement reader-writer locks. + - Solve some synchronization problems of the dining-philosophers + variety. + + +Basic system calls. (And processes.) + +This assignment has (potentially) up to six parts: + - Implement file tables and open-file objects. + - Implement the basic system calls for files, normally: + - open() + - dup2() + - read() + - write() + - lseek() + - close() + - chdir() + - __getcwd() + - Implement processes, process IDs, and the basic process system + calls, normally: + - getpid() + - fork() + - _exit() + - waitpid() + - Implement the execv() system call. + - Implement a scheduler. + + +Virtual memory. + +This assignment entails replacing a provided very simple virtual +memory system with a real one. This possibly includes providing the +sbrk() system call. It does not split into parts readily. + + +Basic file system functionality. + +This assignment has (potentially) up to five parts: + - Add more system calls for file system operations, typically taken + from these: + - sync() + - mkdir() + - rmdir() + - remove() + - link() + - rename() + - getdirentry() + - fstat() + - fsync() + - ftruncate() + - flock() + although others may be chosen. + - Implement a buffer cache. + - Replace a biglock with fine-grained locking in the VFS layer + and/or the SFS file system. + - Add support for subdirectories to SFS. + - Implement cross-directory rename in SFS. + - Implement larger files in SFS. + + +File system recovery via journaling. + +This assignment has (potentially) five parts: + - Implement an on-disk container for a file system journal. + - Instrument the buffer cache to support write-ahead journaling. + - Design a system of journal records suitable for recovering the + file system after a crash. + - Add code to SFS to issue these journal records. + - Implement code to read the on-disk journal and recover from a + crash. + + +Additional projects. + +There is a wide variety of things that can be done to build on the +above assignments. None are listed here, because this file is not +the place for it. diff --git a/design/shell.txt b/design/shell.txt new file mode 100644 index 0000000..d902c32 --- /dev/null +++ b/design/shell.txt @@ -0,0 +1,55 @@ + SHELL DESIGN NOTES + ------------------ + + The shell has few bells and whistles. It allows up to 128 +backgrounded jobs (after this point you have to wait for some to exit, +because the table it uses to track these cannot be resized.) + + The background jobs are tracked in an array of MAXBG pid_t's. If an +open slot is found, a background job's pid can be stashed there. +Background jobs can be collected using the "wait" built-in command, +which removes any pids whose exit status it collects from the +background jobs table. + + The wait built-in command takes an optional argument, the process +id to wait for. The shell will attempt to wait for any process, not +just the ones it actually started as its own background jobs. However, +since no facility exists for looking up the pids of running processes, +this ability is not necessarily useful. If no argument is provided, +wait waits for all outstanding background jobs. + + The shell uses WNOHANG if WNOHANG is defined, in which case +background jobs are polled after every command, like in Unix shells. +If WNOHANG is not defined, background jobs are polled only by user +request. In OS/161 2.0, WNOHANG is always defined in the kernel header +files, but the implementation is only suggested, not required. To make +the shell stop trying to use WNOHANG, patch it, or remove WNOHANG from +kern/wait.h. + + There are two other built-in commands: chdir, which uses the chdir +system call to change directory, and can also be accessed as just cd, +and exit, which causes the shell to exit with a specified exit status +(0 if not supplied). + + Note that all these built-in commands must be built into the shell +in order to work usefully. + + The shell processes commands by reading lines and then splitting +them up into words using whitespace characters (space, tab, carriage +return, and newline) as separators. No punctuation characters are +interpreted, except for `&'. No variable substitution or argument +wildcard expansion ("globbing") is performed. + + The `&' character, if present as the last word on a command line, +is treated as the "background" operator: the command is run as a +background job, that is, after starting it the shell immediately +prints another prompt and accepts more commands. Note that the `&' +must be preceded by whitespace to be recognized. The process id of the +background job is printed as it starts. Note that shell builtins +cannot be backgrounded; furthermore, because the OS/161 console does +not support job control, starting background jobs that perform +terminal input (or, to a lesser extent, terminal output) may produce +confusing and/or unwanted results. + + The shell also supports the "sh -c COMMAND" syntax in the hopes +that it will be useful. diff --git a/design/usermalloc.txt b/design/usermalloc.txt new file mode 100644 index 0000000..7a8fe0d --- /dev/null +++ b/design/usermalloc.txt @@ -0,0 +1,24 @@ +User-level malloc +----------------- + + The user-level malloc implementation is defined to be simple, not +fast or efficient. It uses a very basic first-fit block algorithm. + + There's an 8-byte header which holds the offsets to the previous +and next blocks, a used/free bit, and some magic numbers (for +consistency checking) in the remaining available header bits. It also +allocates in units of 8 bytes to guarantee proper alignment of +doubles. (It also assumes its own headers are aligned on 8-byte +boundaries.) + + On malloc(), it searches the entire heap starting at the beginning +for the first block big enough to hold the allocation. If it doesn't +find one, it calls sbrk() to get more memory. If it does find one, it +marks the block in use. It splits the remaining portion of the block +off as a new free block only if said portion is large enough to hold +both a header and some data. + + On free(), it marks the block free and then tries to merge it with +the adjacent blocks (both above and below) if they're free. + + That's about all there is to it. diff --git a/kern/Makefile b/kern/Makefile new file mode 100644 index 0000000..f3a01bd --- /dev/null +++ b/kern/Makefile @@ -0,0 +1,17 @@ +# +# Toplevel makefile for the OS/161 kernel tree. +# +# Note: actual kernels are not compiled here; they are compiled in +# compile/FOO where FOO is a kernel configuration name. +# +# We don't actually do anything from here except install includes. +# + +TOP=.. +.include "$(TOP)/mk/os161.config.mk" + +INCLUDES=\ + include/kern include/kern \ + arch/$(MACHINE)/include/kern include/kern/$(MACHINE) + +.include "$(TOP)/mk/os161.includes.mk" diff --git a/kern/arch/mips/conf/conf.arch b/kern/arch/mips/conf/conf.arch new file mode 100644 index 0000000..21c23af --- /dev/null +++ b/kern/arch/mips/conf/conf.arch @@ -0,0 +1,79 @@ + +# +# The machine dependent sources for MIPS. +# + +# Standard C functions +machine mips file ../common/libc/arch/mips/setjmp.S + +# 64-bit integer ops support for gcc +machine mips file ../common/gcc-millicode/adddi3.c +machine mips file ../common/gcc-millicode/anddi3.c +machine mips file ../common/gcc-millicode/ashldi3.c +machine mips file ../common/gcc-millicode/ashrdi3.c +machine mips file ../common/gcc-millicode/cmpdi2.c +machine mips file ../common/gcc-millicode/divdi3.c +machine mips file ../common/gcc-millicode/iordi3.c +machine mips file ../common/gcc-millicode/lshldi3.c +machine mips file ../common/gcc-millicode/lshrdi3.c +machine mips file ../common/gcc-millicode/moddi3.c +machine mips file ../common/gcc-millicode/muldi3.c +machine mips file ../common/gcc-millicode/negdi2.c +machine mips file ../common/gcc-millicode/notdi2.c +machine mips file ../common/gcc-millicode/qdivrem.c +machine mips file ../common/gcc-millicode/subdi3.c +machine mips file ../common/gcc-millicode/ucmpdi2.c +machine mips file ../common/gcc-millicode/udivdi3.c +machine mips file ../common/gcc-millicode/umoddi3.c +machine mips file ../common/gcc-millicode/xordi3.c + +# +# Low-level stuff ("locore") +# The platform should select cache handling and exception handling from +# among these: +# +# cache-mips1.S +# cache-mips161.S +# cache-mips32.S +# +# exception-mips1.S +# exception-mips32.S +# + +machine mips file arch/mips/locore/trap.c # Common trap handler. + +# +# Thread subsystem +# + +machine mips file arch/mips/thread/cpu.c # CPU control. +machine mips file arch/mips/thread/switch.S # Thread context switch +machine mips file arch/mips/thread/switchframe.c # New thread prep +machine mips file arch/mips/thread/thread_machdep.c # MD thread code +machine mips file arch/mips/thread/threadstart.S # New thread startup + +# +# VM system +# The platform should select TLB handling from among these: +# +# tlb-mips1.S +# tlb-mips161.S +# tlb-mips32.S +# + +machine mips file arch/mips/vm/ram.c # Physical memory accounting + +# This is included here rather than in conf.kern because +# it may not be suitable for all architectures. +machine mips file vm/copyinout.c # copyin/out et al. + +# For the early assignments, we supply a very stupid MIPS-only skeleton +# of a VM system. It is just barely capable of running a single userlevel +# program as long as that program's not very large. +defoption dumbvm +machine mips optfile dumbvm arch/mips/vm/dumbvm.c + +# +# System call layer +# +machine mips file arch/mips/syscall/syscall.c # System call handler diff --git a/kern/arch/mips/conf/ldscript b/kern/arch/mips/conf/ldscript new file mode 100644 index 0000000..cbe86ac --- /dev/null +++ b/kern/arch/mips/conf/ldscript @@ -0,0 +1,98 @@ +/* + * This is a pile of crap that tells the linker how to link the kernel, + * because it's too stupid to be able to work it out on its own. + */ +ENTRY(__start) + +_DYNAMIC_LINK = 0; +SECTIONS +{ + /* + * Base address for the kernel. + */ + . = 0x80000200; + + /* + * Read-only loaded sections. + */ + + /* code */ + .text : { *(.text) } + + /* linker-provided symbol for end of code */ + _etext = .; + + /* read-only data */ + .rodata : { *(.rodata) *(.rodata.*) } + + /* MIPS register-usage blather */ + .reginfo : { *(.reginfo) } + + /* + * Move to a fresh page. This method puts read-only and + * read-write material on separate pages without having to + * waste space on page-alignment in the on-disk file; the + * on-disk page that contains both text and data is mapped + * twice. + * + * For mips kernels we can't write-protect the text anyhow so + * there's no point doing it. + */ + /* . = . + 0x1000; */ + + /* + * Read-write loaded sections. + */ + + /* initialized data */ + .data : { + *(.data) + CONSTRUCTORS + } + + /* Value for GP register */ + _gp = ALIGN(16) + 0x7ff0; + + /* Small data accessed via GP register */ + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + .sdata : { *(.sdata) } + + /* cleared-to-zero data */ + .sbss : { *(.sbss *.scommon) } + .bss : { *(.bss) *(COMMON) } + + /* linker-provided symbol for end of program */ + _end = .; + + /* + * Debug info + */ + + /* stabs debug sections */ + .stab 0: { *(.stab) } + .stabstr 0: { *(.stabstr) } + + /* DWARF debug sections */ + .debug 0: { *(.debug) } + .line 0: { *(.line) } + .debug_srcinfo 0: { *(.debug_srcinfo) } + .debug_sfnames 0: { *(.debug_sfnames) } + .debug_aranges 0: { *(.debug_aranges) } + .debug_pubnames 0: { *(.debug_pubnames) } + .debug_info 0: { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0: { *(.debug_abbrev) } + .debug_line 0: { *(.debug_line) } + .debug_frame 0: { *(.debug_frame) } + .debug_str 0: { *(.debug_str) } + .debug_loc 0: { *(.debug_loc) } + .debug_macinfo 0: { *(.debug_macinfo) } + .debug_weaknames 0: { *(.debug_weaknames) } + .debug_funcnames 0: { *(.debug_funcnames) } + .debug_typenames 0: { *(.debug_typenames) } + .debug_varnames 0: { *(.debug_varnames) } + + /* These must appear regardless of . */ + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } +} diff --git a/kern/arch/mips/include/current.h b/kern/arch/mips/include/current.h new file mode 100644 index 0000000..12f257c --- /dev/null +++ b/kern/arch/mips/include/current.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MIPS_CURRENT_H_ +#define _MIPS_CURRENT_H_ + + +/* + * Macro for current thread, or current cpu. + * + * This file should only be included via (q.v.) + * + * On mips we track the current thread. There's an architectural + * issue that informs this choice: there's no easy way to find the + * current cpu, the current thread, or even the kernel stack of the + * current thread when entering the kernel at trap time. (On most CPUs + * there's a canonical way to find at least the stack.) + * + * Therefore we do the following: + * + * - We misuse a kernel-settable field of a nonessential MMU register + * to hold the CPU number. + * + * - On trap entry we use this number to index an array that gets us + * both the kernel stack and curthread. + * + * - We tell the compiler not to use the s7 register and keep + * curthread there. + * + * Note that if you want to change this scheme to use a different + * register, or change to a different scheme, you need to touch three + * places: here, the mips-specific kernel CFLAGS in the makefiles, and + * the trap entry and return code. + */ + +#ifdef __GNUC__ +register struct thread *curthread __asm("$23"); /* s7 register */ +#else +#error "Don't know how to declare curthread in this compiler" +#endif +#undef __NEED_CURTHREAD +#define __NEED_CURCPU + +/* For how we've defined it, curthread gets set first, then curcpu. */ +#define INIT_CURCPU(cpu, thread) (curthread = (thread), curcpu = (cpu)) + +#endif /* _MIPS_CURRENT_H_ */ diff --git a/kern/arch/mips/include/elf.h b/kern/arch/mips/include/elf.h new file mode 100644 index 0000000..c97aff7 --- /dev/null +++ b/kern/arch/mips/include/elf.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MIPS_ELF_H_ +#define _MIPS_ELF_H_ + +/* + * MIPS machine-dependent definitions for the ELF binary format. + */ + + +/* The ELF executable type. */ +#define EM_MACHINE EM_MIPS + +/* Linker relocation codes. SIZE DESCRIPTION */ +#define R_MIPS_NONE 0 /* --- nop */ +#define R_MIPS_16 1 /* u16 value */ +#define R_MIPS_32 2 /* u32 value */ +#define R_MIPS_REL32 3 /* u32 value relative to patched address */ +#define R_MIPS_26 4 /* u26 j/jal instruction address field */ +#define R_MIPS_HI16 5 /* u16 %hi(sym) as below */ +#define R_MIPS_LO16 6 /* s16 %lo(sym) as below */ +#define R_MIPS_GPREL16 7 /* s16 offset from GP register */ +#define R_MIPS_LITERAL 8 /* s16 GPREL16 for file-local symbols (?) */ +#define R_MIPS_GOT16 9 /* u16 offset into global offset table */ +#define R_MIPS_PC16 10 /* s16 PC-relative reference */ +#define R_MIPS_CALL16 11 /* u16 call through global offset table */ +#define R_MIPS_GPREL32 12 /* s32 offset from GP register */ +/* %hi/%lo are defined so %hi(sym) << 16 + %lo(sym) = sym */ + + +#endif /* _MIPS_ELF_H_ */ diff --git a/kern/arch/mips/include/kern/endian.h b/kern/arch/mips/include/kern/endian.h new file mode 100644 index 0000000..b9a1784 --- /dev/null +++ b/kern/arch/mips/include/kern/endian.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_MIPS_ENDIAN_H_ +#define _KERN_MIPS_ENDIAN_H_ + +/* + * Endianness. While the MIPS can be either big-endian (mipseb) or + * little-endian (mipsel), at least for now we only do mipseb. + * + * This file should only be included via which in turn + * should be gotten via in the kernel or in + * userland. + */ + +#define _BYTE_ORDER _BIG_ENDIAN + +#endif /* _KERN_MIPS_ENDIAN_H_ */ diff --git a/kern/arch/mips/include/kern/regdefs.h b/kern/arch/mips/include/kern/regdefs.h new file mode 100644 index 0000000..5fd6a6e --- /dev/null +++ b/kern/arch/mips/include/kern/regdefs.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Macros for general-purpose register numbers for MIPS. + * + * Exported to userlevel because it's ~standard for that architecture. + */ + +#ifndef _KERN_MIPS_REGDEFS_H_ +#define _KERN_MIPS_REGDEFS_H_ + + +#define z0 $0 /* always zero register */ +#define AT $1 /* assembler temp register */ +#define v0 $2 /* value 0 */ +#define v1 $3 /* value 1 */ +#define a0 $4 /* argument 0 */ +#define a1 $5 /* argument 1 */ +#define a2 $6 /* argument 2 */ +#define a3 $7 /* argument 3 */ +#define t0 $8 /* temporary (caller-save) 0 */ +#define t1 $9 /* temporary (caller-save) 1 */ +#define t2 $10 /* temporary (caller-save) 2 */ +#define t3 $11 /* temporary (caller-save) 3 */ +#define t4 $12 /* temporary (caller-save) 4 */ +#define t5 $13 /* temporary (caller-save) 5 */ +#define t6 $14 /* temporary (caller-save) 6 */ +#define t7 $15 /* temporary (caller-save) 7 */ +#define s0 $16 /* saved (callee-save) 0 */ +#define s1 $17 /* saved (callee-save) 1 */ +#define s2 $18 /* saved (callee-save) 2 */ +#define s3 $19 /* saved (callee-save) 3 */ +#define s4 $20 /* saved (callee-save) 4 */ +#define s5 $21 /* saved (callee-save) 5 */ +#define s6 $22 /* saved (callee-save) 6 */ +#define s7 $23 /* saved (callee-save) 7 */ +#define t8 $24 /* temporary (caller-save) 8 */ +#define t9 $25 /* temporary (caller-save) 9 */ +#define k0 $26 /* kernel temporary 0 */ +#define k1 $27 /* kernel temporary 1 */ +#define gp $28 /* global pointer */ +#define sp $29 /* stack pointer */ +#define s8 $30 /* saved (callee-save) 8 = frame pointer */ +#define ra $31 /* return address */ + + +#endif /* _KERN_MIPS_REGDEFS_H_ */ diff --git a/kern/arch/mips/include/kern/setjmp.h b/kern/arch/mips/include/kern/setjmp.h new file mode 100644 index 0000000..13596a1 --- /dev/null +++ b/kern/arch/mips/include/kern/setjmp.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MIPS_SETJMP_H_ +#define _MIPS_SETJMP_H_ + +/* + * MIPS jmp_buf definition. + */ + +/* + * Must save: s0-s8, sp, ra (11 registers) + * Don't change __JB_REGS without adjusting mips_setjmp.S accordingly. + */ +#define __JB_REGS 11 + +/* A jmp_buf is an array of __JB_REGS registers */ +typedef uint32_t jmp_buf[__JB_REGS]; + + +#endif /* _MIPS_SETJMP_H_ */ diff --git a/kern/arch/mips/include/kern/signal.h b/kern/arch/mips/include/kern/signal.h new file mode 100644 index 0000000..fbc713d --- /dev/null +++ b/kern/arch/mips/include/kern/signal.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef _KERN_MIPS_SIGNAL_H_ +#define _KERN_MIPS_SIGNAL_H_ + +/* + * Structure used to hold the register values for returning from a + * userland signal handler - basically the saved register values from + * whatever userlevel execution context the signal interrupted. Fill + * this in as needed, if you ever implement signal handlers. (Which you + * probably won't.) + */ +struct sigcontext { + /* Dummy. */ +}; + +#endif /* _KERN_MIPS_SIGNAL_H_ */ diff --git a/kern/arch/mips/include/kern/types.h b/kern/arch/mips/include/kern/types.h new file mode 100644 index 0000000..fd93ba4 --- /dev/null +++ b/kern/arch/mips/include/kern/types.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_MIPS_TYPES_H_ +#define _KERN_MIPS_TYPES_H_ + +/* + * Machine-dependent types visible to userland. + * (Kernel-only types should go in mips/types.h.) + * 32-bit MIPS version. + * + * See kern/types.h for an explanation of the underscores. + */ + + +/* Sized integer types, with convenient short names */ +typedef char __i8; /* 8-bit signed integer */ +typedef short __i16; /* 16-bit signed integer */ +typedef int __i32; /* 32-bit signed integer */ +typedef long long __i64; /* 64-bit signed integer */ + +typedef unsigned char __u8; /* 8-bit unsigned integer */ +typedef unsigned short __u16; /* 16-bit unsigned integer */ +typedef unsigned int __u32; /* 32-bit unsigned integer */ +typedef unsigned long long __u64; /* 64-bit unsigned integer */ + +/* Further standard C types */ +typedef long __intptr_t; /* Signed pointer-sized integer */ +typedef unsigned long __uintptr_t; /* Unsigned pointer-sized integer */ + +/* + * Since we're a 32-bit platform, size_t, ssize_t, and ptrdiff_t can + * correctly be either (unsigned) int or (unsigned) long. However, if we + * don't define it to the same one gcc is using, gcc will get + * upset. If you switch compilers and see otherwise unexplicable type + * errors involving size_t, try changing this. + */ +#if 1 +typedef unsigned __size_t; /* Size of a memory region */ +typedef int __ssize_t; /* Signed type of same size */ +typedef int __ptrdiff_t; /* Difference of two pointers */ +#else +typedef unsigned long __size_t; /* Size of a memory region */ +typedef long __ssize_t; /* Signed type of same size */ +typedef long __ptrdiff_t; /* Difference of two pointers */ +#endif + +/* Number of bits per byte. */ +#define __CHAR_BIT 8 + + +#endif /* _KERN_MIPS_TYPES_H_ */ diff --git a/kern/arch/mips/include/membar.h b/kern/arch/mips/include/membar.h new file mode 100644 index 0000000..95b05fe --- /dev/null +++ b/kern/arch/mips/include/membar.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MIPS_MEMBAR_H_ +#define _MIPS_MEMBAR_H_ + +/* + * On the mips there's only one memory barrier instruction, so these + * are all the same. This is not true on many other CPUs (x86, arm, + * sparc, powerpc, etc.) We also mark the instruction as a compiler- + * level barrier by telling gcc that it destroys memory; this prevents + * gcc from reordering loads and stores around it. + * + * See include/membar.h for further information. + */ + +MEMBAR_INLINE +void +membar_any_any(void) +{ + __asm volatile( + ".set push;" /* save assembler mode */ + ".set mips32;" /* allow MIPS32 instructions */ + "sync;" /* do it */ + ".set pop" /* restore assembler mode */ + : /* no outputs */ + : /* no inputs */ + : "memory"); /* "changes" memory */ +} + +MEMBAR_INLINE void membar_load_load(void) { membar_any_any(); } +MEMBAR_INLINE void membar_store_store(void) { membar_any_any(); } +MEMBAR_INLINE void membar_store_any(void) { membar_any_any(); } +MEMBAR_INLINE void membar_any_store(void) { membar_any_any(); } + + +#endif /* _MIPS_MEMBAR_H_ */ diff --git a/kern/arch/mips/include/specialreg.h b/kern/arch/mips/include/specialreg.h new file mode 100644 index 0000000..84b6e88 --- /dev/null +++ b/kern/arch/mips/include/specialreg.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MIPS_SPECIALREG_H_ +#define _MIPS_SPECIALREG_H_ + + +/* + * Coprocessor 0 (system processor) register numbers + */ +#define c0_index $0 /* TLB entry index register */ +#define c0_random $1 /* TLB random slot register */ +#define c0_entrylo $2 /* TLB entry contents (low-order half) */ +/* c0_entrylo0 $2 */ /* MIPS-II and up only */ +/* c0_entrylo1 $3 */ /* MIPS-II and up only */ +#define c0_context $4 /* some precomputed pagetable stuff */ +/* c0_pagemask $5 */ /* MIPS-II and up only */ +/* c0_wired $6 */ /* MIPS-II and up only */ +#define c0_vaddr $8 /* virtual addr of failing memory access */ +#define c0_count $9 /* cycle counter (MIPS-II and up) */ +#define c0_entryhi $10 /* TLB entry contents (high-order half) */ +#define c0_compare $11 /* on-chip timer control (MIPS-II and up) */ +#define c0_status $12 /* processor status register */ +#define c0_cause $13 /* exception cause register */ +#define c0_epc $14 /* exception PC register */ +#define c0_prid $15 /* processor ID register */ +/* c0_config $16 */ /* MIPS-II and up only */ +/* c0_lladdr $17 */ /* MIPS-II and up only */ +/* c0_watchlo $18 */ /* MIPS-II and up only */ +/* c0_watchhi $19 */ /* MIPS-II and up only */ + +/* + * Mode bits in c0_status + */ +#define CST_IEc 0x00000001 /* current: interrupt enable */ +#define CST_KUc 0x00000002 /* current: user mode */ +#define CST_IEp 0x00000004 /* previous: interrupt enable */ +#define CST_KUp 0x00000008 /* previous: user mode */ +#define CST_IEo 0x00000010 /* old: interrupt enable */ +#define CST_KUo 0x00000020 /* old: user mode */ +#define CST_MODEMASK 0x0000003f /* mask for the above */ +#define CST_IRQMASK 0x0000ff00 /* mask for the individual irq enable bits */ +#define CST_BEV 0x00400000 /* bootstrap exception vectors flag */ + +/* + * Fields of the c0_cause register + */ +#define CCA_UTLB 0x00000001 /* true if UTLB exception (set by our asm) */ +#define CCA_CODE 0x0000003c /* EX_foo in trapframe.h */ +#define CCA_IRQS 0x0000ff00 /* Currently pending interrupts */ +#define CCA_COPN 0x30000000 /* Coprocessor number for EX_CPU */ +#define CCA_JD 0x80000000 /* True if exception happened in jump delay */ + +#define CCA_CODESHIFT 2 /* shift for CCA_CODE field */ + +/* + * Fields of the c0_index register + */ +#define CIN_P 0x80000000 /* nonzero -> TLB probe found nothing */ +#define CIN_INDEX 0x00003f00 /* 6-bit index into TLB */ + +#define CIN_INDEXSHIFT 8 /* shift for CIN_INDEX field */ + +/* + * Fields of the c0_context register + * + * The intent of c0_context is that you can manage virtually-mapped + * page tables in kseg2; then you load the base address of the current + * page table into c0_context. On a TLB miss the failing address is + * masked and shifted and appears in the VSHIFT field, and c0_context + * thereby contains the address of the page table entry you need to + * load into the TLB. This can be used to make TLB refill very fast. + * + * However, in OS/161 we use CTX_PTBASE to hold the current CPU + * number. This (or something like it) is fairly important to have and + * there's no other good place in the chip to put it. See discussions + * elsewhere. + */ +#define CTX_VSHIFT 0x001ffffc /* shifted/masked copy of c0_vaddr */ +#define CTX_PTBASE 0xffe00000 /* page table base address */ + +#define CTX_PTBASESHIFT 21 /* shift for CTX_PBASE field */ + +/* + * Hardwired exception handler addresses. + */ +#define EXADDR_UTLB 0x80000000 +#define EXADDR_GENERAL 0x80000080 + + +#endif /* _MIPS_SPECIALREG_H_ */ diff --git a/kern/arch/mips/include/spinlock.h b/kern/arch/mips/include/spinlock.h new file mode 100644 index 0000000..7c3ea1a --- /dev/null +++ b/kern/arch/mips/include/spinlock.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MIPS_SPINLOCK_H_ +#define _MIPS_SPINLOCK_H_ + +#include + + +/* Type of value needed to actually spin on */ +typedef unsigned spinlock_data_t; + +/* Initializer for use by SPINLOCK_INITIALIZER */ +#define SPINLOCK_DATA_INITIALIZER 0 + +/* Atomic operations on spinlock_data_t */ +SPINLOCK_INLINE +void spinlock_data_set(volatile spinlock_data_t *sd, unsigned val); +SPINLOCK_INLINE +spinlock_data_t spinlock_data_get(volatile spinlock_data_t *sd); +SPINLOCK_INLINE +spinlock_data_t spinlock_data_testandset(volatile spinlock_data_t *sd); + +//////////////////////////////////////////////////////////// + +/* + * Assign a spinlock_data_t. On mips assigment of a plain 32-bit value + * is one instruction, and instructions are atomic with respect to + * memory. + */ +SPINLOCK_INLINE +void +spinlock_data_set(volatile spinlock_data_t *sd, unsigned val) +{ + *sd = val; +} + +/* + * Read a spinlock_data_t. On mips reading a plain 32-bit value is one + * instruction, and instructions are atomic with respect to memory. + */ +SPINLOCK_INLINE +spinlock_data_t +spinlock_data_get(volatile spinlock_data_t *sd) +{ + return *sd; +} + +/* + * Test-and-set a spinlock_data_t. Use the LL/SC instructions to + * make it atomic. + * + * LL (load linked) loads a machine word from memory, and marks the + * address. SC (store conditional) stores a machine word to memory, + * but succeeds only if the address is marked from a previous LL on + * the same processor. Stores from other processors clear that mark, + * as do traps on the current processor. Note that there may be no + * other memory accesses (besides instruction fetches) between the LL + * and the SC or the behavior is *undefined*. You can only use LL/SC + * to atomically update one machine word. + */ +SPINLOCK_INLINE +spinlock_data_t +spinlock_data_testandset(volatile spinlock_data_t *sd) +{ + spinlock_data_t x; + spinlock_data_t y; + + /* + * Test-and-set using LL/SC. + * + * Load the existing value into X, and use Y to store 1. + * After the SC, Y contains 1 if the store succeeded, + * 0 if it failed. + * + * On failure, return 1 to pretend that the spinlock + * was already held. + */ + + y = 1; + __asm volatile( + ".set push;" /* save assembler mode */ + ".set mips32;" /* allow MIPS32 instructions */ + ".set volatile;" /* avoid unwanted optimization */ + "ll %0, 0(%2);" /* x = *sd */ + "sc %1, 0(%2);" /* *sd = y; y = success? */ + ".set pop" /* restore assembler mode */ + : "=&r" (x), "+r" (y) : "r" (sd)); + if (y == 0) { + return 1; + } + return x; +} + + +#endif /* _MIPS_SPINLOCK_H_ */ diff --git a/kern/arch/mips/include/thread.h b/kern/arch/mips/include/thread.h new file mode 100644 index 0000000..822781e --- /dev/null +++ b/kern/arch/mips/include/thread.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MIPS_THREAD_H_ +#define _MIPS_THREAD_H_ + + +/* + * Machine-dependent thread bits. + */ + +#include + +typedef void (*badfaultfunc_t)(void); + +struct thread_machdep { + badfaultfunc_t tm_badfaultfunc; /* fault hook used by copyin/out */ + jmp_buf tm_copyjmp; /* longjmp area used by copyin/out */ +}; + + +#endif /* _MIPS_THREAD_H_ */ diff --git a/kern/arch/mips/include/tlb.h b/kern/arch/mips/include/tlb.h new file mode 100644 index 0000000..31d1890 --- /dev/null +++ b/kern/arch/mips/include/tlb.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MIPS_TLB_H_ +#define _MIPS_TLB_H_ + +/* + * MIPS-specific TLB access functions. + * + * tlb_random: write the TLB entry specified by ENTRYHI and ENTRYLO + * into a "random" TLB slot chosen by the processor. + * + * IMPORTANT NOTE: never write more than one TLB entry with the + * same virtual page field. + * + * tlb_write: same as tlb_random, but you choose the slot. + * + * tlb_read: read a TLB entry out of the TLB into ENTRYHI and ENTRYLO. + * INDEX specifies which one to get. + * + * tlb_probe: look for an entry matching the virtual page in ENTRYHI. + * Returns the index, or a negative number if no matching entry + * was found. ENTRYLO is not actually used, but must be set; 0 + * should be passed. + * + * IMPORTANT NOTE: An entry may be matching even if the valid bit + * is not set. To completely invalidate the TLB, load it with + * translations for addresses in one of the unmapped address + * ranges - these will never be matched. + */ + +void tlb_random(uint32_t entryhi, uint32_t entrylo); +void tlb_write(uint32_t entryhi, uint32_t entrylo, uint32_t index); +void tlb_read(uint32_t *entryhi, uint32_t *entrylo, uint32_t index); +int tlb_probe(uint32_t entryhi, uint32_t entrylo); + +/* + * TLB entry fields. + * + * Note that the MIPS has support for a 6-bit address space ID. In the + * interests of simplicity, we don't use it. The fields related to it + * (TLBLO_GLOBAL and TLBHI_PID) can be left always zero, as can the + * bits that aren't assigned a meaning. + * + * The TLBLO_DIRTY bit is actually a write privilege bit - it is not + * ever set by the processor. If you set it, writes are permitted. If + * you don't set it, you'll get a "TLB Modify" exception when a write + * is attempted. + * + * There is probably no reason in the course of CS161 to use TLBLO_NOCACHE. + */ + +/* Fields in the high-order word */ +#define TLBHI_VPAGE 0xfffff000 +/* TLBHI_PID 0x00000fc0 */ + +/* Fields in the low-order word */ +#define TLBLO_PPAGE 0xfffff000 +#define TLBLO_NOCACHE 0x00000800 +#define TLBLO_DIRTY 0x00000400 +#define TLBLO_VALID 0x00000200 +/* TLBLO_GLOBAL 0x00000100 */ + +/* + * Values for completely invalid TLB entries. The TLB entry index should + * be passed to TLBHI_INVALID; this prevents loading the same invalid + * entry into multiple TLB slots. + */ +#define TLBHI_INVALID(entryno) ((0x80000+(entryno))<<12) +#define TLBLO_INVALID() (0) + +/* + * Number of TLB entries in the processor. + */ + +#define NUM_TLB 64 + + +#endif /* _MIPS_TLB_H_ */ diff --git a/kern/arch/mips/include/trapframe.h b/kern/arch/mips/include/trapframe.h new file mode 100644 index 0000000..931ed89 --- /dev/null +++ b/kern/arch/mips/include/trapframe.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MIPS_TRAPFRAME_H_ +#define _MIPS_TRAPFRAME_H_ + +/* + * Structure describing what is saved on the stack during entry to + * the exception handler. + * + * This must agree with the code in exception-*.S. + */ + +struct trapframe { + uint32_t tf_vaddr; /* coprocessor 0 vaddr register */ + uint32_t tf_status; /* coprocessor 0 status register */ + uint32_t tf_cause; /* coprocessor 0 cause register */ + uint32_t tf_lo; + uint32_t tf_hi; + uint32_t tf_ra; /* Saved register 31 */ + uint32_t tf_at; /* Saved register 1 (AT) */ + uint32_t tf_v0; /* Saved register 2 (v0) */ + uint32_t tf_v1; /* etc. */ + uint32_t tf_a0; + uint32_t tf_a1; + uint32_t tf_a2; + uint32_t tf_a3; + uint32_t tf_t0; + uint32_t tf_t1; + uint32_t tf_t2; + uint32_t tf_t3; + uint32_t tf_t4; + uint32_t tf_t5; + uint32_t tf_t6; + uint32_t tf_t7; + uint32_t tf_s0; + uint32_t tf_s1; + uint32_t tf_s2; + uint32_t tf_s3; + uint32_t tf_s4; + uint32_t tf_s5; + uint32_t tf_s6; + uint32_t tf_s7; + uint32_t tf_t8; + uint32_t tf_t9; + uint32_t tf_gp; + uint32_t tf_sp; + uint32_t tf_s8; + uint32_t tf_epc; /* coprocessor 0 epc register */ +}; + +/* + * MIPS exception codes. + */ +#define EX_IRQ 0 /* Interrupt */ +#define EX_MOD 1 /* TLB Modify (write to read-only page) */ +#define EX_TLBL 2 /* TLB miss on load */ +#define EX_TLBS 3 /* TLB miss on store */ +#define EX_ADEL 4 /* Address error on load */ +#define EX_ADES 5 /* Address error on store */ +#define EX_IBE 6 /* Bus error on instruction fetch */ +#define EX_DBE 7 /* Bus error on data load *or* store */ +#define EX_SYS 8 /* Syscall */ +#define EX_BP 9 /* Breakpoint */ +#define EX_RI 10 /* Reserved (illegal) instruction */ +#define EX_CPU 11 /* Coprocessor unusable */ +#define EX_OVF 12 /* Arithmetic overflow */ + +/* + * Function to enter user mode. Does not return. The trapframe must + * be on the thread's own stack or bad things will happen. + */ +__DEAD void mips_usermode(struct trapframe *tf); + +/* + * Arrays used to load the kernel stack and curthread on trap entry. + */ +extern vaddr_t cpustacks[]; +extern vaddr_t cputhreads[]; + + +#endif /* _MIPS_TRAPFRAME_H_ */ diff --git a/kern/arch/mips/include/types.h b/kern/arch/mips/include/types.h new file mode 100644 index 0000000..707d61e --- /dev/null +++ b/kern/arch/mips/include/types.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MIPS_TYPES_H_ +#define _MIPS_TYPES_H_ + +/* + * Machine-dependent types that are *not* made visible to userland. + * Those that are made visible are found in kern/machine/types.h. + * 32-bit MIPS version. + * + * (Use the underscore versions of the base type names because this + * file is included by types.h before the non-underscore versions are + * defined.) + */ + +typedef __u32 paddr_t; +typedef __u32 vaddr_t; + +#endif /* _MIPS_TYPES_H_ */ diff --git a/kern/arch/mips/include/vm.h b/kern/arch/mips/include/vm.h new file mode 100644 index 0000000..92fb454 --- /dev/null +++ b/kern/arch/mips/include/vm.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MIPS_VM_H_ +#define _MIPS_VM_H_ + + +/* + * Machine-dependent VM system definitions. + */ + +#define PAGE_SIZE 4096 /* size of VM page */ +#define PAGE_FRAME 0xfffff000 /* mask for getting page number from addr */ + +/* + * MIPS-I hardwired memory layout: + * 0xc0000000 - 0xffffffff kseg2 (kernel, tlb-mapped) + * 0xa0000000 - 0xbfffffff kseg1 (kernel, unmapped, uncached) + * 0x80000000 - 0x9fffffff kseg0 (kernel, unmapped, cached) + * 0x00000000 - 0x7fffffff kuseg (user, tlb-mapped) + * + * (mips32 is a little different) + */ + +#define MIPS_KUSEG 0x00000000 +#define MIPS_KSEG0 0x80000000 +#define MIPS_KSEG1 0xa0000000 +#define MIPS_KSEG2 0xc0000000 + +/* + * The first 512 megs of physical space can be addressed in both kseg0 and + * kseg1. We use kseg0 for the kernel. This macro returns the kernel virtual + * address of a given physical address within that range. (We assume we're + * not using systems with more physical space than that anyway.) + * + * N.B. If you, say, call a function that returns a paddr or 0 on error, + * check the paddr for being 0 *before* you use this macro. While paddr 0 + * is not legal for memory allocation or memory management (it holds + * exception handler code) when converted to a vaddr it's *not* NULL, *is* + * a valid address, and will make a *huge* mess if you scribble on it. + */ +#define PADDR_TO_KVADDR(paddr) ((paddr)+MIPS_KSEG0) + +/* + * The top of user space. (Actually, the address immediately above the + * last valid user address.) + */ +#define USERSPACETOP MIPS_KSEG0 + +/* + * The starting value for the stack pointer at user level. Because + * the stack is subtract-then-store, this can start as the next + * address after the stack area. + * + * We put the stack at the very top of user virtual memory because it + * grows downwards. + */ +#define USERSTACK USERSPACETOP + +/* + * Interface to the low-level module that looks after the amount of + * physical memory we have. + * + * ram_getsize returns one past the highest valid physical + * address. (This value is page-aligned.) The extant RAM ranges from + * physical address 0 up to but not including this address. + * + * ram_getfirstfree returns the lowest valid physical address. (It is + * also page-aligned.) Memory at this address and above is available + * for use during operation, and excludes the space the kernel is + * loaded into and memory that is grabbed in the very early stages of + * bootup. Memory below this address is already in use and should be + * reserved or otherwise not managed by the VM system. It should be + * called exactly once when the VM system initializes to take over + * management of physical memory. + * + * ram_stealmem can be used before ram_getsize is called to allocate + * memory that cannot be freed later. This is intended for use early + * in bootup before VM initialization is complete. + */ + +void ram_bootstrap(void); +paddr_t ram_stealmem(unsigned long npages); +paddr_t ram_getsize(void); +paddr_t ram_getfirstfree(void); + +/* + * TLB shootdown bits. + * + * We'll take up to 16 invalidations before just flushing the whole TLB. + */ + +struct tlbshootdown { + /* + * Change this to what you need for your VM design. + */ + int ts_placeholder; +}; + +#define TLBSHOOTDOWN_MAX 16 + + +#endif /* _MIPS_VM_H_ */ diff --git a/kern/arch/mips/locore/cache-mips161.S b/kern/arch/mips/locore/cache-mips161.S new file mode 100644 index 0000000..a6865a7 --- /dev/null +++ b/kern/arch/mips/locore/cache-mips161.S @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2001, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + + /* + * Cache flushing code for the System/161 MIPS variant, which + * (for now at least) has magically coherent caches. Almost all + * real MIPS processors require explicit cache control of one + * form or another; it can be quite a nuisance. (It is particularly + * nasty on the MIPS-1, that is, r2000/r3000.) + */ + + .text + .set noreorder + + .globl mips_flushicache + .type mips_flushicache,@function + .ent mips_flushicache +mips_flushicache: + j ra + nop + .end mips_flushicache diff --git a/kern/arch/mips/locore/exception-mips1.S b/kern/arch/mips/locore/exception-mips1.S new file mode 100644 index 0000000..f0fec13 --- /dev/null +++ b/kern/arch/mips/locore/exception-mips1.S @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * Entry points for exceptions. + * + * MIPS-1 (r2000/r3000) style exception handling, with the "rfe" + * instruction rather than "eret", and the three sets of status bits. + */ + + + /* + * Do not allow the assembler to use $1 (at), because we need to be + * able to save it. + */ + .set noat + .set noreorder + +/* + * UTLB exception handler. + * + * This code is copied to address 0x80000000, where the MIPS processor + * automatically invokes it. + * + * To avoid colliding with the other exception code, it must not + * exceed 128 bytes (32 instructions). + * + * This is the special entry point for the fast-path TLB refill for + * faults in the user address space. We don't implement fast-path TLB + * refill by default. Note that if you do, you either need to make + * sure the refill code doesn't fault or write extra code in + * common_exception to tidy up after such faults. + */ + + .text + .globl mips_utlb_handler + .type mips_utlb_handler,@function + .ent mips_utlb_handler +mips_utlb_handler: + j common_exception /* Don't need to do anything special */ + nop /* Delay slot */ + .globl mips_utlb_end +mips_utlb_end: + .end mips_utlb_handler + +/* + * General exception handler. + * + * This code is copied to address 0x80000080, where + * the MIPS processor automatically invokes it. + */ + + .text + .globl mips_general_handler + .type mips_general_handler,@function + .ent mips_general_handler +mips_general_handler: + j common_exception /* Don't need to do anything special */ + nop /* Delay slot */ + .globl mips_general_end +mips_general_end: + .end mips_general_handler + + /* This keeps gdb from conflating common_exception and mips_general_end */ + nop /* padding */ + + +/* + * Shared exception code for both handlers. + */ + + .text + .type common_exception,@function + .ent common_exception + .cfi_startproc + .cfi_signal_frame +common_exception: + mfc0 k0, c0_status /* Get status register */ + andi k0, k0, CST_KUp /* Check the we-were-in-user-mode bit */ + beq k0, $0, 1f /* If clear, from kernel, already have stack */ + nop /* delay slot */ + + /* Coming from user mode - find kernel stack */ + mfc0 k1, c0_context /* we keep the CPU number here */ + srl k1, k1, CTX_PTBASESHIFT /* shift it to get just the CPU number */ + sll k1, k1, 2 /* shift it back to make an array index */ + lui k0, %hi(cpustacks) /* get base address of cpustacks[] */ + addu k0, k0, k1 /* index it */ + move k1, sp /* Save previous stack pointer in k1 */ + b 2f /* Skip to common code */ + lw sp, %lo(cpustacks)(k0) /* Load kernel stack pointer (in delay slot) */ +1: + /* Coming from kernel mode - just save previous stuff */ + move k1, sp /* Save previous stack in k1 (delay slot) */ +2: + /* + * At this point: + * Interrupts are off. (The processor did this for us.) + * k0 contains the value for curthread, to go into s7. + * k1 contains the old stack pointer. + * sp points into the kernel stack. + * All other registers are untouched. + */ + + /* + * Allocate stack space for 35 words to hold the trap frame, + * plus four more words for a minimal argument block, plus + * one more for proper (64-bit) stack alignment. + */ + addi sp, sp, -160 + .cfi_def_cfa sp, 0 + + /* + * Save general registers. + * We exclude k0/k1, which the kernel is free to clobber (and which + * we already have clobbered), and $0, whose value is fixed. + * + * The order here must match mips/include/trapframe.h. + * + * gdb uses the .cfi_offset assembler directives inserted below to + * to figure out where each register is stored. Since we've marked + * this function as a "signal handler" with the .cfi_signal_frame + * directive, gdb won't complain about the fact that the stack + * is noncontiguous (if we're coming from userland). + * + * We also play a trick with the return address: we mark the ra + * register as stored to the stack normally and then mark the + * return address for *this* function as being in the k1 register + * using the .cfi_return_column directive. gdb is then able to + * recognize that the ra we've stored here is the return address + * for the function that was executing when this exception was + * taken. + * + * All of the cfi (call frame information) material is compiled + * into the .eh_frame section of the compiled kernel. + */ + sw s8, 148(sp) /* save s8 */ + .cfi_offset s8, 148 + sw k1, 144(sp) /* real saved sp */ + .cfi_offset sp, 144 + sw gp, 140(sp) /* save gp */ + nop /* delay slot for store */ + .cfi_offset gp, 140 + + .cfi_return_column k1 + mfc0 k1, c0_epc /* Copr.0 reg 13 == PC for exception */ + sw k1, 152(sp) /* real saved PC */ + .cfi_offset k1, 152 + + sw t9, 136(sp) + .cfi_offset t9, 136 + sw t8, 132(sp) + .cfi_offset t8, 132 + sw s7, 128(sp) + .cfi_offset s7, 128 + sw s6, 124(sp) + .cfi_offset s6, 124 + sw s5, 120(sp) + .cfi_offset s5, 120 + sw s4, 116(sp) + .cfi_offset s4, 116 + sw s3, 112(sp) + .cfi_offset s3, 112 + sw s2, 108(sp) + .cfi_offset s2, 108 + sw s1, 104(sp) + .cfi_offset s1, 104 + sw s0, 100(sp) + .cfi_offset s0, 100 + sw t7, 96(sp) + .cfi_offset t7, 96 + sw t6, 92(sp) + .cfi_offset t6, 92 + sw t5, 88(sp) + .cfi_offset t5, 88 + sw t4, 84(sp) + .cfi_offset t4, 84 + sw t3, 80(sp) + .cfi_offset t3, 80 + sw t2, 76(sp) + .cfi_offset t2, 76 + sw t1, 72(sp) + .cfi_offset t1, 72 + sw t0, 68(sp) + .cfi_offset t0, 68 + sw a3, 64(sp) + .cfi_offset a3, 64 + sw a2, 60(sp) + .cfi_offset a2, 60 + sw a1, 56(sp) + .cfi_offset a1, 56 + sw a0, 52(sp) + .cfi_offset a0, 52 + sw v1, 48(sp) + .cfi_offset v1, 48 + sw v0, 44(sp) + .cfi_offset v0, 44 + sw AT, 40(sp) + .cfi_offset AT, 40 + + sw ra, 36(sp) + .cfi_offset ra, 36 + + /* + * Save special registers. + */ + mfhi t0 + mflo t1 + sw t0, 32(sp) + sw t1, 28(sp) + + /* + * Save remaining exception context information. + */ + + mfc0 t2, c0_status /* Copr.0 reg 11 == status */ + sw t2, 20(sp) + mfc0 t3, c0_vaddr /* Copr.0 reg 8 == faulting vaddr */ + sw t3, 16(sp) + mfc0 t4, c0_cause + sw t4, 24(sp) /* Copr.0 reg 13 == exception cause */ + + /* + * Load the curthread register if coming from user mode. + */ + andi k0, t2, CST_KUp /* Check the we-were-in-user-mode bit */ + beq k0, $0, 3f /* If clear, were in kernel, skip ahead */ + nop /* delay slot */ + + mfc0 k1, c0_context /* we keep the CPU number here */ + srl k1, k1, CTX_PTBASESHIFT /* shift it to get just the CPU number */ + sll k1, k1, 2 /* shift it back to make an array index */ + lui k0, %hi(cputhreads) /* get base address of cputhreads[] */ + addu k0, k0, k1 /* index it */ + lw s7, %lo(cputhreads)(k0) /* Load curthread value */ +3: + + /* + * Load the kernel GP value. + */ + la gp, _gp + + /* + * Prepare to call mips_trap(struct trapframe *) + */ + + addiu a0, sp, 16 /* set argument - pointer to the trapframe */ + jal mips_trap /* call it */ + nop /* delay slot */ + + /* + * Now restore stuff and return from the exception. + * Interrupts should be off. + */ +exception_return: + + /* 16(sp) no need to restore tf_vaddr */ + lw t0, 20(sp) /* load status register value into t0 */ + nop /* load delay slot */ + mtc0 t0, c0_status /* store it back to coprocessor 0 */ + /* 24(sp) no need to restore tf_cause */ + + /* restore special registers */ + lw t1, 28(sp) + lw t0, 32(sp) + mtlo t1 + mthi t0 + + /* load the general registers */ + lw ra, 36(sp) + + lw AT, 40(sp) + lw v0, 44(sp) + lw v1, 48(sp) + lw a0, 52(sp) + lw a1, 56(sp) + lw a2, 60(sp) + lw a3, 64(sp) + lw t0, 68(sp) + lw t1, 72(sp) + lw t2, 76(sp) + lw t3, 80(sp) + lw t4, 84(sp) + lw t5, 88(sp) + lw t6, 92(sp) + lw t7, 96(sp) + lw s0, 100(sp) + lw s1, 104(sp) + lw s2, 108(sp) + lw s3, 112(sp) + lw s4, 116(sp) + lw s5, 120(sp) + lw s6, 124(sp) + lw s7, 128(sp) + lw t8, 132(sp) + lw t9, 136(sp) + lw gp, 140(sp) /* restore gp */ + /* 144(sp) stack pointer - below */ + lw s8, 148(sp) /* restore s8 */ + lw k1, 152(sp) /* fetch exception return PC into k1 */ + + lw sp, 144(sp) /* fetch saved sp (must be last) */ + + /* done */ + jr k1 /* jump back */ + rfe /* in delay slot */ + .cfi_endproc + .end common_exception + +/* + * Code to enter user mode for the first time. + * Does not return. + * + * This is called from mips_usermode(). + * Interrupts on this processor should be off. + */ + + .text + .globl asm_usermode + .type asm_usermode,@function + .ent asm_usermode +asm_usermode: + /* + * a0 is the address of a trapframe to use for exception "return". + * It's allocated on our stack. + * + * Move it to the stack pointer - we don't need the actual stack + * position any more. (When we come back from usermode, cpustacks[] + * will be used to reinitialize our stack pointer, and that was + * set by mips_usermode.) + * + * Then just jump to the exception return code above. + */ + + j exception_return + addiu sp, a0, -16 /* in delay slot */ + .end asm_usermode diff --git a/kern/arch/mips/locore/trap.c b/kern/arch/mips/locore/trap.c new file mode 100644 index 0000000..69ae12c --- /dev/null +++ b/kern/arch/mips/locore/trap.c @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* in exception-*.S */ +extern __DEAD void asm_usermode(struct trapframe *tf); + +/* called only from assembler, so not declared in a header */ +void mips_trap(struct trapframe *tf); + + +/* Names for trap codes */ +#define NTRAPCODES 13 +static const char *const trapcodenames[NTRAPCODES] = { + "Interrupt", + "TLB modify trap", + "TLB miss on load", + "TLB miss on store", + "Address error on load", + "Address error on store", + "Bus error on code", + "Bus error on data", + "System call", + "Break instruction", + "Illegal instruction", + "Coprocessor unusable", + "Arithmetic overflow", +}; + +/* + * Function called when user-level code hits a fatal fault. + */ +static +void +kill_curthread(vaddr_t epc, unsigned code, vaddr_t vaddr) +{ + int sig = 0; + + KASSERT(code < NTRAPCODES); + switch (code) { + case EX_IRQ: + case EX_IBE: + case EX_DBE: + case EX_SYS: + /* should not be seen */ + KASSERT(0); + sig = SIGABRT; + break; + case EX_MOD: + case EX_TLBL: + case EX_TLBS: + sig = SIGSEGV; + break; + case EX_ADEL: + case EX_ADES: + sig = SIGBUS; + break; + case EX_BP: + sig = SIGTRAP; + break; + case EX_RI: + sig = SIGILL; + break; + case EX_CPU: + sig = SIGSEGV; + break; + case EX_OVF: + sig = SIGFPE; + break; + } + + /* + * You will probably want to change this. + */ + + kprintf("Fatal user mode trap %u sig %d (%s, epc 0x%x, vaddr 0x%x)\n", + code, sig, trapcodenames[code], epc, vaddr); + panic("I don't know how to handle this\n"); +} + +/* + * General trap (exception) handling function for mips. + * This is called by the assembly-language exception handler once + * the trapframe has been set up. + */ +void +mips_trap(struct trapframe *tf) +{ + uint32_t code; + /*bool isutlb; -- not used */ + bool iskern; + int spl; + + /* The trap frame is supposed to be 35 registers long. */ + KASSERT(sizeof(struct trapframe)==(35*4)); + + /* + * Extract the exception code info from the register fields. + */ + code = (tf->tf_cause & CCA_CODE) >> CCA_CODESHIFT; + /*isutlb = (tf->tf_cause & CCA_UTLB) != 0;*/ + iskern = (tf->tf_status & CST_KUp) == 0; + + KASSERT(code < NTRAPCODES); + + /* Make sure we haven't run off our stack */ + if (curthread != NULL && curthread->t_stack != NULL) { + KASSERT((vaddr_t)tf > (vaddr_t)curthread->t_stack); + KASSERT((vaddr_t)tf < (vaddr_t)(curthread->t_stack + + STACK_SIZE)); + } + + /* Interrupt? Call the interrupt handler and return. */ + if (code == EX_IRQ) { + int old_in; + bool doadjust; + + old_in = curthread->t_in_interrupt; + curthread->t_in_interrupt = 1; + + /* + * The processor has turned interrupts off; if the + * currently recorded interrupt state is interrupts on + * (spl of 0), adjust the recorded state to match, and + * restore after processing the interrupt. + * + * How can we get an interrupt if the recorded state + * is interrupts off? Well, as things currently stand + * when the CPU finishes idling it flips interrupts on + * and off to allow things to happen, but leaves + * curspl high while doing so. + * + * While we're here, assert that the interrupt + * handling code hasn't leaked a spinlock or an + * splhigh(). + */ + + if (curthread->t_curspl == 0) { + KASSERT(curthread->t_curspl == 0); + KASSERT(curthread->t_iplhigh_count == 0); + curthread->t_curspl = IPL_HIGH; + curthread->t_iplhigh_count++; + doadjust = true; + } + else { + doadjust = false; + } + + mainbus_interrupt(tf); + + if (doadjust) { + KASSERT(curthread->t_curspl == IPL_HIGH); + KASSERT(curthread->t_iplhigh_count == 1); + curthread->t_iplhigh_count--; + curthread->t_curspl = 0; + } + + curthread->t_in_interrupt = old_in; + goto done2; + } + + /* + * The processor turned interrupts off when it took the trap. + * + * While we're in the kernel, and not actually handling an + * interrupt, restore the interrupt state to where it was in + * the previous context, which may be low (interrupts on). + * + * Do this by forcing splhigh(), which may do a redundant + * cpu_irqoff() but forces the stored MI interrupt state into + * sync, then restoring the previous state. + */ + spl = splhigh(); + splx(spl); + + /* Syscall? Call the syscall handler and return. */ + if (code == EX_SYS) { + /* Interrupts should have been on while in user mode. */ + KASSERT(curthread->t_curspl == 0); + KASSERT(curthread->t_iplhigh_count == 0); + + DEBUG(DB_SYSCALL, "syscall: #%d, args %x %x %x %x\n", + tf->tf_v0, tf->tf_a0, tf->tf_a1, tf->tf_a2, tf->tf_a3); + + syscall(tf); + goto done; + } + + /* + * Ok, it wasn't any of the really easy cases. + * Call vm_fault on the TLB exceptions. + * Panic on the bus error exceptions. + */ + switch (code) { + case EX_MOD: + if (vm_fault(VM_FAULT_READONLY, tf->tf_vaddr)==0) { + goto done; + } + break; + case EX_TLBL: + if (vm_fault(VM_FAULT_READ, tf->tf_vaddr)==0) { + goto done; + } + break; + case EX_TLBS: + if (vm_fault(VM_FAULT_WRITE, tf->tf_vaddr)==0) { + goto done; + } + break; + case EX_IBE: + case EX_DBE: + /* + * This means you loaded invalid TLB entries, or + * touched invalid parts of the direct-mapped + * segments. These are serious kernel errors, so + * panic. + * + * The MIPS won't even tell you what invalid address + * caused the bus error. + */ + panic("Bus error exception, PC=0x%x\n", tf->tf_epc); + break; + } + + /* + * If we get to this point, it's a fatal fault - either it's + * one of the other exceptions, like illegal instruction, or + * it was a page fault we couldn't handle. + */ + + if (!iskern) { + /* + * Fatal fault in user mode. + * Kill the current user process. + */ + kill_curthread(tf->tf_epc, code, tf->tf_vaddr); + goto done; + } + + /* + * Fatal fault in kernel mode. + * + * If pcb_badfaultfunc is set, we do not panic; badfaultfunc is + * set by copyin/copyout and related functions to signify that + * the addresses they're accessing are userlevel-supplied and + * not trustable. What we actually want to do is resume + * execution at the function pointed to by badfaultfunc. That's + * going to be "copyfail" (see copyinout.c), which longjmps + * back to copyin/copyout or wherever and returns EFAULT. + * + * Note that we do not just *call* this function, because that + * won't necessarily do anything. We want the control flow + * that is currently executing in copyin (or whichever), and + * is stopped while we process the exception, to *teleport* to + * copyfail. + * + * This is accomplished by changing tf->tf_epc and returning + * from the exception handler. + */ + + if (curthread != NULL && + curthread->t_machdep.tm_badfaultfunc != NULL) { + tf->tf_epc = (vaddr_t) curthread->t_machdep.tm_badfaultfunc; + goto done; + } + + /* + * Really fatal kernel-mode fault. + */ + + kprintf("panic: Fatal exception %u (%s) in kernel mode\n", code, + trapcodenames[code]); + kprintf("panic: EPC 0x%x, exception vaddr 0x%x\n", + tf->tf_epc, tf->tf_vaddr); + + panic("I can't handle this... I think I'll just die now...\n"); + + done: + /* + * Turn interrupts off on the processor, without affecting the + * stored interrupt state. + */ + cpu_irqoff(); + done2: + + /* + * The boot thread can get here (e.g. on interrupt return) but + * since it doesn't go to userlevel, it can't be returning to + * userlevel, so there's no need to set cputhreads[] and + * cpustacks[]. Just return. + */ + if (curthread->t_stack == NULL) { + return; + } + + cputhreads[curcpu->c_number] = (vaddr_t)curthread; + cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE; + + /* + * This assertion will fail if either + * (1) curthread->t_stack is corrupted, or + * (2) the trap frame is somehow on the wrong kernel stack. + * + * If cpustacks[] is corrupted, the next trap back to the + * kernel will (most likely) hang the system, so it's better + * to find out now. + */ + KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf)); +} + +/* + * Function for entering user mode. + * + * This should not be used by threads returning from traps - they + * should just return from mips_trap(). It should be used by threads + * entering user mode for the first time - whether the child thread in + * a fork(), or into a brand-new address space after exec(), or when + * starting the first userlevel program. + * + * It works by jumping into the exception return code. + * + * mips_usermode is common code for this. It cannot usefully be called + * outside the mips port, but should be called from one of the + * following places: + * - enter_new_process, for use by exec and equivalent. + * - enter_forked_process, in syscall.c, for use by fork. + */ +void +mips_usermode(struct trapframe *tf) +{ + + /* + * Interrupts should be off within the kernel while entering + * user mode. However, while in user mode, interrupts should + * be on. To interact properly with the spl-handling logic + * above, we explicitly call spl0() and then call cpu_irqoff(). + */ + spl0(); + cpu_irqoff(); + + cputhreads[curcpu->c_number] = (vaddr_t)curthread; + cpustacks[curcpu->c_number] = (vaddr_t)curthread->t_stack + STACK_SIZE; + + /* + * This assertion will fail if either + * (1) cpustacks[] is corrupted, or + * (2) the trap frame is not on our own kernel stack, or + * (3) the boot thread tries to enter user mode. + * + * If cpustacks[] is corrupted, the next trap back to the + * kernel will (most likely) hang the system, so it's better + * to find out now. + * + * It's necessary for the trap frame used here to be on the + * current thread's own stack. It cannot correctly be on + * either another thread's stack or in the kernel heap. + * (Exercise: why?) + */ + KASSERT(SAME_STACK(cpustacks[curcpu->c_number]-1, (vaddr_t)tf)); + + /* + * This actually does it. See exception-*.S. + */ + asm_usermode(tf); +} + +/* + * enter_new_process: go to user mode after loading an executable. + * + * Performs the necessary initialization so that the user program will + * get the arguments supplied in argc/argv (note that argv must be a + * user-level address) and the environment pointer env (ditto), and + * begin executing at the specified entry point. The stack pointer is + * initialized from the stackptr argument. Note that passing argc/argv + * may use additional stack space on some other platforms (but not on + * mips). + * + * Unless you implement execve() that passes environments around, just + * pass NULL for the environment. + * + * Works by creating an ersatz trapframe. + */ +void +enter_new_process(int argc, userptr_t argv, userptr_t env, + vaddr_t stack, vaddr_t entry) +{ + struct trapframe tf; + + bzero(&tf, sizeof(tf)); + + tf.tf_status = CST_IRQMASK | CST_IEp | CST_KUp; + tf.tf_epc = entry; + tf.tf_a0 = argc; + tf.tf_a1 = (vaddr_t)argv; + tf.tf_a2 = (vaddr_t)env; + tf.tf_sp = stack; + + mips_usermode(&tf); +} diff --git a/kern/arch/mips/syscall/syscall.c b/kern/arch/mips/syscall/syscall.c new file mode 100644 index 0000000..d37d239 --- /dev/null +++ b/kern/arch/mips/syscall/syscall.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * System call dispatcher. + * + * A pointer to the trapframe created during exception entry (in + * exception-*.S) is passed in. + * + * The calling conventions for syscalls are as follows: Like ordinary + * function calls, the first 4 32-bit arguments are passed in the 4 + * argument registers a0-a3. 64-bit arguments are passed in *aligned* + * pairs of registers, that is, either a0/a1 or a2/a3. This means that + * if the first argument is 32-bit and the second is 64-bit, a1 is + * unused. + * + * This much is the same as the calling conventions for ordinary + * function calls. In addition, the system call number is passed in + * the v0 register. + * + * On successful return, the return value is passed back in the v0 + * register, or v0 and v1 if 64-bit. This is also like an ordinary + * function call, and additionally the a3 register is also set to 0 to + * indicate success. + * + * On an error return, the error code is passed back in the v0 + * register, and the a3 register is set to 1 to indicate failure. + * (Userlevel code takes care of storing the error code in errno and + * returning the value -1 from the actual userlevel syscall function. + * See src/user/lib/libc/arch/mips/syscalls-mips.S and related files.) + * + * Upon syscall return the program counter stored in the trapframe + * must be incremented by one instruction; otherwise the exception + * return code will restart the "syscall" instruction and the system + * call will repeat forever. + * + * If you run out of registers (which happens quickly with 64-bit + * values) further arguments must be fetched from the user-level + * stack, starting at sp+16 to skip over the slots for the + * registerized values, with copyin(). + */ +void +syscall(struct trapframe *tf) +{ + int callno; + int32_t retval; + int err; + + KASSERT(curthread != NULL); + KASSERT(curthread->t_curspl == 0); + KASSERT(curthread->t_iplhigh_count == 0); + + callno = tf->tf_v0; + + /* + * Initialize retval to 0. Many of the system calls don't + * really return a value, just 0 for success and -1 on + * error. Since retval is the value returned on success, + * initialize it to 0 by default; thus it's not necessary to + * deal with it except for calls that return other values, + * like write. + */ + + retval = 0; + + switch (callno) { + case SYS_reboot: + err = sys_reboot(tf->tf_a0); + break; + + case SYS___time: + err = sys___time((userptr_t)tf->tf_a0, + (userptr_t)tf->tf_a1); + break; + + /* Add stuff here */ + + default: + kprintf("Unknown syscall %d\n", callno); + err = ENOSYS; + break; + } + + + if (err) { + /* + * Return the error code. This gets converted at + * userlevel to a return value of -1 and the error + * code in errno. + */ + tf->tf_v0 = err; + tf->tf_a3 = 1; /* signal an error */ + } + else { + /* Success. */ + tf->tf_v0 = retval; + tf->tf_a3 = 0; /* signal no error */ + } + + /* + * Now, advance the program counter, to avoid restarting + * the syscall over and over again. + */ + + tf->tf_epc += 4; + + /* Make sure the syscall code didn't forget to lower spl */ + KASSERT(curthread->t_curspl == 0); + /* ...or leak any spinlocks */ + KASSERT(curthread->t_iplhigh_count == 0); +} + +/* + * Enter user mode for a newly forked process. + * + * This function is provided as a reminder. You need to write + * both it and the code that calls it. + * + * Thus, you can trash it and do things another way if you prefer. + */ +void +enter_forked_process(struct trapframe *tf) +{ + (void)tf; +} diff --git a/kern/arch/mips/thread/cpu.c b/kern/arch/mips/thread/cpu.c new file mode 100644 index 0000000..d43a4ec --- /dev/null +++ b/kern/arch/mips/thread/cpu.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * CPU control functions. + */ + +#include +#include +#include +#include +#include +#include +#include + +//////////////////////////////////////////////////////////// + +/* + * Startup and exception-time stack hook. + * + * The MIPS lacks a good way to find the current CPU, current thread, + * or current thread stack upon trap entry from user mode. To deal + * with this, we store the CPU number (our number, not the hardware + * number) in a nonessential field in the MMU, which is about the only + * place possible, and then use that to index cpustacks[]. This gets + * us the value to load as the stack pointer. We can then also load + * curthread from cputhreads[] by parallel indexing. + * + * These arrays are also used to start up new CPUs, for roughly the + * same reasons. + * + * The values in the current cpu's slots in these arrays are updated + * with the current thread's information in trap.c before heading to + * userlevel, as well as being initialized in cpu_machdep_init below. + * This means that (unless something really horrible happens) on entry + * to the kernel, and when a new CPU starts up in cpu_start_secondary, + * they will have the information needed to figure out who we are and + * proceed. + */ + +vaddr_t cpustacks[MAXCPUS]; +vaddr_t cputhreads[MAXCPUS]; + +/* + * Do machine-dependent initialization of the cpu structure or things + * associated with a new cpu. Note that we're not running on the new + * cpu when this is called. + */ +void +cpu_machdep_init(struct cpu *c) +{ + vaddr_t stackpointer; + + KASSERT(c->c_number < MAXCPUS); + + if (c->c_curthread->t_stack == NULL) { + /* boot cpu; don't need to do anything here */ + } + else { + /* + * Stick the stack in cpustacks[], and thread pointer + * in cputhreads[]. + */ + + /* stack base address */ + stackpointer = (vaddr_t) c->c_curthread->t_stack; + /* since stacks grow down, get the top */ + stackpointer += STACK_SIZE; + + cpustacks[c->c_number] = stackpointer; + cputhreads[c->c_number] = (vaddr_t)c->c_curthread; + } +} + +//////////////////////////////////////////////////////////// + +/* + * Return the type name of the currently running CPU. + * + * For now, assume we're running on System/161 so we can use the + * System/161 processor-ID values. + */ + +#define SYS161_PRID_ORIG 0x000003ff +#define SYS161_PRID_2X 0x000000a1 + +static inline +uint32_t +cpu_getprid(void) +{ + uint32_t prid; + + __asm volatile("mfc0 %0,$15" : "=r" (prid)); + return prid; +} + +static inline +uint32_t +cpu_getfeatures(void) +{ + uint32_t features; + + __asm volatile(".set push;" /* save assembler mode */ + ".set mips32;" /* allow mips32 instructions */ + "mfc0 %0,$15,1;" /* get cop0 reg 15 sel 1 */ + ".set pop" /* restore assembler mode */ + : "=r" (features)); + return features; +} + +static inline +uint32_t +cpu_getifeatures(void) +{ + uint32_t features; + + __asm volatile(".set push;" /* save assembler mode */ + ".set mips32;" /* allow mips32 instructions */ + "mfc0 %0,$15,2;" /* get cop0 reg 15 sel 2 */ + ".set pop" /* restore assembler mode */ + : "=r" (features)); + return features; +} + +void +cpu_identify(char *buf, size_t max) +{ + uint32_t prid; + uint32_t features; + + prid = cpu_getprid(); + switch (prid) { + case SYS161_PRID_ORIG: + snprintf(buf, max, "MIPS/161 (System/161 1.x and pre-2.x)"); + break; + case SYS161_PRID_2X: + features = cpu_getfeatures(); + snprintf(buf, max, "MIPS/161 (System/161 2.x) features 0x%x", + features); + features = cpu_getifeatures(); + if (features != 0) { + kprintf("WARNING: unknown CPU incompatible features " + "0x%x\n", features); + } + break; + default: + snprintf(buf, max, "32-bit MIPS (unknown type, CPU ID 0x%x)", + prid); + break; + } +} + +//////////////////////////////////////////////////////////// + +/* + * Interrupt control. + * + * While the mips actually has on-chip interrupt priority masking, in + * the interests of simplicity, we don't use it. Instead we use + * coprocessor 0 register 12 (the system coprocessor "status" + * register) bit 0, IEc, which is the global interrupt enable flag. + * (IEc stands for interrupt-enable-current.) + */ + +/* + * gcc inline assembly to get at the status register. + * + * Pipeline hazards: + * - there must be at least one cycle between GET_STATUS + * and SET_STATUS; + * - it may take up to three cycles after SET_STATUS for the + * interrupt state to really change. + * + * These considerations do not (currently) apply to System/161, + * however. + */ +#define GET_STATUS(x) __asm volatile("mfc0 %0,$12" : "=r" (x)) +#define SET_STATUS(x) __asm volatile("mtc0 %0,$12" :: "r" (x)) + +/* + * Interrupts on. + */ +void +cpu_irqon(void) +{ + uint32_t x; + + GET_STATUS(x); + x |= CST_IEc; + SET_STATUS(x); +} + +/* + * Interrupts off. + */ +void +cpu_irqoff(void) +{ + uint32_t x; + + GET_STATUS(x); + x &= ~(uint32_t)CST_IEc; + SET_STATUS(x); +} + +/* + * Used below. + */ +static +void +cpu_irqonoff(void) +{ + uint32_t x, xon, xoff; + + GET_STATUS(x); + xon = x | CST_IEc; + xoff = x & ~(uint32_t)CST_IEc; + SET_STATUS(xon); + __asm volatile("nop; nop; nop; nop"); + SET_STATUS(xoff); +} + +//////////////////////////////////////////////////////////// + +/* + * Idling. + */ + +/* + * gcc inline assembly for the WAIT instruction. + * + * mips r2k/r3k has no idle instruction at all. + * + * However, to avoid completely overloading the computing cluster, we + * appropriate the mips32 WAIT instruction. + */ + +static +inline +void +wait(void) +{ + /* + * The WAIT instruction goes into powersave mode until an + * interrupt is trying to occur. + * + * Then switch interrupts on and off again, so we actually + * take the interrupt. + * + * Note that the precise behavior of this instruction in the + * System/161 simulator is partly guesswork. This code may not + * work on a real mips. + */ + __asm volatile( + ".set push;" /* save assembler mode */ + ".set mips32;" /* allow MIPS32 instructions */ + ".set volatile;" /* avoid unwanted optimization */ + "wait;" /* suspend until interrupted */ + ".set pop" /* restore assembler mode */ + ); +} + +/* + * Idle the processor until something happens. + */ +void +cpu_idle(void) +{ + wait(); + cpu_irqonoff(); +} + +/* + * Halt the CPU permanently. + */ +void +cpu_halt(void) +{ + cpu_irqoff(); + while (1) { + wait(); + } +} diff --git a/kern/arch/mips/thread/switch.S b/kern/arch/mips/thread/switch.S new file mode 100644 index 0000000..a633b16 --- /dev/null +++ b/kern/arch/mips/thread/switch.S @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Assembly language context switch code. + */ + +#include + + .text + .set noreorder + + .globl switchframe_switch + .type switchframe_switch,@function + .ent switchframe_switch +switchframe_switch: + /* + * a0 contains the address of the switchframe pointer in the old thread. + * a1 contains the address of the switchframe pointer in the new thread. + * + * The switchframe pointer is really the stack pointer. The other + * registers get saved on the stack, namely: + * + * s0-s6, s8 + * gp, ra + * + * The order must match . + * + * Note that while we'd ordinarily need to save s7 too, because we + * use it to hold curthread saving it would interfere with the way + * curthread is managed by thread.c. So we'll just let thread.c + * manage it. + */ + + /* Allocate stack space for saving 10 registers. 10*4 = 40 */ + addi sp, sp, -40 + + /* Save the registers */ + sw ra, 36(sp) + sw gp, 32(sp) + sw s8, 28(sp) + sw s6, 24(sp) + sw s5, 20(sp) + sw s4, 16(sp) + sw s3, 12(sp) + sw s2, 8(sp) + sw s1, 4(sp) + sw s0, 0(sp) + + /* Store the old stack pointer in the old thread */ + sw sp, 0(a0) + + /* Get the new stack pointer from the new thread */ + lw sp, 0(a1) + nop /* delay slot for load */ + + /* Now, restore the registers */ + lw s0, 0(sp) + lw s1, 4(sp) + lw s2, 8(sp) + lw s3, 12(sp) + lw s4, 16(sp) + lw s5, 20(sp) + lw s6, 24(sp) + lw s8, 28(sp) + lw gp, 32(sp) + lw ra, 36(sp) + nop /* delay slot for load */ + + /* and return. */ + j ra + addi sp, sp, 40 /* in delay slot */ + .end switchframe_switch diff --git a/kern/arch/mips/thread/switchframe.c b/kern/arch/mips/thread/switchframe.c new file mode 100644 index 0000000..1a7a41b --- /dev/null +++ b/kern/arch/mips/thread/switchframe.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "switchframe.h" + +/* in threadstart.S */ +extern void mips_threadstart(/* arguments are in unusual registers */); + + +/* + * Function to initialize the switchframe of a new thread, which is + * *not* the one that is currently running. + * + * The new thread should, when it is run the first time, end up calling + * thread_startup(entrypoint, data1, data2). + * + * We arrange for this by creating a phony switchframe for + * switchframe_switch() to switch to. The only trouble is that the + * switchframe doesn't include the argument registers a0-a3. So we + * store the arguments in the s* registers, and use a bit of asm + * (mips_threadstart) to move them and then jump to thread_startup. + */ +void +switchframe_init(struct thread *thread, + void (*entrypoint)(void *data1, unsigned long data2), + void *data1, unsigned long data2) +{ + vaddr_t stacktop; + struct switchframe *sf; + + /* + * MIPS stacks grow down. t_stack is just a hunk of memory, so + * get the other end of it. Then set up a switchframe on the + * top of the stack. + */ + stacktop = ((vaddr_t)thread->t_stack) + STACK_SIZE; + sf = ((struct switchframe *) stacktop) - 1; + + /* Zero out the switchframe. */ + bzero(sf, sizeof(*sf)); + + /* + * Now set the important parts: pass through the three arguments, + * and set the return address register to the place we want + * execution to begin. + * + * Thus, when switchframe_switch does its "j ra", it will + * actually jump to mips_threadstart, which will move the + * arguments into the right register and jump to + * thread_startup(). + * + * Note that this means that when we call switchframe_switch() + * in thread_switch(), we may not come back out the same way + * in the next thread. (Though we will come back out the same + * way when we later come back to the same thread again.) + * + * This has implications for code at the bottom of + * thread_switch, described in thread.c. + */ + sf->sf_s0 = (uint32_t)entrypoint; + sf->sf_s1 = (uint32_t)data1; + sf->sf_s2 = (uint32_t)data2; + sf->sf_ra = (uint32_t)mips_threadstart; + + /* Set ->t_context, and we're done. */ + thread->t_context = sf; +} diff --git a/kern/arch/mips/thread/switchframe.h b/kern/arch/mips/thread/switchframe.h new file mode 100644 index 0000000..140ebcc --- /dev/null +++ b/kern/arch/mips/thread/switchframe.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MIPS_SWITCHFRAME_H_ +#define _MIPS_SWITCHFRAME_H_ + +/* + * Structure describing what is saved on the stack during a context switch. + * + * This must agree with the code in switch.S. + */ + +struct switchframe { + uint32_t sf_s0; + uint32_t sf_s1; + uint32_t sf_s2; + uint32_t sf_s3; + uint32_t sf_s4; + uint32_t sf_s5; + uint32_t sf_s6; + uint32_t sf_s8; + uint32_t sf_gp; + uint32_t sf_ra; +}; + +#endif /* _MIPS_SWITCHFRAME_H_ */ diff --git a/kern/arch/mips/thread/thread_machdep.c b/kern/arch/mips/thread/thread_machdep.c new file mode 100644 index 0000000..fcd82ba --- /dev/null +++ b/kern/arch/mips/thread/thread_machdep.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Functions for handling struct thread_machdep. + */ + +#include +#include +#include +#include + +void +thread_machdep_init(struct thread_machdep *tm) +{ + tm->tm_badfaultfunc = NULL; +} + +void +thread_machdep_cleanup(struct thread_machdep *tm) +{ + KASSERT(tm->tm_badfaultfunc == NULL); +} diff --git a/kern/arch/mips/thread/threadstart.S b/kern/arch/mips/thread/threadstart.S new file mode 100644 index 0000000..07a3b33 --- /dev/null +++ b/kern/arch/mips/thread/threadstart.S @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Assembler-level thread startup trampoline. + */ + +#include + + .text + .set noreorder + + .globl mips_threadstart + .type mips_threadstart,@function + .ent mips_threadstart +mips_threadstart: + + /* + * This code doesn't take normal arguments. It's reached when + * switchframe_switch switches to a new thread. switchframe_switch + * does "j ra"; ra gets preloaded in switchframe_init to come here. + * + * Our arguments are in callee-save registers, as follows: + * + * s0 entrypoint + * s1 data1 + * s2 data2 + * + * We need to rearrange these so as to call the normal C function + * thread_startup(void (*entrypoint)(), void *data1, unsigned long data2). + */ + + addiu sp, sp, -16 /* make our stack frame */ + + move ra, $0 /* clear return addr so we're top of the call stack */ + + move a0, s0 /* load arguments and call */ + move a1, s1 + j thread_startup + move a2, s2 /* (in delay slot) */ + + .end mips_threadstart diff --git a/kern/arch/mips/vm/dumbvm.c b/kern/arch/mips/vm/dumbvm.c new file mode 100644 index 0000000..cf9d916 --- /dev/null +++ b/kern/arch/mips/vm/dumbvm.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Dumb MIPS-only "VM system" that is intended to only be just barely + * enough to struggle off the ground. You should replace all of this + * code while doing the VM assignment. In fact, starting in that + * assignment, this file is not included in your kernel! + * + * NOTE: it's been found over the years that students often begin on + * the VM assignment by copying dumbvm.c and trying to improve it. + * This is not recommended. dumbvm is (more or less intentionally) not + * a good design reference. The first recommendation would be: do not + * look at dumbvm at all. The second recommendation would be: if you + * do, be sure to review it from the perspective of comparing it to + * what a VM system is supposed to do, and understanding what corners + * it's cutting (there are many) and why, and more importantly, how. + */ + +/* under dumbvm, always have 72k of user stack */ +/* (this must be > 64K so argument blocks of size ARG_MAX will fit) */ +#define DUMBVM_STACKPAGES 18 + +/* + * Wrap ram_stealmem in a spinlock. + */ +static struct spinlock stealmem_lock = SPINLOCK_INITIALIZER; + +void +vm_bootstrap(void) +{ + /* Do nothing. */ +} + +/* + * Check if we're in a context that can sleep. While most of the + * operations in dumbvm don't in fact sleep, in a real VM system many + * of them would. In those, assert that sleeping is ok. This helps + * avoid the situation where syscall-layer code that works ok with + * dumbvm starts blowing up during the VM assignment. + */ +static +void +dumbvm_can_sleep(void) +{ + if (CURCPU_EXISTS()) { + /* must not hold spinlocks */ + KASSERT(curcpu->c_spinlocks == 0); + + /* must not be in an interrupt handler */ + KASSERT(curthread->t_in_interrupt == 0); + } +} + +static +paddr_t +getppages(unsigned long npages) +{ + paddr_t addr; + + spinlock_acquire(&stealmem_lock); + + addr = ram_stealmem(npages); + + spinlock_release(&stealmem_lock); + return addr; +} + +/* Allocate/free some kernel-space virtual pages */ +vaddr_t +alloc_kpages(unsigned npages) +{ + paddr_t pa; + + dumbvm_can_sleep(); + pa = getppages(npages); + if (pa==0) { + return 0; + } + return PADDR_TO_KVADDR(pa); +} + +void +free_kpages(vaddr_t addr) +{ + /* nothing - leak the memory. */ + + (void)addr; +} + +void +vm_tlbshootdown(const struct tlbshootdown *ts) +{ + (void)ts; + panic("dumbvm tried to do tlb shootdown?!\n"); +} + +int +vm_fault(int faulttype, vaddr_t faultaddress) +{ + vaddr_t vbase1, vtop1, vbase2, vtop2, stackbase, stacktop; + paddr_t paddr; + int i; + uint32_t ehi, elo; + struct addrspace *as; + int spl; + + faultaddress &= PAGE_FRAME; + + DEBUG(DB_VM, "dumbvm: fault: 0x%x\n", faultaddress); + + switch (faulttype) { + case VM_FAULT_READONLY: + /* We always create pages read-write, so we can't get this */ + panic("dumbvm: got VM_FAULT_READONLY\n"); + case VM_FAULT_READ: + case VM_FAULT_WRITE: + break; + default: + return EINVAL; + } + + if (curproc == NULL) { + /* + * No process. This is probably a kernel fault early + * in boot. Return EFAULT so as to panic instead of + * getting into an infinite faulting loop. + */ + return EFAULT; + } + + as = proc_getas(); + if (as == NULL) { + /* + * No address space set up. This is probably also a + * kernel fault early in boot. + */ + return EFAULT; + } + + /* Assert that the address space has been set up properly. */ + KASSERT(as->as_vbase1 != 0); + KASSERT(as->as_pbase1 != 0); + KASSERT(as->as_npages1 != 0); + KASSERT(as->as_vbase2 != 0); + KASSERT(as->as_pbase2 != 0); + KASSERT(as->as_npages2 != 0); + KASSERT(as->as_stackpbase != 0); + KASSERT((as->as_vbase1 & PAGE_FRAME) == as->as_vbase1); + KASSERT((as->as_pbase1 & PAGE_FRAME) == as->as_pbase1); + KASSERT((as->as_vbase2 & PAGE_FRAME) == as->as_vbase2); + KASSERT((as->as_pbase2 & PAGE_FRAME) == as->as_pbase2); + KASSERT((as->as_stackpbase & PAGE_FRAME) == as->as_stackpbase); + + vbase1 = as->as_vbase1; + vtop1 = vbase1 + as->as_npages1 * PAGE_SIZE; + vbase2 = as->as_vbase2; + vtop2 = vbase2 + as->as_npages2 * PAGE_SIZE; + stackbase = USERSTACK - DUMBVM_STACKPAGES * PAGE_SIZE; + stacktop = USERSTACK; + + if (faultaddress >= vbase1 && faultaddress < vtop1) { + paddr = (faultaddress - vbase1) + as->as_pbase1; + } + else if (faultaddress >= vbase2 && faultaddress < vtop2) { + paddr = (faultaddress - vbase2) + as->as_pbase2; + } + else if (faultaddress >= stackbase && faultaddress < stacktop) { + paddr = (faultaddress - stackbase) + as->as_stackpbase; + } + else { + return EFAULT; + } + + /* make sure it's page-aligned */ + KASSERT((paddr & PAGE_FRAME) == paddr); + + /* Disable interrupts on this CPU while frobbing the TLB. */ + spl = splhigh(); + + for (i=0; i 0x%x\n", faultaddress, paddr); + tlb_write(ehi, elo, i); + splx(spl); + return 0; + } + + kprintf("dumbvm: Ran out of TLB entries - cannot handle page fault\n"); + splx(spl); + return EFAULT; +} + +struct addrspace * +as_create(void) +{ + struct addrspace *as = kmalloc(sizeof(struct addrspace)); + if (as==NULL) { + return NULL; + } + + as->as_vbase1 = 0; + as->as_pbase1 = 0; + as->as_npages1 = 0; + as->as_vbase2 = 0; + as->as_pbase2 = 0; + as->as_npages2 = 0; + as->as_stackpbase = 0; + + return as; +} + +void +as_destroy(struct addrspace *as) +{ + dumbvm_can_sleep(); + kfree(as); +} + +void +as_activate(void) +{ + int i, spl; + struct addrspace *as; + + as = proc_getas(); + if (as == NULL) { + return; + } + + /* Disable interrupts on this CPU while frobbing the TLB. */ + spl = splhigh(); + + for (i=0; ias_vbase1 == 0) { + as->as_vbase1 = vaddr; + as->as_npages1 = npages; + return 0; + } + + if (as->as_vbase2 == 0) { + as->as_vbase2 = vaddr; + as->as_npages2 = npages; + return 0; + } + + /* + * Support for more than two regions is not available. + */ + kprintf("dumbvm: Warning: too many regions\n"); + return ENOSYS; +} + +static +void +as_zero_region(paddr_t paddr, unsigned npages) +{ + bzero((void *)PADDR_TO_KVADDR(paddr), npages * PAGE_SIZE); +} + +int +as_prepare_load(struct addrspace *as) +{ + KASSERT(as->as_pbase1 == 0); + KASSERT(as->as_pbase2 == 0); + KASSERT(as->as_stackpbase == 0); + + dumbvm_can_sleep(); + + as->as_pbase1 = getppages(as->as_npages1); + if (as->as_pbase1 == 0) { + return ENOMEM; + } + + as->as_pbase2 = getppages(as->as_npages2); + if (as->as_pbase2 == 0) { + return ENOMEM; + } + + as->as_stackpbase = getppages(DUMBVM_STACKPAGES); + if (as->as_stackpbase == 0) { + return ENOMEM; + } + + as_zero_region(as->as_pbase1, as->as_npages1); + as_zero_region(as->as_pbase2, as->as_npages2); + as_zero_region(as->as_stackpbase, DUMBVM_STACKPAGES); + + return 0; +} + +int +as_complete_load(struct addrspace *as) +{ + dumbvm_can_sleep(); + (void)as; + return 0; +} + +int +as_define_stack(struct addrspace *as, vaddr_t *stackptr) +{ + KASSERT(as->as_stackpbase != 0); + + *stackptr = USERSTACK; + return 0; +} + +int +as_copy(struct addrspace *old, struct addrspace **ret) +{ + struct addrspace *new; + + dumbvm_can_sleep(); + + new = as_create(); + if (new==NULL) { + return ENOMEM; + } + + new->as_vbase1 = old->as_vbase1; + new->as_npages1 = old->as_npages1; + new->as_vbase2 = old->as_vbase2; + new->as_npages2 = old->as_npages2; + + /* (Mis)use as_prepare_load to allocate some physical memory. */ + if (as_prepare_load(new)) { + as_destroy(new); + return ENOMEM; + } + + KASSERT(new->as_pbase1 != 0); + KASSERT(new->as_pbase2 != 0); + KASSERT(new->as_stackpbase != 0); + + memmove((void *)PADDR_TO_KVADDR(new->as_pbase1), + (const void *)PADDR_TO_KVADDR(old->as_pbase1), + old->as_npages1*PAGE_SIZE); + + memmove((void *)PADDR_TO_KVADDR(new->as_pbase2), + (const void *)PADDR_TO_KVADDR(old->as_pbase2), + old->as_npages2*PAGE_SIZE); + + memmove((void *)PADDR_TO_KVADDR(new->as_stackpbase), + (const void *)PADDR_TO_KVADDR(old->as_stackpbase), + DUMBVM_STACKPAGES*PAGE_SIZE); + + *ret = new; + return 0; +} diff --git a/kern/arch/mips/vm/ram.c b/kern/arch/mips/vm/ram.c new file mode 100644 index 0000000..8b4e4cd --- /dev/null +++ b/kern/arch/mips/vm/ram.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + + +vaddr_t firstfree; /* first free virtual address; set by start.S */ + +static paddr_t firstpaddr; /* address of first free physical page */ +static paddr_t lastpaddr; /* one past end of last free physical page */ + +/* + * Called very early in system boot to figure out how much physical + * RAM is available. + */ +void +ram_bootstrap(void) +{ + size_t ramsize; + + /* Get size of RAM. */ + ramsize = mainbus_ramsize(); + + /* + * This is the same as the last physical address, as long as + * we have less than 512 megabytes of memory. If we had more, + * we wouldn't be able to access it all through kseg0 and + * everything would get a lot more complicated. This is not a + * case we are going to worry about. + */ + if (ramsize > 512*1024*1024) { + ramsize = 512*1024*1024; + } + + lastpaddr = ramsize; + + /* + * Get first free virtual address from where start.S saved it. + * Convert to physical address. + */ + firstpaddr = firstfree - MIPS_KSEG0; + + kprintf("%uk physical memory available\n", + (lastpaddr-firstpaddr)/1024); +} + +/* + * This function is for allocating physical memory prior to VM + * initialization. + * + * The pages it hands back will not be reported to the VM system when + * the VM system calls ram_getsize(). If it's desired to free up these + * pages later on after bootup is complete, some mechanism for adding + * them to the VM system's page management must be implemented. + * Alternatively, one can do enough VM initialization early so that + * this function is never needed. + * + * Note: while the error return value of 0 is a legal physical address, + * it's not a legal *allocatable* physical address, because it's the + * page with the exception handlers on it. + * + * This function should not be called once the VM system is initialized, + * so it is not synchronized. + */ +paddr_t +ram_stealmem(unsigned long npages) +{ + size_t size; + paddr_t paddr; + + size = npages * PAGE_SIZE; + + if (firstpaddr + size > lastpaddr) { + return 0; + } + + paddr = firstpaddr; + firstpaddr += size; + + return paddr; +} + +/* + * This function is intended to be called by the VM system when it + * initializes in order to find out what memory it has available to + * manage. Physical memory begins at physical address 0 and ends with + * the address returned by this function. We assume that physical + * memory is contiguous. This is not universally true, but is true on + * the MIPS platforms we intend to run on. + * + * lastpaddr is constant once set by ram_bootstrap(), so this function + * need not be synchronized. + * + * It is recommended, however, that this function be used only to + * initialize the VM system, after which the VM system should take + * charge of knowing what memory exists. + */ +paddr_t +ram_getsize(void) +{ + return lastpaddr; +} + +/* + * This function is intended to be called by the VM system when it + * initializes in order to find out what memory it has available to + * manage. + * + * It can only be called once, and once called ram_stealmem() will + * no longer work, as that would invalidate the result it returned + * and lead to multiple things using the same memory. + * + * This function should not be called once the VM system is initialized, + * so it is not synchronized. + */ +paddr_t +ram_getfirstfree(void) +{ + paddr_t ret; + + ret = firstpaddr; + firstpaddr = lastpaddr = 0; + return ret; +} diff --git a/kern/arch/mips/vm/tlb-mips161.S b/kern/arch/mips/vm/tlb-mips161.S new file mode 100644 index 0000000..8dd1494 --- /dev/null +++ b/kern/arch/mips/vm/tlb-mips161.S @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * TLB handling for the MIPS-161. + * + * The MIPS-161 uses the simpler MIPS-1 (r2000/r3000) TLB rather + * than the paired-page TLB of later MIPS models. + * + * However, we handle MIPS32 pipeline hazards. If you want to run on + * a real MIPS-1, change the ssnops to plain nops and check where and + * how many you need in the matching processor docs. + * + * (ssnop means "superscalar nop"; it exists because the pipeline + * hazards require a fixed number of cycles, and a superscalar CPU can + * potentially issue arbitrarily many nops in one cycle.) + */ + + .text + .set noreorder + .set mips32 /* so we can use ssnop */ + + /* + * tlb_random: use the "tlbwr" instruction to write a TLB entry + * into a (very pseudo-) random slot in the TLB. + * + * Pipeline hazard: must wait between setting entryhi/lo and + * doing the tlbwr. Use two cycles; some processors may vary. + */ + .globl tlb_random + .type tlb_random,@function + .ent tlb_random +tlb_random: + mtc0 a0, c0_entryhi /* store the passed entry into the */ + mtc0 a1, c0_entrylo /* tlb entry registers */ + ssnop /* wait for pipeline hazard */ + ssnop + tlbwr /* do it */ + j ra + nop + .end tlb_random + + /* + * tlb_write: use the "tlbwi" instruction to write a TLB entry + * into a selected slot in the TLB. + * + * Pipeline hazard: must wait between setting entryhi/lo and + * doing the tlbwi. Use two cycles; some processors may vary. + */ + .text + .globl tlb_write + .type tlb_write,@function + .ent tlb_write +tlb_write: + mtc0 a0, c0_entryhi /* store the passed entry into the */ + mtc0 a1, c0_entrylo /* tlb entry registers */ + sll t0, a2, CIN_INDEXSHIFT /* shift the passed index into place */ + mtc0 t0, c0_index /* store the shifted index into the index register */ + ssnop /* wait for pipeline hazard */ + ssnop + tlbwi /* do it */ + j ra + nop + .end tlb_write + + /* + * tlb_read: use the "tlbr" instruction to read a TLB entry + * from a selected slot in the TLB. + * + * Pipeline hazard: must wait between setting c0_index and + * doing the tlbr. Use two cycles; some processors may vary. + * Similarly, three more cycles before reading c0_entryhi/lo. + */ + .text + .globl tlb_read + .type tlb_read,@function + .ent tlb_read +tlb_read: + sll t0, a2, CIN_INDEXSHIFT /* shift the passed index into place */ + mtc0 t0, c0_index /* store the shifted index into the index register */ + ssnop /* wait for pipeline hazard */ + ssnop + tlbr /* do it */ + ssnop /* wait for pipeline hazard */ + ssnop + ssnop + mfc0 t0, c0_entryhi /* get the tlb entry out of the */ + mfc0 t1, c0_entrylo /* tlb entry registers */ + sw t0, 0(a0) /* store through the passed pointer */ + j ra + sw t1, 0(a1) /* store (in delay slot) */ + .end tlb_read + + /* + * tlb_probe: use the "tlbp" instruction to find the index in the + * TLB of a TLB entry matching the relevant parts of the one supplied. + * + * Pipeline hazard: must wait between setting c0_entryhi/lo and + * doing the tlbp. Use two cycles; some processors may vary. + * Similarly, two more cycles before reading c0_index. + */ + .text + .globl tlb_probe + .type tlb_probe,@function + .ent tlb_probe +tlb_probe: + mtc0 a0, c0_entryhi /* store the passed entry into the */ + mtc0 a1, c0_entrylo /* tlb entry registers */ + ssnop /* wait for pipeline hazard */ + ssnop + tlbp /* do it */ + ssnop /* wait for pipeline hazard */ + ssnop + mfc0 t0, c0_index /* fetch the index back in t0 */ + + /* + * If the high bit (CIN_P) of c0_index is set, the probe failed. + * The high bit is not set <--> c0_index (now in t0) >= 0. + */ + + bgez t0, 1f /* did probe succeed? if so, skip forward */ + nop /* delay slot */ + addi v0, z0, -1 /* set return value to -1 to indicate failure */ + j ra /* done */ + nop /* delay slot */ + +1: + /* succeeded - get the index field from the index register value */ + andi t1, t0, CIN_INDEX /* mask off the field */ + j ra /* done */ + sra v0, t1, CIN_INDEXSHIFT /* shift it (in delay slot) */ + .end tlb_probe + + + /* + * tlb_reset + * + * Initialize the TLB. At processor startup, the TLB state is completely + * undefined. So be sure to avoid creating any duplicates. Also make sure + * that the initialization entries don't duplicate the INVALID entries + * defined in tlb.h. (This way you can write the invalid entries in + * without having to use tlbp to find out if they're going to cause dups.) + * + * This function is not defined in tlb.h because it's only called from + * start.S. + * + * Pipeline hazards are as above. + */ + .text + .globl tlb_reset + .type tlb_reset,@function + .ent tlb_reset +tlb_reset: + li t0, 0 /* t0 <- tlb index number (shifted) */ + li t1, 0x81000000 /* t1 <- tlb reset vaddr */ +1: + mtc0 $0, c0_entrylo /* set up proposed tlb entry for reset */ + mtc0 t1, c0_entryhi + ssnop /* wait for pipeline hazard */ + ssnop + tlbp /* check if it already exists */ + ssnop /* wait for pipeline hazard */ + ssnop + mfc0 t2, c0_index + bgez t2, 1b /* if it does, loop back */ + addiu t1, t1, 0x1000 /* next vaddr (in delay slot) */ + mtc0 t0, c0_index /* doesn't exist, set index to write to */ + ssnop /* wait for pipeline hazard */ + ssnop + addiu t0, t0, 0x100 /* next tlb index (shifted) */ + bne t0, 0x4000, 1b /* if it's not the last tlb index, loop */ + tlbwi /* write tlb entry (in delay slot) */ + j ra /* done */ + nop /* delay slot */ + .end tlb_reset diff --git a/kern/arch/sys161/conf/conf.arch b/kern/arch/sys161/conf/conf.arch new file mode 100644 index 0000000..21e6338 --- /dev/null +++ b/kern/arch/sys161/conf/conf.arch @@ -0,0 +1,34 @@ + +# +# Platform-dependent sources for System/161. +# + + +# +# locore +# + +# Cache handling for the kind of MIPS we have +platform sys161 file arch/mips/locore/cache-mips161.S + +# Exception handling (assembler entry points) for the kind of MIPS we have +platform sys161 file arch/mips/locore/exception-mips1.S + +# +# VM +# + +# TLB handling for the kind of MIPS we have +platform sys161 file arch/mips/vm/tlb-mips161.S + +# +# Devices. We have LAMEbus. +# + +platform sys161 file arch/sys161/dev/lamebus_machdep.c +include dev/lamebus/conf.lamebus + +# +# Startup and initialization. +# +platform sys161 file arch/sys161/main/start.S diff --git a/kern/arch/sys161/dev/lamebus_machdep.c b/kern/arch/sys161/dev/lamebus_machdep.c new file mode 100644 index 0000000..0cc1fb2 --- /dev/null +++ b/kern/arch/sys161/dev/lamebus_machdep.c @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "autoconf.h" + +/* + * CPU frequency used by the on-chip timer. + * + * Note that we really ought to measure the CPU frequency against the + * real-time clock instead of compiling it in like this. + */ +#define CPU_FREQUENCY 25000000 /* 25 MHz */ + +/* + * Access to the on-chip timer. + * + * The c0_count register increments on every cycle; when the value + * matches the c0_compare register, the timer interrupt line is + * asserted. Writing to c0_compare again clears the interrupt. + */ +static +void +mips_timer_set(uint32_t count) +{ + /* + * $11 == c0_compare; we can't use the symbolic name inside + * the asm string. + */ + __asm volatile( + ".set push;" /* save assembler mode */ + ".set mips32;" /* allow MIPS32 registers */ + "mtc0 %0, $11;" /* do it */ + ".set pop" /* restore assembler mode */ + :: "r" (count)); +} + +/* + * LAMEbus data for the system. (We have only one LAMEbus per system.) + * This does not need to be locked, because it's constant once + * initialized, and initialized before we start other threads or CPUs. + */ +static struct lamebus_softc *lamebus; + +void +mainbus_bootstrap(void) +{ + /* Interrupts should be off (and have been off since startup) */ + KASSERT(curthread->t_curspl > 0); + + /* Initialize the system LAMEbus data */ + lamebus = lamebus_init(); + + /* Probe CPUs (should these be done as device attachments instead?) */ + lamebus_find_cpus(lamebus); + + /* + * Print the device name for the main bus. + */ + kprintf("lamebus0 (system main bus)\n"); + + /* + * Now we can take interrupts without croaking, so turn them on. + * Some device probes might require being able to get interrupts. + */ + + spl0(); + + /* + * Now probe all the devices attached to the bus. + * (This amounts to all devices.) + */ + autoconf_lamebus(lamebus, 0); + + /* + * Configure the MIPS on-chip timer to interrupt HZ times a second. + */ + mips_timer_set(CPU_FREQUENCY / HZ); +} + +/* + * Start all secondary CPUs. + */ +void +mainbus_start_cpus(void) +{ + lamebus_start_cpus(lamebus); +} + +/* + * Function to generate the memory address (in the uncached segment) + * for the specified offset into the specified slot's region of the + * LAMEbus. + */ +void * +lamebus_map_area(struct lamebus_softc *bus, int slot, uint32_t offset) +{ + uint32_t address; + + (void)bus; // not needed + + KASSERT(slot >= 0 && slot < LB_NSLOTS); + + address = LB_BASEADDR + slot*LB_SLOT_SIZE + offset; + return (void *)address; +} + +/* + * Read a 32-bit register from a LAMEbus device. + */ +uint32_t +lamebus_read_register(struct lamebus_softc *bus, int slot, uint32_t offset) +{ + uint32_t *ptr; + + ptr = lamebus_map_area(bus, slot, offset); + + /* + * Make sure the load happens after anything the device has + * been doing. + */ + membar_load_load(); + + return *ptr; +} + +/* + * Write a 32-bit register of a LAMEbus device. + */ +void +lamebus_write_register(struct lamebus_softc *bus, int slot, + uint32_t offset, uint32_t val) +{ + uint32_t *ptr; + + ptr = lamebus_map_area(bus, slot, offset); + *ptr = val; + + /* + * Make sure the store happens before we do anything else to + * the device. + */ + membar_store_store(); +} + + +/* + * Power off the system. + */ +void +mainbus_poweroff(void) +{ + /* + * + * Note that lamebus_write_register() doesn't actually access + * the bus argument, so this will still work if we get here + * before the bus is initialized. + */ + lamebus_poweroff(lamebus); +} + +/* + * Reboot the system. + */ +void +mainbus_reboot(void) +{ + /* + * The MIPS doesn't appear to have any on-chip reset. + * LAMEbus doesn't have a reset control, so we just + * power off instead of rebooting. This would not be + * so great in a real system, but it's fine for what + * we're doing. + */ + kprintf("Cannot reboot - powering off instead, sorry.\n"); + mainbus_poweroff(); +} + +/* + * Halt the system. + * On some systems, this would return to the boot monitor. But we don't + * have one. + */ +void +mainbus_halt(void) +{ + cpu_halt(); +} + +/* + * Called to reset the system from panic(). + * + * By the time we get here, the system may well be sufficiently hosed + * as to panic recursively if we do much of anything. So just power off. + * (We'd reboot, but System/161 doesn't do that.) + */ +void +mainbus_panic(void) +{ + mainbus_poweroff(); +} + +/* + * Function to get the size of installed physical RAM from the LAMEbus + * controller. + */ +uint32_t +mainbus_ramsize(void) +{ + uint32_t ramsize; + + ramsize = lamebus_ramsize(); + + /* + * This is the same as the last physical address, as long as + * we have less than 508 megabytes of memory. The LAMEbus I/O + * area occupies the space between 508 megabytes and 512 + * megabytes, so if we had more RAM than this it would have to + * be discontiguous. This is not a case we are going to worry + * about. + */ + if (ramsize > 508*1024*1024) { + ramsize = 508*1024*1024; + } + + return ramsize; +} + +/* + * Send IPI. + */ +void +mainbus_send_ipi(struct cpu *target) +{ + lamebus_assert_ipi(lamebus, target); +} + +/* + * Trigger the debugger. + */ +void +mainbus_debugger(void) +{ + ltrace_stop(0); +} + +/* + * Interrupt dispatcher. + */ + +/* Wiring of LAMEbus interrupts to bits in the cause register */ +#define LAMEBUS_IRQ_BIT 0x00000400 /* all system bus slots */ +#define LAMEBUS_IPI_BIT 0x00000800 /* inter-processor interrupt */ +#define MIPS_TIMER_BIT 0x00008000 /* on-chip timer */ + +void +mainbus_interrupt(struct trapframe *tf) +{ + uint32_t cause; + bool seen = false; + + /* interrupts should be off */ + KASSERT(curthread->t_curspl > 0); + + cause = tf->tf_cause; + if (cause & LAMEBUS_IRQ_BIT) { + lamebus_interrupt(lamebus); + seen = true; + } + if (cause & LAMEBUS_IPI_BIT) { + interprocessor_interrupt(); + lamebus_clear_ipi(lamebus, curcpu); + seen = true; + } + if (cause & MIPS_TIMER_BIT) { + /* Reset the timer (this clears the interrupt) */ + mips_timer_set(CPU_FREQUENCY / HZ); + /* and call hardclock */ + hardclock(); + seen = true; + } + + if (!seen) { + if ((cause & CCA_IRQS) == 0) { + /* + * Don't panic here; this can happen if an + * interrupt line asserts (very) briefly and + * turns off again before we get as far as + * reading the cause register. This was + * actually seen... once. + */ + } + else { + /* + * But if we get an interrupt on an interrupt + * line that's not supposed to be wired up, + * complain. + */ + panic("Unknown interrupt; cause register is %08x\n", + cause); + } + } +} diff --git a/kern/arch/sys161/include/bus.h b/kern/arch/sys161/include/bus.h new file mode 100644 index 0000000..e0680b0 --- /dev/null +++ b/kern/arch/sys161/include/bus.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SYS161_BUS_H_ +#define _SYS161_BUS_H_ + +/* + * Generic bus interface file. + * + * The only bus on System/161 is LAMEbus. + * This would need to be a bit more complicated if that weren't the case. + */ + +#include /* for MIPS_KSEG1 */ +#include /* for LAMEbus definitions */ + +#define bus_write_register(bus, slot, offset, val) \ + lamebus_write_register(bus, slot, offset, val) + +#define bus_read_register(bus, slot, offset) \ + lamebus_read_register(bus, slot, offset) + +#define bus_map_area(bus, slot, offset) \ + lamebus_map_area(bus, slot, offset) + +/* + * Machine-dependent LAMEbus definitions + */ + +/* Base address of the LAMEbus mapping area */ +#define LB_BASEADDR (MIPS_KSEG1 + 0x1fe00000) + + +#endif /* _SYS161_BUS_H_ */ diff --git a/kern/arch/sys161/include/maxcpus.h b/kern/arch/sys161/include/maxcpus.h new file mode 100644 index 0000000..b6a2d41 --- /dev/null +++ b/kern/arch/sys161/include/maxcpus.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SYS161_MAXCPUS_H_ +#define _SYS161_MAXCPUS_H_ + +/* + * For various reasons (see mips/cpu.c) it's desirable to have a + * fixed-size per-cpu array in the data segment. This is + * platform-dependent rather than processor-dependent because there's + * nothing about the processor that determines how many CPUs can + * exist; however, any real platform has *some* limit. For System/161, + * the limit is 32. + */ + +#define MAXCPUS 32 + +#endif /* _SYS161_MAXCPUS_H_ */ diff --git a/kern/arch/sys161/main/start.S b/kern/arch/sys161/main/start.S new file mode 100644 index 0000000..3d2cdee --- /dev/null +++ b/kern/arch/sys161/main/start.S @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + + .set noreorder + + .text + .globl __start + .type __start,@function + .ent __start +__start: + + /* + * Stack frame. We save the return address register, even though + * it contains nothing useful. This is for gdb's benefit when it + * comes disassembling. We also need 16 bytes for making a call, + * and we have to align to an 8-byte (64-bit) boundary, so the + * total frame size is 24. + * + * Note that the frame here must match the frame we set up below + * when we switch off the bootup stack. Otherwise, gdb gets very + * confused. + */ + .frame sp, 24, $0 /* 24-byte sp-relative frame; return addr on stack */ + .mask 0x80000000, -4 /* register 31 (ra) saved at (sp+24)-4 */ + addiu sp, sp, -24 + sw ra, 20(sp) + + /* + * The System/161 loader sets up a boot stack for the first + * processor at the top of physical memory, and passes us a single + * string argument. The string lives on the very top of the stack. + * We get its address in a0. + * + * The kernel loads at virtual address 0x80000200, which is + * physical address 0x00000200. The space immediately below this + * is reserved for the exception vector code. + * + * The symbol _end is generated by the linker. It's the address of + * the end of the kernel. It's not a variable; the *value* of the + * _end symbol itself is this address. In C you'd use "&_end". + * + * We set up the memory map like this: + * + * top of memory + * free memory + * P + 0x1000 + * first thread's stack (1 page) + * P + * wasted space (< 1 page) + * copy of the boot string + * _end + * kernel + * 0x80000200 + * exception handlers + * 0x80000000 + * + * where P is the next whole page after copying the argument string. + */ + + la s0, _end /* stash _end in a saved register */ + + move a1, a0 /* move bootstring to the second argument */ + move a0, s0 /* make _end the first argument */ + jal strcpy /* call strcpy(_end, bootstring) */ + nop /* delay slot */ + + move a0, s0 /* make _end the first argument again */ + jal strlen /* call strlen(_end) */ + nop + + add t0, s0, v0 /* add in the length of the string */ + addi t0, t0, 1 /* and the null terminator */ + + + addi t0, t0, 4095 /* round up to next page boundary */ + li t1, 0xfffff000 + and t0, t0, t1 + + addi t0, t0, 4096 /* add one page to hold the stack */ + + move sp, t0 /* start the kernel stack for the first thread here */ + + sw t0, firstfree /* remember the first free page for later */ + + /* + * At this point, s0 contains the boot argument string, and no other + * registers contain anything interesting (except the stack pointer). + */ + + /* + * Now set up a stack frame on the real kernel stack: a dummy saved + * return address and four argument slots for making function calls, + * plus a wasted slot for alignment. + * + * (This needs to match the stack frame set up at the top of the + * function, or the debugger gets confused.) + */ + addiu sp, sp, -24 + sw $0, 20(sp) + + /* + * Now, copy the exception handler code onto the first page of memory. + */ + + li a0, EXADDR_UTLB + la a1, mips_utlb_handler + la a2, mips_utlb_end + sub a2, a2, a1 + jal memmove + nop + + li a0, EXADDR_GENERAL + la a1, mips_general_handler + la a2, mips_general_end + sub a2, a2, a1 + jal memmove + nop + + /* + * Flush the instruction cache to make sure the above changes show + * through to instruction fetch. + */ + jal mips_flushicache + nop + + /* + * Initialize the TLB. + */ + jal tlb_reset + nop + + /* + * Load NULL into the register we use for curthread. + */ + li s7, 0 + + /* + * Set up the status register. + * + * The MIPS has six hardware interrupt lines and two software interrupts. + * These are individually maskable in the status register. However, we + * don't use this feature (for simplicity) - we only use the master + * interrupt enable/disable flag in bit 0. So enable all of those bits + * now and forget about them. + * + * The BEV bit in the status register, if set, causes the processor to + * jump to a different set of hardwired exception handling addresses. + * This is so that the kernel's exception handling code can be loaded + * into RAM and that the boot ROM's exception handling code can be ROM. + * This flag is normally set at boot time, and we need to be sure to + * clear it. + * + * The KUo/IEo/KUp/IEp/KUc/IEc bits should all start at zero. + * + * We also want all the other random control bits (mostly for cache + * stuff) set to zero. + * + * Thus, the actual value we write is CST_IRQMASK. + */ + + li t0, CST_IRQMASK /* get value */ + mtc0 t0, c0_status /* set status register */ + + /* + * Load the CPU number into the PTBASE field of the CONTEXT + * register. This is necessary to read from cpustacks[] and + * cputhreads[] on trap entry from user mode. See further + * discussions elsewhere. + * + * Because the boot CPU is CPU 0, we can just send 0. + */ + mtc0 $0, c0_context + + /* + * Load the GP register. This is a MIPS ABI feature; the GP + * register points to an address in the middle of the data segment, + * so data can be accessed relative to GP using one instruction + * instead of the two it takes to set up a full 32-bit address. + */ + la gp, _gp + + /* + * We're all set up! + * Fetch the copy of the bootstring as the argument, and call main. + */ + jal kmain + move a0, s0 /* in delay slot */ + + + /* + * kmain shouldn't return. panic. + * Loop back just in case panic returns too. + */ +1: + la a0, panicstr + jal panic + nop /* delay slot */ + j 1b + nop /* delay slot */ + .end __start + + .rdata +panicstr: + .asciz "kmain returned\n" + + /* + * CPUs started after the boot CPU come here. + */ + .text + .globl cpu_start_secondary + .type cpu_start_secondary,@function + .ent cpu_start_secondary +cpu_start_secondary: + + /* + * When we get here our stack points to the CRAM area of the bus + * controller per-CPU space. This means we can, with a bit of + * caution, call C functions, but nothing very deeply nesting. + * However, we don't need to. + * + * The a0 register contains the value that was put in the second + * word of the CRAM area, which is the (software) cpu number for + * indexing cpustacks[]. None of the other registers contain + * anything useful. + */ + + + /* + * Stack frame. We save the return address register, even though + * it contains nothing useful. This is for gdb's benefit when it + * comes disassembling. We also need 16 bytes for making a call, + * and 4 bytes for alignment, so the total frame size is 24. + * + * Note that the frame here must match the frame we set up below + * when we switch stacks. Otherwise, gdb gets very confused. + */ + .frame sp, 24, $0 /* 24-byte sp-relative frame; return addr on stack */ + .mask 0x80000000, -4 /* register 31 (ra) saved at (sp+24)-4 */ + addiu sp, sp, -24 + sw ra, 20(sp) + + /* + * Fetch the stack out of cpustacks[]. + */ + lui t0, %hi(cpustacks) /* load upper half of cpustacks base addr */ + sll v0, a0, 2 /* get byte index for array (multiply by 4) */ + addu t0, t0, v0 /* add it in */ + lw sp, %lo(cpustacks)(t0) /* get the stack pointer */ + + /* + * Now fetch curthread out of cputhreads[]. + */ + lui t0, %hi(cputhreads) /* load upper half of cpustacks base addr */ + sll v0, a0, 2 /* get byte index for array (multiply by 4) */ + addu t0, t0, v0 /* add it in */ + lw s7, %lo(cputhreads)(t0) /* load curthread register */ + + /* + * Initialize the TLB. + */ + jal tlb_reset + nop + + /* + * Set up the status register, as described above. + */ + li t0, CST_IRQMASK /* get value */ + mtc0 t0, c0_status /* set status register */ + + /* + * Load the CPU number into the PTBASE field of the CONTEXT + * register, as described above. + */ + sll v0, a0, CTX_PTBASESHIFT + mtc0 v0, c0_context + + /* + * Initialize the on-chip timer interrupt. + * + * This should be set to CPU_FREQUENCY/HZ, but we don't have either + * of those values here, so we'll arbitrarily set it to 100,000. It + * will get reset to the right thing after it first fires. + */ + li v0, 100000 + mtc0 v0, c0_compare + + + /* + * Load the GP register. + */ + la gp, _gp + + /* + * Set up a stack frame. Store zero into the return address slot so + * we show as the top of the stack. + */ + addiu sp, sp, -24 + sw z0, 20(sp) + + /* + * Off to MI code. Pass the cpu number as the argument; it's already + * in the a0 register. + */ + j cpu_hatch + nop /* delay slot for jump */ + .end cpu_start_secondary diff --git a/kern/conf/DUMBVM b/kern/conf/DUMBVM new file mode 100644 index 0000000..2a19bee --- /dev/null +++ b/kern/conf/DUMBVM @@ -0,0 +1,34 @@ +# Kernel config file using dumbvm. +# This should be used until you have your own VM system. + +include conf/conf.kern # get definitions of available options + +debug # Compile with debug info and -Og. +#debugonly # Compile with debug info only (no -Og). +#options hangman # Deadlock detection. (off by default) + +# +# Device drivers for hardware. +# +device lamebus0 # System/161 main bus +device emu* at lamebus* # Emulator passthrough filesystem +device ltrace* at lamebus* # trace161 trace control device +device ltimer* at lamebus* # Timer device +device lrandom* at lamebus* # Random device +device lhd* at lamebus* # Disk device +device lser* at lamebus* # Serial port +#device lscreen* at lamebus* # Text screen (not supported yet) +#device lnet* at lamebus* # Network interface (not supported yet) +device beep0 at ltimer* # Abstract beep handler device +device con0 at lser* # Abstract console on serial port +#device con0 at lscreen* # Abstract console on screen (not supported) +device rtclock0 at ltimer* # Abstract realtime clock +device random0 at lrandom* # Abstract randomness device + +#options net # Network stack (not supported) +options semfs # Semaphores for userland + +options sfs # Always use the file system +#options netfs # You might write this as a project. + +options dumbvm # Chewing gum and baling wire. diff --git a/kern/conf/DUMBVM-OPT b/kern/conf/DUMBVM-OPT new file mode 100644 index 0000000..115016f --- /dev/null +++ b/kern/conf/DUMBVM-OPT @@ -0,0 +1,37 @@ +# Kernel config file using dumbvm. +# This should be used until you have your own VM system. +# +# This config builds with optimization for performance testing. +# + +include conf/conf.kern # get definitions of available options + +#debug # Optimizing compile (no debug). +#debugonly +options noasserts # Disable assertions. + +# +# Device drivers for hardware. +# +device lamebus0 # System/161 main bus +device emu* at lamebus* # Emulator passthrough filesystem +device ltrace* at lamebus* # trace161 trace control device +device ltimer* at lamebus* # Timer device +device lrandom* at lamebus* # Random device +device lhd* at lamebus* # Disk device +device lser* at lamebus* # Serial port +#device lscreen* at lamebus* # Text screen (not supported yet) +#device lnet* at lamebus* # Network interface (not supported yet) +device beep0 at ltimer* # Abstract beep handler device +device con0 at lser* # Abstract console on serial port +#device con0 at lscreen* # Abstract console on screen (not supported) +device rtclock0 at ltimer* # Abstract realtime clock +device random0 at lrandom* # Abstract randomness device + +#options net # Network stack (not supported) +options semfs # Semaphores for userland + +options sfs # Always use the file system +#options netfs # You might write this as a project. + +options dumbvm # Chewing gum and baling wire. diff --git a/kern/conf/GENERIC b/kern/conf/GENERIC new file mode 100644 index 0000000..a726c3c --- /dev/null +++ b/kern/conf/GENERIC @@ -0,0 +1,35 @@ +# Kernel config file for an ordinary, generic kernel. +# This config file should be used once you start working on +# your own VM system. + +include conf/conf.kern # get definitions of available options + +debug # Compile with debug info. +#debugonly # Compile with debug info only (no -Og). +#options hangman # Deadlock detection. (off by default) + +# +# Device drivers for hardware. +# +device lamebus0 # System/161 main bus +device emu* at lamebus* # Emulator passthrough filesystem +device ltrace* at lamebus* # trace161 trace control device +device ltimer* at lamebus* # Timer device +device lrandom* at lamebus* # Random device +device lhd* at lamebus* # Disk device +device lser* at lamebus* # Serial port +#device lscreen* at lamebus* # Text screen (not supported yet) +#device lnet* at lamebus* # Network interface (not supported yet) +device beep0 at ltimer* # Abstract beep handler device +device con0 at lser* # Abstract console on serial port +#device con0 at lscreen* # Abstract console on screen (not supported) +device rtclock0 at ltimer* # Abstract realtime clock +device random0 at lrandom* # Abstract randomness device + +#options net # Network stack (not supported) +options semfs # Semaphores for userland + +options sfs # Always use the file system +#options netfs # You might write this as a project. + +#options dumbvm # Use your own VM system now. diff --git a/kern/conf/GENERIC-OPT b/kern/conf/GENERIC-OPT new file mode 100644 index 0000000..7bdc740 --- /dev/null +++ b/kern/conf/GENERIC-OPT @@ -0,0 +1,37 @@ +# Kernel config file for an ordinary, generic kernel. +# This config file should be used once you start working on +# your own VM system. +# +# This config builds with optimization for performance testing. + +include conf/conf.kern # get definitions of available options + +#debug # Optimizing compile (no debug). +#debugonly +options noasserts # Disable assertions. + +# +# Device drivers for hardware. +# +device lamebus0 # System/161 main bus +device emu* at lamebus* # Emulator passthrough filesystem +device ltrace* at lamebus* # trace161 trace control device +device ltimer* at lamebus* # Timer device +device lrandom* at lamebus* # Random device +device lhd* at lamebus* # Disk device +device lser* at lamebus* # Serial port +#device lscreen* at lamebus* # Text screen (not supported yet) +#device lnet* at lamebus* # Network interface (not supported yet) +device beep0 at ltimer* # Abstract beep handler device +device con0 at lser* # Abstract console on serial port +#device con0 at lscreen* # Abstract console on screen (not supported) +device rtclock0 at ltimer* # Abstract realtime clock +device random0 at lrandom* # Abstract randomness device + +#options net # Network stack (not supported) +options semfs # Semaphores for userland + +options sfs # Always use the file system +#options netfs # You might write this as a project. + +#options dumbvm # Use your own VM system now. diff --git a/kern/conf/conf.kern b/kern/conf/conf.kern new file mode 100644 index 0000000..ad58977 --- /dev/null +++ b/kern/conf/conf.kern @@ -0,0 +1,443 @@ +# +# Machine-independent kernel config definitions. +# +# The idea is that the files, options, and facilities in the system +# are declared by conf.kern and the various files it includes. Then a +# kernel config (such as ASST1, or GENERIC, or TEST, or whatever) is +# used to select options and facilities for a particular kernel build. +# +# To add new files to the system, you need to edit this file (or +# others like it) and rerun the config script. +# +# Note: when running the config script, be sure to be in the +# right directory (the same one this file is in) and run it as +# "./config", not just "config" - in the latter case you will +# probably get the host system's kernel config utility, which +# will likely make a mess and produce mysterious error messages. +# +# The documentation for the syntax of these files follows. +# + +############################################################ +# +# Kernel config file syntax: +# +# The syntax for including the system definition is: +# +# include conf.kern +# +# This should come first. This is because the system must be +# defined before you can do much else useful. +# +# You can also include other files using the same syntax. +# +# +# The syntax for turning on a kernel compile option is: +# +# options optname +# +# A previous "defoption" must have been seen first. See below +# for more information. +# +# The act of compiling with debug info is (has to be) handled +# specially, and is just "debug" without the "options". +# +# +# The syntax for turning on a device driver is: +# +# device foo% +# device foo% at bar% +# +# where the % is either a number or a star, which is treated as +# a wildcard. The first line enables a device foo that is not +# supposed to be "attached" to anything. The second line enables +# a device foo that is attached to a device bar. For more +# information about what this means, see below. +# +# +############################################################ +# +# Kernel definition file syntax: +# +# Note: All source file names are relative to the top directory of the +# kernel source, that is, src/kern. +# +# The syntax for adding a regular source file is: +# +# [machine M | platform P] file sourcefile.c +# +# Such a file is always included automatically in every kernel +# built for machine M, or platform P, or all kernels. +# +# +# The syntax for defining optional source files is: +# +# defoption optname +# [machine M | platform P] optfile optname sourcefile.c +# [machine M | platform P] optofffile optname sourcefile.c +# +# "defoption" declares the name of a kernel option. These are +# then turned on by including "options optname" in a +# kernel config. +# +# Source files added with optfile are compiled in if the option +# specified is enabled. Source files added with optofffile are +# compiled in if the option specified is not enabled. +# +# Additionally, a file "opt-optname.h" is created in the compile +# directory, which defines a C preprocessor symbol OPT_OPTNAME. +# This symbol is #defined to either 0 or 1 in the logical way. +# Thus, you can have small bits of code that are enabled or +# disabled by particular options by writing constructs like +# +# #include "opt-foo.h" +# #if OPT_FOO +# code(); +# #else +# other_code(); +# #endif +# +# *** Be sure to use #if and not #ifdef - you want the value +# of the symbol. +# *** Be sure to remember to include the header file for the +# option - if you don't, cpp will silently assume it is 0, +# which can be quite frustrating. +# +# The defoption must be seen before any optional file +# declarations that use it. +# +# +# The syntax for defining device drivers is: +# +# defdevice devname sourcefile.c +# defattach devname% otherdevname% sourcefile.c +# pseudoattach devname% +# +# Declare a device driver and its "attachment(s)". (The device +# driver can then be selectively included or not included in any +# particular kernel by using the "device" statement in the +# kernel config file.) +# +# The specified source files are only compiled if the device +# is enabled. +# +# The % is either a specific number N, meaning "only the Nth +# such device can be attached this way", or a star (*), meaning +# "any such device can be attached this way". +# +# In OS/161, device drivers are conceptually organized into +# trees. This mimics the organization of real hardware, where +# several expansion cards are plugged into one bus and there +# might be several devices on each expansion card and so forth. +# +# There can be any number of these trees. However, devices at +# the root of each tree must be able to probe and "find" +# themselves completely on their own. This generally means that +# they are either all software with no hardware, or they are the +# system main bus which is located in a machine-dependent way. +# +# Software-only devices are known as "pseudo-devices". These +# are "attached" with the pseudoattach directive; functions +# of the form +# +# pseudoattach_devname +# +# are called from autoconf.c to create instances as requested. +# These calls are made from the function pseudoconfig(), which +# should be called from dev/init.c after hardware device +# initialization completes. The pseudoattach functions should +# perform all setup and initialization necessary. (No +# config_devname function will be called.) +# +# Devices with attachments are automatically probed and +# configured from code in autoconf.c. This file is generated +# by the config script. It contains functions called +# "autoconf_devname", for each device. These functions call +# other functions, which are supplied by device drivers, +# which have the following hardwired names: +# +# attach_devname1_to_devname2 +# +# A "devname2" device has been found and configured; +# this function attempts to probe the devname2 for +# a "devname1" device. Returns NULL if nothing was +# found. +# +# config_devname +# +# A "devname" device has been found. This function +# can then perform initialization that's shared +# among all the possible things it can be attached +# to. +# +# The idea is that there can be multiple attachments for +# the same device to different underlying devices. In the +# real world this can be used to great effect when you have, +# for instance, the same ethernet chipset used on both PCI +# and ISA cards - the chipset behaves the same way in both +# cases, but the probe and attach logic is very different. +# +# The attach_foo_to_bar functions are put in the files +# specified with defattach; the config_foo function (and +# generally the rest of the driver for the foo device) is +# put in the file specified with defdevice. +# +# One selects particular attachments when including the device +# in the kernel. A top-level device with no attachments should +# be included with this syntax: +# +# device bar +# +# A pseudo-device should be included with this syntax: +# +# device bar0 +# +# To make use of device foo, which can be found attached to +# device bar, one of the following syntaxes is used: +# +# device foo* at bar* +# device foo* at bar0 +# device foo0 at bar* +# device foo0 at bar0 +# +# depending on to what extent you want to configure only a +# specific device number. +# +# It sometimes matters what order things are handled in; probes +# occur more or less in the order things appear in the config, +# as constrained by the tree structure of the available devices. +# +# Note that OS/161 does not make extensive use of this +# functionality, and the device driver architecture outlined +# here is overkill for such a limited environment as System/161. +# However, it's similar to the way real systems are organized. +# +# +# The syntax for including other config/definition files is: +# +# include filename +# +# The filename is relative to the top of the kernel source tree. +# +# Thus, +# include conf/conf.foo includes src/kern/conf/conf.foo +# +# +############################################################ + + +######################################## +# # +# Generic machine-independent devices. # +# # +######################################## + +# +# These are abstract system services we expect the system hardware to +# provide: beeping, system console I/O, and time of day clock. +# +# These come before the archinclude so that the hardware device +# definitions, which are included from there, can define attachments +# for them. +# + +defdevice beep dev/generic/beep.c +defdevice con dev/generic/console.c +defdevice rtclock dev/generic/rtclock.c +defdevice random dev/generic/random.c + +######################################## +# # +# Machine-dependent stuff # +# # +######################################## + +# +# Get the definitions for each machine and platform supported. The +# ones used will be selected by make at compile time based on the +# contents of the top-level defs.mk file. +# +# This will declare a bunch of machine-dependent source files and also +# declare all the hardware devices (since what sorts of hardware we +# expect to find is machine-dependent.) +# + +include arch/mips/conf/conf.arch +include arch/sys161/conf/conf.arch + +######################################## +# # +# Support code # +# # +######################################## + +# +# Kernel utility code +# + +file lib/array.c +file lib/bitmap.c +file lib/bswap.c +file lib/kgets.c +file lib/kprintf.c +file lib/misc.c +file lib/time.c +file lib/uio.c + +defoption noasserts + + +# +# Standard C functions +# +# For most of these, we take the source files from our libc. Note +# that those files have to have been hacked a bit to support this. +# + +file ../common/libc/printf/__printf.c +file ../common/libc/printf/snprintf.c +file ../common/libc/stdlib/atoi.c +file ../common/libc/string/bzero.c +file ../common/libc/string/memcpy.c +file ../common/libc/string/memmove.c +file ../common/libc/string/memset.c +file ../common/libc/string/strcat.c +file ../common/libc/string/strchr.c +file ../common/libc/string/strcmp.c +file ../common/libc/string/strcpy.c +file ../common/libc/string/strlen.c +file ../common/libc/string/strrchr.c +file ../common/libc/string/strtok_r.c + +######################################## +# # +# Core kernel source files # +# # +######################################## + +# +# Thread system +# + +file thread/clock.c +file thread/spl.c +file thread/spinlock.c +file thread/synch.c +file thread/thread.c +file thread/threadlist.c + +defoption hangman +optfile hangman thread/hangman.c + +# +# Process system +# + +file proc/proc.c + +# +# Virtual memory system +# (you will probably want to add stuff here while doing the VM assignment) +# + +file vm/kmalloc.c + +optofffile dumbvm vm/addrspace.c + +# +# Network +# (nothing here yet) +# + +defoption net +#optfile net net/net.c + +# +# VFS layer +# + +file vfs/device.c +file vfs/vfscwd.c +file vfs/vfsfail.c +file vfs/vfslist.c +file vfs/vfslookup.c +file vfs/vfspath.c +file vfs/vnode.c + +# +# VFS devices +# + +file vfs/devnull.c + +# +# System call layer +# (You will probably want to add stuff here while doing the basic system +# calls assignment.) +# + +file syscall/loadelf.c +file syscall/runprogram.c +file syscall/time_syscalls.c + +# +# Startup and initialization +# + +file main/main.c +file main/menu.c + +######################################## +# # +# Filesystems # +# # +######################################## + +# +# semfs (fake filesystem providing userlevel semaphores) +# +defoption semfs +optfile semfs fs/semfs/semfs_fsops.c +optfile semfs fs/semfs/semfs_obj.c +optfile semfs fs/semfs/semfs_vnops.c + +# +# sfs (the small/simple filesystem) +# + +defoption sfs +optfile sfs fs/sfs/sfs_balloc.c +optfile sfs fs/sfs/sfs_bmap.c +optfile sfs fs/sfs/sfs_dir.c +optfile sfs fs/sfs/sfs_fsops.c +optfile sfs fs/sfs/sfs_inode.c +optfile sfs fs/sfs/sfs_io.c +optfile sfs fs/sfs/sfs_vnops.c + +# +# netfs (the networked filesystem - you might write this as one assignment) +# +defoption netfs +#optfile netfs fs/netfs/netfs_fs.c # or whatever + +# +# Note that "emufs" is completely contained in the "emu" device. +# + + +######################################## +# # +# Test code # +# # +######################################## + +file test/arraytest.c +file test/bitmaptest.c +file test/threadlisttest.c +file test/threadtest.c +file test/tt3.c +file test/synchtest.c +file test/semunit.c +file test/kmalloctest.c +file test/fstest.c +optfile net test/nettest.c diff --git a/kern/conf/config b/kern/conf/config new file mode 100755 index 0000000..f49c4ab --- /dev/null +++ b/kern/conf/config @@ -0,0 +1,1068 @@ +#!/bin/sh +# +# Kernel config script for OS/161. +# +# Usage: ./config conf-name +# +# WARNING! IF YOU JUST RUN "config" INSTEAD OF "./config" YOU WILL +# PROBABLY GET THE HOST SYSTEM'S KERNEL CONFIG INSTEAD OF THIS ONE, +# WHICH WILL CAUSE WEIRD THINGS TO HAPPEN. DON'T DO IT. +# +# +# Recognized directives: +# +# file use source file +# debug turn on debug info and -Og +# debugonly turn on debug info without -Og +# defoption define an option +# optfile if option is enabled, use file +# optofffile if option is disabled, use file +# defdevice define a device +# defattach +# define an attachment for a device to a bus +# pseudoattach define a pseudo-attachment for a device +# +# options enable an option +# device [at ] enable a particular device [on a particular bus] +# +# include get additional directives from another file +# +# Filenames are relative to the top of the kernel tree. +# +# The comment character is '#'. +# +# The idea is that the first group of directives is used to set up a +# static description of all possible configurations for each supported +# architecture. Then a kernel config file uses the second group of +# directives to specify a particular configuration. Then this script +# is used to first check that the configuration is one of the possible +# ones, and then to set up the compile directory, makefiles, and +# associated material necessary to actually build that configuration. +# +# Further documentation is at the top of conf.kern. +# + + +# +# Make sure we're in the right place. +# +if [ ! -d ../dev ]; then + echo "$0: Run me from src/kern/conf" + exit 1 +fi + +######################################## +# +# 1. Get configuration name and config file. +# + +CONFNAME=$1 +if [ "x$CONFNAME" = x ]; then + echo "Usage: $0 CONFIG-NAME" + exit 1 +fi + +FOO=`echo $CONFNAME | tr -d 'a-zA-Z0-9_-'` +if [ "x$FOO" != x ]; then + echo "Illegal configuration name $CONFNAME" + exit 1 +fi + +if [ ! -f $CONFNAME ]; then + echo "$0: $CONFNAME not found" + exit 1 +fi +echo "Configuration $CONFNAME" + +COMPILEDIR="../compile/$CONFNAME" + +######################################## +# +# 2. Process includes. +# Also strip comments. +# Simultaneously, do a basic syntax check. +# +# For an introduction to awk, see +# http://www.hcs.harvard.edu/~dholland/computers/awk.html +# + +CONFTMP=.conftmp + +rm -f $CONFTMP + +echo "$CONFNAME" $CONFTMP | awk ' + BEGIN { + # + # Initialize list of directives and required numbers of words for each. + # + nfields["include"] = 2; + nfields["file"] = 2; + nfields["debug"] = 1; + nfields["debugonly"] = 1; + nfields["defoption"] = 2; + nfields["optfile"] = 3; + nfields["optofffile"] = 3; + nfields["defdevice"] = 3; + nfields["defattach"] = 4; + nfields["pseudoattach"] = 2; + nfields["options"] = 2; + nfields["device"] = 4; # actually 2 or 4, handled specially + # + # Directives that can be made machine-dependent with "machine" + # or "platform". + # + okmd["file"] = 1; + okmd["optfile"] = 1; + okmd["optofffile"] = 1; + } + + function doinclude(file, lineno) { + # + # Include a file. + # + # lineno is a local. + # + # Read lines and hand them off recursively to processline(). + # + lineno = 1; + while (getline < file) { + if (ERRNO) { + printf "%s: %s\n", file, ERRNO; + exit(1); + } + processline(file, lineno); + lineno++; + } + } + + function processline(filename, lineno) { + # + # Handle a single config line. + # + + # Strip comments. + sub("#.*", "", $0); + + # Ignore blank lines. + if (NF==0) return; + + direct = $1; + foundfields = NF; + + if (direct == "machine" && NF > 2 && okmd[$3]) { + # machine mips file ... + direct = $3; + foundfields -= 2; + } + else if (direct == "platform" && NF > 2 && okmd[$3]) { + # platform sys161 file ... + direct = $3; + foundfields -= 2; + } + + # Syntax check: reject unknown directives + if (!nfields[direct]) { + printf "%s: %d: Unknown directive %s\n", filename, lineno, direct; + exit(1); + } + + # Syntax check: require correct # of args. + if (direct=="device") { + # special case - device directive can have 2 or 4 words + if ((NF!=2 && NF!=4) || (NF==4 && $3!="at")) { + msg = sprintf("%s: Invalid arguments", direct); + printf "%s: %d: %s\n", filename, lineno, msg; + exit(1); + } + } + else if (nfields[direct]!=foundfields) { + printf "%s: %d: %s: Invalid arguments\n", filename, lineno, direct; + exit(1); + } + + # Now actually process the directives we need at this stage - which + # is only "include". Handle includes. + + if (direct == "include") { + doinclude("../" $2); + } + else { + print >> outfile; + } + } + + # + # Code called for lines input on stdin. + # There is only one - the one generated above with echo, which + # gives us the names of the input and output files to use. + # + { + outfile = $2; + doinclude($1); + } +' || exit 1 + +######################################## +# +# 3. Create compile dir. +# + +if [ ! -d "$COMPILEDIR" ]; then + mkdir $COMPILEDIR +fi + +echo -n 'Generating files...' + +######################################## +# +# 4. Process device attachments into $CONFTMP.attach. +# Also add device/attachment files to $CONFTMP.files. +# + +rm -f $CONFTMP.files +rm -f $CONFTMP.attach + +awk < $CONFTMP ' + + # + # Function to grab the "0" off "le0" or the "*" off "wd*". + # + function getunit(invalmsg, d, u, tmp) { + u = d; + sub("^[a-zA-Z_]*", "", u); + + if (u!="*") { + tmp = u; + sub("[0-9]*", "", tmp); + if (tmp!="") { + printf "\n%s: Invalid device/unit specification\n", invalmsg; + exit(1); + } + } + + return u; + } + + # + # Function to grab the "le" off "le0" or the "wd" off "wd*". + # + function getbase(invalmsg, d, base) { + base = d; + sub("[\\*0-9]*$", "", base); + + if (!use[base]) { + printf "\n%s: No such device\n", invalmsg; + exit(1); + } + + return base; + } + + # + # Routine invoked for "defdevice" directive lines. + # + $1=="defdevice" { + dev = $2; + file = $3; + + # Check for illegal characters in device name + # (must be legal C symbol, and at this point must not have unit number) + tmp = dev; + sub("[a-zA-Z_]*", "", tmp); + if (tmp!="") { + printf "\ndefdevice %s: Illegal device name\n", dev; + exit(1); + } + + # Device must not have been already defined. + if (use[dev]) { + printf "\ndefdevice %s: %s already exists\n", dev, dev; + exit(1); + } + + # Note that it exists, but is not in use, and remember the + # source file for later. + use[dev] = "no"; + files[dev] = file; + } + + # + # Routine called for "defattach" directive lines. + # + $1=="defattach" { + dev = $2; + bus = $3; + file = $4; + + # Even though we do not use basebus, busunit, or devunit, + # call the routines to compute them, because they check the + # syntax. + + devmsg = "defattach: device " dev; + devunit = getunit(devmsg, dev); + basedev = getbase(devmsg, dev); + + busmsg = "defattach: bus " bus; + busunit = getunit(busmsg, bus); + basebus = getbase(busmsg, bus); + + if (pseudo[basedev]) { + printf "\n%s: Already declared pseudoattach\n", devmsg; + exit(1); + } + + # The attachment is the pair of bus and device. + # We remember the specific names, including the unit numbers. + # This is because "le* at sbus*" is different from "le0 at sbus0" + # - the former allows le0 to be at sbus1, allows le1, etc. + + attachment = bus "." dev; + attach[attachment] = "no"; + files[attachment] = file; + + # Remember that attachments are defined for this device. If + # attachments are defined, when the device is turned on later + # an attachment must be specified. + attachable[basedev] = 1; + } + + # + # Routine called for "pseudoattach" directive lines. + # + $1=="pseudoattach" { + dev = $2; + + devmsg = "pseudoattach: device " dev; + devunit = getunit(devmsg, dev); + basedev = getbase(devmsg, dev); + + if (attachable[basedev]) { + printf "\n%s: Attachments already declared\n", devmsg; + exit(1); + } + + # Remember that this device is a pseudo-device. + pseudo[basedev] = 1; + } + + # + # Helper function for the "device" code. + # + function tryattach(combo) { + if (!attachok && attach[combo]) { + # This attachment is defined. Note to compile it in, and report + # success. + attach[combo] = "yes"; + attachok = 1; + } + } + + # + # Routine called for "device" directive lines. + # + $1=="device" { + dev = $2; + if (NF==4) { + devmsg = "device: " dev " at " $4; + } + else { + devmsg = "device: device " dev; + } + devunit = getunit(devmsg, dev); + basedev = getbase(devmsg, dev); + gendev = basedev "*"; + + if (NF==4) { + # + # The longer form, with an attachment ("bus"). + # + bus = $4; + busmsg = "device: " dev " at " bus ": " bus; + busunit = getunit(busmsg, bus); + basebus = getbase(busmsg, bus); + genbus = basebus "*"; + + if (use[basebus]!="yes") { + printf "\ndevice: bus %s: Bus device is not enabled\n", bus; + exit(1); + } + + # If the line was "le0 at sbus0", we try to attach it using + # the following attachments: + # First, the exact thing that was requested: + # sbus0.le0 (le0 at sbus0) + # Second, for any such device on that bus: + # sbus*.le0 (le0 at sbus*) + # Third, for that device on any such bus: + # sbus0.le* (le* at sbus0) + # Fourth, for any such device on any such bus: + # sbus*.le* (le* at sbus*) + # + # If the line was "le* at sbus0", some of these will be + # redundant, but that is ok. + + attachok = 0; + tryattach(bus "." dev); + tryattach(bus "." gendev); + tryattach(genbus "." dev); + tryattach(genbus "." gendev); + if (!attachok) { + # No matching attachment found. + printf "\ndevice: %s at %s: Undefined attachment\n", dev, bus; + exit(1); + } + + devattach = sprintf("%s %s", basedev, devunit); + baseattach = sprintf("%s %s", basebus, busunit); + printf "attach %s at %s\n", devattach, baseattach >> attachfile; + } + else { + # No bus specified to attach the device to (really, to find the + # device attached on.) This is only legal if no attachments + # at all were defined for the device, which is the case if the + # device is in fact not attached to anything else (like the main + # system bus, or a device like /dev/null that has no hardware.) + + + # The opposite check to this is not required in the + # preceding section because no attachment can be found if + # attachable[basedev] is false. + + if (attachable[basedev]) { + printf "\ndevice %s: attachment required\n", dev; + exit(1); + } + + if (pseudo[basedev]) { + if (devunit=="*") { + printf "\n%s: May not use wildcard units here\n", devmsg; + exit(1); + } + printf "pseudo %s %s\n", basedev, devunit >> attachfile; + } + else { + printf "noattach %s\n", basedev >> attachfile; + } + } + + use[basedev] = "yes"; + } + + # + # Routine invoked when we have seen all the input. + # + END { + # Print out the source filenames for the devices and attachments + # we are using. + + for (dev in use) { + if (use[dev]=="yes") { + printf "* * %s\n", files[dev] >> filelistfile; + } + } + for (att in attach) { + if (attach[att]=="yes") { + printf "* * %s\n", files[att] >> filelistfile; + } + } + } + +' "attachfile=$CONFTMP.attach" "filelistfile=$CONFTMP.files" || exit 1 + +######################################## +# +# 5. Process options. +# + +awk < $CONFTMP ' + + # + # Routine for a defoption line. + # + $1=="defoption" { + opt = $2; + options[opt] = "no"; + } + + # + # Routine for an optfile line. + # + $1=="optfile" || (($1=="machine" || $1=="platform") && $3=="optfile") { + if ($1 == "optfile") { + opt = $2; + file = $3; + platform = "*"; + machine = "*"; + } + else { + if ($1=="machine") { + platform = "*"; + machine = $2; + } + else { + platform = $2; + machine = "*"; + } + opt = $4; + file = $5; + } + + if (!options[opt]) { + printf "\noptfile %s %s: No such option %s\n", opt, file, opt; + exit(1); + } + + controllers[file] = opt; + platforms[file] = platform; + machines[file] = machine; + } + + # + # Routine for an optofffile line. + # + $1=="optofffile" || (($1=="machine" || $1=="platform") &&$3=="optofffile"){ + if ($1 == "optofffile") { + opt = $2; + file = $3; + platform = "*"; + machine = "*"; + } + else { + if ($1=="machine") { + platform = "*"; + machine = $2; + } + else { + platform = $2; + machine = "*"; + } + opt = $4; + file = $5; + } + + if (!options[opt]) { + printf "\noptofffile %s %s: No such option %s\n", opt, file, opt; + exit(1); + } + + offcontrollers[file] = opt; + platforms[file] = platform; + machines[file] = machine; + } + + # + # Routine for an options line. + # + $1=="options" { + opt = $2; + + if (!options[$2]) { + printf "\noptions %s: No such option\n", opt; + exit(1); + } + + options[$2] = "yes"; + } + + # + # Routine invoked when we have seen everything. + # + END { + # + # First, add any files to the list of sources we are building. + # + for (file in controllers) { + if (options[controllers[file]]=="yes") { + line = sprintf("%s %s %s", + platforms[file], machines[file], file); + printf "%s\n", line >> filelistfile; + } + } + for (file in offcontrollers) { + if (options[offcontrollers[file]]=="no") { + line = sprintf("%s %s %s", + platforms[file], machines[file], file); + printf "%s\n", line >> filelistfile; + } + } + close(filelistfile); + + # + # Now, generate the .h file for every option + # (both the ones that are on and the ones that are off) + # + for (opt in options) { + realfile = compiledir "/opt-" opt ".h"; + file = realfile ".new"; + sym = toupper(opt); + printf "/* Automatically generated; do not edit */\n" > file; + printf "#ifndef _OPT_%s_H_\n", sym >> file; + printf "#define _OPT_%s_H_\n", sym >> file; + val = options[opt]=="yes" ? 1 : 0; + printf "#define OPT_%s %d\n", sym, val >> file; + printf "#endif /* _OPT_%s_H_ */\n", sym >> file; + close(file); + } + } + +' "compiledir=$COMPILEDIR" "filelistfile=$CONFTMP.files" || exit 1 + +# Avoid changing the actual headers if they aren't different, so as to +# reduce unnecessary recompiles. + +( + cd $COMPILEDIR + for NF in opt-*.h.new; do + OF=`echo $NF | sed 's/\.new$//'` + if diff $OF $NF >/dev/null 2>&1; then + rm -f $NF # unchanged + else + mv -f $NF $OF # it changed + fi + echo -n " $OF" + done +) + +######################################## +# +# 6. Add in the unconditional files. +# + +awk < $CONFTMP ' + $1=="file" { + printf "* * %s\n", $2 >> filelistfile; + } + $1=="machine" && $3=="file" { + printf "* %s %s\n", $2, $4 >> filelistfile; + } + $1=="platform" && $3=="file" { + printf "%s * %s\n", $2, $4 >> filelistfile; + } + +' "filelistfile=$CONFTMP.files" || exit 1 + +# +# autoconf.c (which we generate further down) is always compiled in but +# is not in the list yet. Note that the path to it is where we are about +# to put it: it lives in the build directory, because it's part of a +# particular build. +# +echo "* * compile/$CONFNAME/autoconf.c" >> $CONFTMP.files + +######################################## +# +# 7. We now have the compile file list. +# Generate files.mk. +# + +# +# Validate list first. +# +# We allow C++ files, because the makefile rules we generate are +# sufficient to compile them. However, some low-level kernel hacking +# will be needed to actually use C++ in OS/161. +# + +awk < $CONFTMP.files ' + /\.cc$/ { next; } + /\.cpp$/ { next; } + /\.C$/ { next; } + /\.c$/ { next; } + #/\.l$/ { next; } # will require some makefile hacking to make work + #/\.y$/ { next; } # will require some makefile hacking to make work + /\.S$/ { next; } + /\.o$/ { next; } + { + printf "\n%s: Unrecognized source file type\n", $1; + exit(1); + } +' || exit 1; + +# +# Check for files with the same basename. +# +awk < $CONFTMP.files ' + { + path = $3; + base = path; + sub("^.*/", "", base); + sub("\\.[^\\.]*$", "", base); + if (seen[base]) { + msg = sprintf("%s: object file name %s.o conflicts with %s", + path, base, seen[base]); + printf "\n%s\n", msg; + failed = 1; + } + seen[base] = path; + } + END { + if (failed) { + exit(1); + } + } +' || exit 1 + +# +# Do it. +# Generate a make rule for each file. +# + +sort < $CONFTMP.files | awk ' + BEGIN { + printf "# Automatically generated by config; do not edit\n"; + } + + { + platform = $1; + machine = $2; + file = $3; + + # get basename + basename = file; + sub(".*/", "", basename); + + # get extension + ext = basename; + sub(".*\\.", "", ext); + sub("\\.[^\\.]*$", "", basename); + + if (file ~ "^\\.\\./") { + sub("^...", "", file); + path = "$(TOP)/" file; + } + else { + path = "$(KTOP)/" file; + } + + # + # For now a file cannot be both platform-dependent and + # machine-dependent, so this sequence of tests is enough. + # + if (platform != "*") { + printf "SRCS.PLATFORM.%s+=%s\n", platform, path; + } + else if (machine != "*") { + printf "SRCS.MACHINE.%s+=%s\n", machine, path; + } + else { + printf "SRCS+=%s\n", path; + } + } +' > $COMPILEDIR/files.mk + +rm -f $CONFTMP.files + +echo -n ' files.mk' + +######################################## +# +# 8. (reserved) +# + +######################################## +# +# 9. Generate Makefile +# + +( + echo "# Automatically generated by config; do not edit." + echo "#" + echo + echo '# Top of the kernel tree' + echo 'KTOP=../..' + echo '# Top of the whole tree' + echo 'TOP=$(KTOP)/..' + + echo '# Debug vs. optimize' + awk < $CONFTMP ' + # Default: optimize. + BEGIN { debugflags="-O2"; } + $1=="debug" { + debugflags="-g -Og"; + } + $1=="debugonly" { + debugflags="-g"; + } + + END { + printf "KDEBUG=%s\n", debugflags; + } + ' + echo '# Name of the kernel config file' + echo "CONFNAME=$CONFNAME" + echo + echo '.include "$(TOP)/mk/os161.config.mk"' + echo '.include "files.mk"' + echo '.include "$(TOP)/mk/os161.kernel.mk"' + +) > $COMPILEDIR/Makefile || exit 1 + +echo -n ' Makefile' + +######################################## +# +# 10. (reserved) +# + +######################################## +# +# 11. Process attachment list. +# Generate autoconf.[ch]. +# + +ACHREAL=$COMPILEDIR/autoconf.h +ACH=$COMPILEDIR/autoconf.h.new +ACC=$COMPILEDIR/autoconf.c + +echo '/* Automatically generated; do not edit */' > $ACH +echo '/* Automatically generated; do not edit */' > $ACC + +echo '#ifndef _AUTOCONF_H_' >> $ACH +echo '#define _AUTOCONF_H_' >> $ACH + +# +# first, declare struct foo_softc for all devices foo. +# + +echo >> $ACH +awk < $CONFTMP.attach '{ printf "struct %s_softc;\n", $2 }' >> $ACH + +# +# second, declare the autoconf_foo functions for unattached devices. +# +# The autoconf_foo functions for attached devices are file-static +# in autoconf.c. +# + +echo >> $ACH +awk < $CONFTMP.attach '$1=="noattach" { print $2 }' | sort -u | awk ' + { + printf "void autoconf_%s(struct %s_softc *dev, int unit);\n", $1, $1; + } +' >> $ACH + +# +# third, declare the attach functions. +# + +echo >> $ACH +awk < $CONFTMP.attach ' + $1=="attach" { + dev = $2; + bus = $5; + f = sprintf("struct %s_softc *attach_%s_to_%s", dev, dev, bus); + printf "%s(int devunit, struct %s_softc *bus);\n", f, bus; + } + $1=="pseudo" { + dev = $2; + printf "struct %s_softc *pseudoattach_%s(int devunit);\n", dev, dev; + } +' >> $ACH + +# +# fourth, declare the config functions. +# + +echo >> $ACH +awk < $CONFTMP.attach ' + $1=="attach" { + dev = $2; + printf "int config_%s(struct %s_softc *dev, int unit);\n", dev, dev; + } +' >> $ACH + +# +# Declare pseudoconfig() +# +echo >> $ACH +echo 'void pseudoconfig(void);' >> $ACH +echo >> $ACH + +# +# Done with the header file. +# +echo '#endif /* _AUTOCONF_H_ */' >> $ACH + +# +# Avoid changing the actual autoconf.h if it's not different, so as to +# reduce unnecessary recompiles. +# + +if diff $ACHREAL $ACH >/dev/null 2>&1; then + rm -f $ACH # unchanged +else + mv -f $ACH $ACHREAL # it changed +fi + +echo -n ' autoconf.h' + +# +# now, autoconf.c +# + +echo '#include ' >> $ACC +echo '#include ' >> $ACC +echo '#include "autoconf.h"' >> $ACC + +# +# first, declare the static autoconf_foo functions and the nextunit_foo vars +# +echo >> $ACC +awk < $CONFTMP.attach '$1=="attach" || $1=="pseudo" { print $2 }' | sort -u |\ + awk ' + { + printf "static void autoconf_%s(struct %s_softc *, int);\n", $1, $1; + } +' >> $ACC +awk < $CONFTMP.attach '$1=="attach" { print $2 }' | sort -u | awk ' + { + printf "static int nextunit_%s;\n", $1; + } +' >> $ACC +echo >> $ACC + +# +# Now generate the tryattach_ functions. +# + +awk < $CONFTMP.attach ' + $1=="attach" { + dev = $2; + bus = $5; + printf "static\n"; + printf "int\n"; + printf "tryattach_%s_to_%s", dev, bus; + printf "(int devunit, struct %s_softc *bus, int busunit)\n", bus; + printf "{\n"; + printf "\tstruct %s_softc *dev;\n", dev; + printf "\tint result;\n", dev; + printf "\n"; + printf "\tdev = attach_%s_to_%s(devunit, bus);\n", dev, bus; + printf "\tif (dev==NULL) {\n"; + printf "\t\treturn -1;\n"; + printf "\t}\n"; + printf "\tkprintf(\"%s%%d at %s%%d\", devunit, busunit);\n", dev, bus; + printf "\tresult = config_%s(dev, devunit);\n", dev; + printf "\tif (result != 0) {\n"; + printf "\t\tkprintf(\": %%s\\n\", strerror(result));\n"; + # Note: we leak the device softc instead of trying + # to clean it up. + printf "\t\t/* should really clean up dev */\n"; + printf "\t\treturn result;\n"; + printf "\t}\n"; + printf "\tkprintf(\"\\n\");\n"; + printf "\tnextunit_%s = devunit+1;\n", dev; + printf "\tautoconf_%s(dev, devunit);\n", dev; + printf "\treturn 0;\n"; + printf "}\n"; + printf "\n"; + } +' >> $ACC +echo >> $ACC + + +# +# Now comes the tricky part, actually writing those autoconf +# functions. We need one for every device. In each one, there needs +# to be a probe section for each line in $CONFTMP.attach in which that +# device appears on the *right hand* (bus) side. +# + +awk < $CONFTMP.attach ' + BEGIN { nlines=0; npseudo=0; } + $1=="attach" { + devs[nlines] = $2; + devunits[nlines] = $3; + buses[nlines] = $5; + busunits[nlines] = $6; + alldevs[$2] = 1; + nlines++; + } + $1=="noattach" { + alldevs[$2] = 0; + } + $1=="pseudo" { + alldevs[$2] = 0; + pseudodevs[npseudo] = $2; + pseudounits[npseudo] = $3; + npseudo++; + } + + function genprobe(dev, devunit, bus, busunit) { + + tryfunc = sprintf("tryattach_%s_to_%s", dev, bus); + + if (busunit!="*") { + printf "\tif (busunit==%d) {\n", busunit; + } + else { + printf "\t{\n"; + } + + if (devunit!="*") { + printf "\t\tif (nextunit_%s <= %d) {\n", dev, devunit; + printf "\t\t\t%s(%d, bus, busunit);\n", tryfunc, devunit; + printf "\t\t}\n"; + } + else { + printf "\t\tint result, devunit=nextunit_%s;\n", dev; + printf "\t\tdo {\n"; + printf "\t\t\tresult = %s(devunit, bus, busunit);\n", tryfunc; + printf "\t\t\tdevunit++;\n"; + printf "\t\t} while (result==0);\n"; + } + + printf "\t}\n"; + } + + END { + for (bus in alldevs) { + softc = sprintf("struct %s_softc", bus); + + if (alldevs[bus]) printf "static\n"; + printf "void\n"; + printf "autoconf_%s(%s *bus, int busunit)\n", bus, softc; + printf "{\n"; + printf "\t(void)bus; (void)busunit;\n"; + + for (i=0; i> $ACC + +echo -n ' autoconf.c' + +rm -f $CONFTMP $CONFTMP.attach + +######################################## +# +# Done. +# + +echo +echo "Configuration in ../compile/$CONFNAME done" +echo "Remember to make depend" diff --git a/kern/conf/newvers.sh b/kern/conf/newvers.sh new file mode 100755 index 0000000..c550efd --- /dev/null +++ b/kern/conf/newvers.sh @@ -0,0 +1,67 @@ +#!/bin/sh +# +# newvers.sh - increment build number in current directory (a build directory) +# and emit vers.c. +# The build number is kept in the file "version". +# +# Usage: newvers.sh CONFIGNAME + +# +# Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 +# The President and Fellows of Harvard College. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +if [ ! -f autoconf.c ]; then + # + # If there's no file autoconf.c, we are in the wrong place. + # + echo "$0: Not in a kernel build directory" + exit 1 +fi + +if [ "x$1" = x ]; then + echo "Usage: $0 CONFIGNAME" + exit 1 +fi + +CONFIG="$1" + +# +# Get and increment the version number +# + +VERS=`cat version 2>/dev/null || echo 0` +VERS=`expr $VERS + 1` +echo "$VERS" > version + +# +# Write vers.c +# + +echo '/* This file is automatically generated. Edits will be lost.*/' > vers.c +echo "const int buildversion = $VERS;" >> vers.c +echo 'const char buildconfig[] = "'"$CONFIG"'";' >> vers.c diff --git a/kern/dev/generic/beep.c b/kern/dev/generic/beep.c new file mode 100644 index 0000000..38d7aa9 --- /dev/null +++ b/kern/dev/generic/beep.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include "autoconf.h" + +/* + * Machine-independent generic beep "device". + * + * Basically, all we do is remember something that can be used for + * beeping, and provide the beep() function to the rest of the kernel. + * + * The kernel config mechanism can be used to explicitly choose which + * of the available beeping devices to use, if more than one is + * available. + */ + +static struct beep_softc *the_beep = NULL; + +int +config_beep(struct beep_softc *bs, int unit) +{ + /* We use only the first beep device. */ + if (unit!=0) { + return ENODEV; + } + + KASSERT(the_beep==NULL); + the_beep = bs; + return 0; +} + +void +beep(void) +{ + if (the_beep!=NULL) { + the_beep->bs_beep(the_beep->bs_devdata); + } + else { + kprintf("beep: Warning: no beep device\n"); + } +} diff --git a/kern/dev/generic/beep.h b/kern/dev/generic/beep.h new file mode 100644 index 0000000..eff3afa --- /dev/null +++ b/kern/dev/generic/beep.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _GENERIC_BEEP_H_ +#define _GENERIC_BEEP_H_ + +/* + * The device info for the generic MI beep device - a function + * to call and a context pointer for it. + */ + +struct beep_softc { + void *bs_devdata; + void (*bs_beep)(void *devdata); +}; + +#endif /* _GENERIC_BEEP_H_ */ diff --git a/kern/dev/generic/console.c b/kern/dev/generic/console.c new file mode 100644 index 0000000..ff0d771 --- /dev/null +++ b/kern/dev/generic/console.c @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Machine (and hardware) independent console driver. + * + * We expose a simple interface to the rest of the kernel: "putch" to + * print a character, "getch" to read one. + * + * As long as the device we're connected to does, we allow printing in + * an interrupt handler or with interrupts off (by polling), + * transparently to the caller. Note that getch by polling is not + * supported, although such support could be added without undue + * difficulty. + * + * Note that nothing happens until we have a device to write to. A + * buffer of size DELAYBUFSIZE is used to hold output that is + * generated before this point. This means that (1) using kprintf for + * debugging problems that occur early in initialization is awkward, + * and (2) if the system crashes before we find a console, no output + * at all may appear. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "autoconf.h" + +/* + * The console device. + */ +static struct con_softc *the_console = NULL; + +/* + * Lock so user I/Os are atomic. + * We use two locks so readers waiting for input don't lock out writers. + */ +static struct lock *con_userlock_read = NULL; +static struct lock *con_userlock_write = NULL; + +////////////////////////////////////////////////// + +/* + * This is for accumulating characters printed before the + * console is set up. Upon console setup they are dumped + * to the actual console; thenceforth this space is unused. + */ +#define DELAYBUFSIZE 1024 +static char delayed_outbuf[DELAYBUFSIZE]; +static size_t delayed_outbuf_pos=0; + +static +void +putch_delayed(int ch) +{ + /* + * No synchronization needed: called only during system startup + * by main thread. + */ + + KASSERT(delayed_outbuf_pos < sizeof(delayed_outbuf)); + delayed_outbuf[delayed_outbuf_pos++] = ch; +} + +static +void +flush_delay_buf(void) +{ + size_t i; + for (i=0; ics_sendpolled(cs->cs_devdata, ch); +} + +////////////////////////////////////////////////// + +/* + * Print a character, using interrupts to wait for I/O completion. + */ +static +void +putch_intr(struct con_softc *cs, int ch) +{ + P(cs->cs_wsem); + cs->cs_send(cs->cs_devdata, ch); +} + +/* + * Read a character, using interrupts to wait for I/O completion. + */ +static +int +getch_intr(struct con_softc *cs) +{ + unsigned char ret; + + P(cs->cs_rsem); + ret = cs->cs_gotchars[cs->cs_gotchars_tail]; + cs->cs_gotchars_tail = + (cs->cs_gotchars_tail + 1) % CONSOLE_INPUT_BUFFER_SIZE; + return ret; +} + +/* + * Called from underlying device when a read-ready interrupt occurs. + * + * Note: if gotchars_head == gotchars_tail, the buffer is empty. Thus + * if gotchars_head+1 == gotchars_tail, the buffer is full. A slightly + * tidier way to implement this check (that avoids wasting a slot, + * too) would be with a second semaphore used with a nonblocking P, + * but we don't have that in OS/161. + */ +void +con_input(void *vcs, int ch) +{ + struct con_softc *cs = vcs; + unsigned nexthead; + + nexthead = (cs->cs_gotchars_head + 1) % CONSOLE_INPUT_BUFFER_SIZE; + if (nexthead == cs->cs_gotchars_tail) { + /* overflow; drop character */ + return; + } + + cs->cs_gotchars[cs->cs_gotchars_head] = ch; + cs->cs_gotchars_head = nexthead; + + V(cs->cs_rsem); +} + +/* + * Called from underlying device when a write-done interrupt occurs. + */ +void +con_start(void *vcs) +{ + struct con_softc *cs = vcs; + + V(cs->cs_wsem); +} + +////////////////////////////////////////////////// + +/* + * Exported interface. + * + * Warning: putch must work even in an interrupt handler or with + * interrupts disabled, and before the console is probed. getch need + * not, and does not. + */ + +void +putch(int ch) +{ + struct con_softc *cs = the_console; + + if (cs==NULL) { + putch_delayed(ch); + } + else if (curthread->t_in_interrupt || + curthread->t_curspl > 0 || + curcpu->c_spinlocks > 0) { + putch_polled(cs, ch); + } + else { + putch_intr(cs, ch); + } +} + +int +getch(void) +{ + struct con_softc *cs = the_console; + KASSERT(cs != NULL); + KASSERT(!curthread->t_in_interrupt && curthread->t_iplhigh_count == 0); + + return getch_intr(cs); +} + +//////////////////////////////////////////////////////////// + +/* + * VFS interface functions + */ + +static +int +con_eachopen(struct device *dev, int openflags) +{ + (void)dev; + (void)openflags; + return 0; +} + +static +int +con_io(struct device *dev, struct uio *uio) +{ + int result; + char ch; + struct lock *lk; + + (void)dev; // unused + + if (uio->uio_rw==UIO_READ) { + lk = con_userlock_read; + } + else { + lk = con_userlock_write; + } + + KASSERT(lk != NULL); + lock_acquire(lk); + + while (uio->uio_resid > 0) { + if (uio->uio_rw==UIO_READ) { + ch = getch(); + if (ch=='\r') { + ch = '\n'; + } + result = uiomove(&ch, 1, uio); + if (result) { + lock_release(lk); + return result; + } + if (ch=='\n') { + break; + } + } + else { + result = uiomove(&ch, 1, uio); + if (result) { + lock_release(lk); + return result; + } + if (ch=='\n') { + putch('\r'); + } + putch(ch); + } + } + lock_release(lk); + return 0; +} + +static +int +con_ioctl(struct device *dev, int op, userptr_t data) +{ + /* No ioctls. */ + (void)dev; + (void)op; + (void)data; + return EINVAL; +} + +static const struct device_ops console_devops = { + .devop_eachopen = con_eachopen, + .devop_io = con_io, + .devop_ioctl = con_ioctl, +}; + +static +int +attach_console_to_vfs(struct con_softc *cs) +{ + struct device *dev; + int result; + + dev = kmalloc(sizeof(*dev)); + if (dev==NULL) { + return ENOMEM; + } + + dev->d_ops = &console_devops; + dev->d_blocks = 0; + dev->d_blocksize = 1; + dev->d_data = cs; + + result = vfs_adddev("con", dev, 0); + if (result) { + kfree(dev); + return result; + } + + return 0; +} + +//////////////////////////////////////////////////////////// + +/* + * Config routine called by autoconf.c after we are attached to something. + */ + +int +config_con(struct con_softc *cs, int unit) +{ + struct semaphore *rsem, *wsem; + struct lock *rlk, *wlk; + + /* + * Only allow one system console. + * Further devices that could be the system console are ignored. + * + * Do not hardwire the console to be "con1" instead of "con0", + * or these asserts will go off. + */ + if (unit>0) { + KASSERT(the_console!=NULL); + return ENODEV; + } + KASSERT(the_console==NULL); + + rsem = sem_create("console read", 0); + if (rsem == NULL) { + return ENOMEM; + } + wsem = sem_create("console write", 1); + if (wsem == NULL) { + sem_destroy(rsem); + return ENOMEM; + } + rlk = lock_create("console-lock-read"); + if (rlk == NULL) { + sem_destroy(rsem); + sem_destroy(wsem); + return ENOMEM; + } + wlk = lock_create("console-lock-write"); + if (wlk == NULL) { + lock_destroy(rlk); + sem_destroy(rsem); + sem_destroy(wsem); + return ENOMEM; + } + + cs->cs_rsem = rsem; + cs->cs_wsem = wsem; + cs->cs_gotchars_head = 0; + cs->cs_gotchars_tail = 0; + + the_console = cs; + con_userlock_read = rlk; + con_userlock_write = wlk; + + flush_delay_buf(); + + return attach_console_to_vfs(cs); +} diff --git a/kern/dev/generic/console.h b/kern/dev/generic/console.h new file mode 100644 index 0000000..0d7f4bd --- /dev/null +++ b/kern/dev/generic/console.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _GENERIC_CONSOLE_H_ +#define _GENERIC_CONSOLE_H_ + +/* + * Device data for the hardware-independent system console. + * + * devdata, send, and sendpolled are provided by the underlying + * device, and are to be initialized by the attach routine. + */ + +#define CONSOLE_INPUT_BUFFER_SIZE 32 + +struct con_softc { + /* initialized by attach routine */ + void *cs_devdata; + void (*cs_send)(void *devdata, int ch); + void (*cs_sendpolled)(void *devdata, int ch); + + /* initialized by config routine */ + struct semaphore *cs_rsem; + struct semaphore *cs_wsem; + unsigned char cs_gotchars[CONSOLE_INPUT_BUFFER_SIZE]; + unsigned cs_gotchars_head; /* next slot to put a char in */ + unsigned cs_gotchars_tail; /* next slot to take a char out */ +}; + +/* + * Functions called by lower-level drivers + */ +void con_input(/*struct con_softc*/ void *cs, int ch); +void con_start(/*struct con_softc*/ void *cs); + +/* + * Functions called by higher-level code + * + * putch/getch - see + */ + +#endif /* _GENERIC_CONSOLE_H_ */ diff --git a/kern/dev/generic/random.c b/kern/dev/generic/random.c new file mode 100644 index 0000000..3caf8c0 --- /dev/null +++ b/kern/dev/generic/random.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "autoconf.h" + +/* + * Machine-independent generic randomness device. + * + * Remembers something that's a random source, and provides random() + * and randmax() to the rest of the kernel. + * + * The kernel config mechanism can be used to explicitly choose which + * of the available random sources to use, if more than one is + * available. + */ + +static struct random_softc *the_random = NULL; + +/* + * VFS device functions. + * open: allow reading only. + */ +static +int +randeachopen(struct device *dev, int openflags) +{ + (void)dev; + + if (openflags != O_RDONLY) { + return EIO; + } + + return 0; +} + +/* + * VFS I/O function. Hand off to implementation. + */ +static +int +randio(struct device *dev, struct uio *uio) +{ + struct random_softc *rs = dev->d_data; + + if (uio->uio_rw != UIO_READ) { + return EIO; + } + + return rs->rs_read(rs->rs_devdata, uio); +} + +/* + * VFS ioctl function. + */ +static +int +randioctl(struct device *dev, int op, userptr_t data) +{ + /* + * We don't support any ioctls. + */ + (void)dev; + (void)op; + (void)data; + return EIOCTL; +} + +static const struct device_ops random_devops = { + .devop_eachopen = randeachopen, + .devop_io = randio, + .devop_ioctl = randioctl, +}; + +/* + * Config function. + */ +int +config_random(struct random_softc *rs, int unit) +{ + int result; + + /* We use only the first random device. */ + if (unit!=0) { + return ENODEV; + } + + KASSERT(the_random==NULL); + the_random = rs; + + rs->rs_dev.d_ops = &random_devops; + rs->rs_dev.d_blocks = 0; + rs->rs_dev.d_blocksize = 1; + rs->rs_dev.d_data = rs; + + /* Add the VFS device structure to the VFS device list. */ + result = vfs_adddev("random", &rs->rs_dev, 0); + if (result) { + return result; + } + + return 0; +} + + +/* + * Random number functions exported to the rest of the kernel. + */ + +uint32_t +random(void) +{ + if (the_random==NULL) { + panic("No random device\n"); + } + return the_random->rs_random(the_random->rs_devdata); +} + +uint32_t +randmax(void) +{ + if (the_random==NULL) { + panic("No random device\n"); + } + return the_random->rs_randmax(the_random->rs_devdata); +} diff --git a/kern/dev/generic/random.h b/kern/dev/generic/random.h new file mode 100644 index 0000000..d23336c --- /dev/null +++ b/kern/dev/generic/random.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _GENERIC_RANDOM_H_ +#define _GENERIC_RANDOM_H_ + +#include +struct uio; + +struct random_softc { + /* Initialized by lower-level attach routine */ + void *rs_devdata; + uint32_t (*rs_random)(void *devdata); + uint32_t (*rs_randmax)(void *devdata); + int (*rs_read)(void *devdata, struct uio *uio); + + struct device rs_dev; +}; + +#endif /* _GENERIC_RANDOM_H_ */ diff --git a/kern/dev/generic/rtclock.c b/kern/dev/generic/rtclock.c new file mode 100644 index 0000000..ab1cd68 --- /dev/null +++ b/kern/dev/generic/rtclock.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Machine-independent generic clock "device". + * + * Basically, all we do is remember something that can be used for + * handling requests for the current time, and provide the gettime() + * function to the rest of the kernel. + * + * The kernel config mechanism can be used to explicitly choose which + * of the available clocks to use, if more than one is available. + * + * The system will panic if gettime() is called and there is no clock. + */ + +#include +#include +#include +#include +#include +#include "autoconf.h" + +static struct rtclock_softc *the_clock = NULL; + +int +config_rtclock(struct rtclock_softc *rtc, int unit) +{ + /* We use only the first clock device. */ + if (unit!=0) { + return ENODEV; + } + + KASSERT(the_clock==NULL); + the_clock = rtc; + return 0; +} + +void +gettime(struct timespec *ts) +{ + KASSERT(the_clock!=NULL); + the_clock->rtc_gettime(the_clock->rtc_devdata, ts); +} diff --git a/kern/dev/generic/rtclock.h b/kern/dev/generic/rtclock.h new file mode 100644 index 0000000..98fc63a --- /dev/null +++ b/kern/dev/generic/rtclock.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _GENERIC_RTCLOCK_H_ +#define _GENERIC_RTCLOCK_H_ + +/* + * The device info for the generic MI clock device - a function + * to call and a context pointer for it. + */ + +struct timespec; + +struct rtclock_softc { + void *rtc_devdata; + void (*rtc_gettime)(void *devdata, struct timespec *); +}; + +#endif /* _GENERIC_RTCLOCK_H_ */ diff --git a/kern/dev/lamebus/beep_ltimer.c b/kern/dev/lamebus/beep_ltimer.c new file mode 100644 index 0000000..5115d30 --- /dev/null +++ b/kern/dev/lamebus/beep_ltimer.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Attachment code for having the generic beep device use the LAMEbus + * ltimer device for beeping. + */ + +#include +#include +#include +#include +#include "autoconf.h" + +struct beep_softc * +attach_beep_to_ltimer(int beepno, struct ltimer_softc *ls) +{ + struct beep_softc *bs = kmalloc(sizeof(struct beep_softc)); + if (bs==NULL) { + return NULL; + } + + (void)beepno; // unused + + bs->bs_devdata = ls; + bs->bs_beep = ltimer_beep; + + return bs; +} diff --git a/kern/dev/lamebus/con_lscreen.c b/kern/dev/lamebus/con_lscreen.c new file mode 100644 index 0000000..e3bc68e --- /dev/null +++ b/kern/dev/lamebus/con_lscreen.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Attachment code for having the generic console device use the LAMEbus + * screen device. + */ + +#include +#include +#include +#include +#include "autoconf.h" + +struct con_softc * +attach_con_to_lscreen(int consno, struct lscreen_softc *ls) +{ + struct con_softc *cs = kmalloc(sizeof(struct con_softc)); + if (cs==NULL) { + return NULL; + } + + cs->cs_devdata = ls; + cs->cs_send = lscreen_write; + cs->cs_sendpolled = lscreen_write; + + ls->ls_devdata = cs; + ls->ls_start = con_start; + ls->ls_input = con_input; + + return cs; +} + diff --git a/kern/dev/lamebus/con_lser.c b/kern/dev/lamebus/con_lser.c new file mode 100644 index 0000000..c5fdb7a --- /dev/null +++ b/kern/dev/lamebus/con_lser.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Attachment code for having the generic console device use the LAMEbus + * serial device. + */ + +#include +#include +#include +#include +#include "autoconf.h" + +struct con_softc * +attach_con_to_lser(int consno, struct lser_softc *ls) +{ + struct con_softc *cs = kmalloc(sizeof(struct con_softc)); + if (cs==NULL) { + return NULL; + } + + (void)consno; // unused + + cs->cs_devdata = ls; + cs->cs_send = lser_write; + cs->cs_sendpolled = lser_writepolled; + + ls->ls_devdata = cs; + ls->ls_start = con_start; + ls->ls_input = con_input; + + return cs; +} + diff --git a/kern/dev/lamebus/conf.lamebus b/kern/dev/lamebus/conf.lamebus new file mode 100644 index 0000000..53adce5 --- /dev/null +++ b/kern/dev/lamebus/conf.lamebus @@ -0,0 +1,57 @@ +# +# Kernel config definitions for LAMEbus devices. +# +# See conf/conf.kern for more information. +# + +# System main bus. +defdevice lamebus dev/lamebus/lamebus.c + +# Timer. +defdevice ltimer dev/lamebus/ltimer.c +defattach ltimer* lamebus* dev/lamebus/ltimer_att.c + +# Random. +defdevice lrandom dev/lamebus/lrandom.c +defattach lrandom* lamebus* dev/lamebus/lrandom_att.c + +# Disk. +defdevice lhd dev/lamebus/lhd.c +defattach lhd* lamebus* dev/lamebus/lhd_att.c + +# Serial port. +defdevice lser dev/lamebus/lser.c +defattach lser* lamebus* dev/lamebus/lser_att.c + +# Text screen. +defdevice lscreen dev/lamebus/lscreen.c +defattach lscreen* lamebus* dev/lamebus/lscreen_att.c + +# Network interface. +defdevice lnet dev/lamebus/lnet.c +defattach lnet* lamebus* dev/lamebus/lnet_att.c + +# Trace control device. +defdevice ltrace dev/lamebus/ltrace.c +defattach ltrace* lamebus* dev/lamebus/ltrace_att.c + +# Emulator passthrough filesystem. +defdevice emu dev/lamebus/emu.c +defattach emu* lamebus* dev/lamebus/emu_att.c + +# +# Attachments to generic interface devices +# + +# Consoles. +defattach con0 lser* dev/lamebus/con_lser.c +defattach con0 lscreen* dev/lamebus/con_lscreen.c + +# Beeper. +defattach beep* ltimer* dev/lamebus/beep_ltimer.c + +# Clock. +defattach rtclock* ltimer* dev/lamebus/rtclock_ltimer.c + +# Random. +defattach random0 lrandom* dev/lamebus/random_lrandom.c diff --git a/kern/dev/lamebus/emu.c b/kern/dev/lamebus/emu.c new file mode 100644 index 0000000..676fb6f --- /dev/null +++ b/kern/dev/lamebus/emu.c @@ -0,0 +1,1357 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Emulator passthrough filesystem. + * + * The idea is that this appears as a filesystem in the VFS layer, and + * passes VFS operations through a somewhat complicated "hardware" + * interface to some simulated "hardware" in System/161 that accesses + * the filesystem System/161 is running in. + * + * This makes it unnecessary to copy the system files to the simulated + * disk, although we recommend doing so and trying running without this + * device as part of testing your filesystem. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "autoconf.h" + +/* Register offsets */ +#define REG_HANDLE 0 +#define REG_OFFSET 4 +#define REG_IOLEN 8 +#define REG_OPER 12 +#define REG_RESULT 16 + +/* I/O buffer offset */ +#define EMU_BUFFER 32768 + +/* Operation codes for REG_OPER */ +#define EMU_OP_OPEN 1 +#define EMU_OP_CREATE 2 +#define EMU_OP_EXCLCREATE 3 +#define EMU_OP_CLOSE 4 +#define EMU_OP_READ 5 +#define EMU_OP_READDIR 6 +#define EMU_OP_WRITE 7 +#define EMU_OP_GETSIZE 8 +#define EMU_OP_TRUNC 9 + +/* Result codes for REG_RESULT */ +#define EMU_RES_SUCCESS 1 +#define EMU_RES_BADHANDLE 2 +#define EMU_RES_BADOP 3 +#define EMU_RES_BADPATH 4 +#define EMU_RES_BADSIZE 5 +#define EMU_RES_EXISTS 6 +#define EMU_RES_ISDIR 7 +#define EMU_RES_MEDIA 8 +#define EMU_RES_NOHANDLES 9 +#define EMU_RES_NOSPACE 10 +#define EMU_RES_NOTDIR 11 +#define EMU_RES_UNKNOWN 12 +#define EMU_RES_UNSUPP 13 + +//////////////////////////////////////////////////////////// +// +// Hardware ops +// + +/* + * Shortcut for reading a register + */ +static +inline +uint32_t +emu_rreg(struct emu_softc *sc, uint32_t reg) +{ + return bus_read_register(sc->e_busdata, sc->e_buspos, reg); +} + +/* + * Shortcut for writing a register + */ +static +inline +void +emu_wreg(struct emu_softc *sc, uint32_t reg, uint32_t val) +{ + bus_write_register(sc->e_busdata, sc->e_buspos, reg, val); +} + +/* + * Called by the underlying bus code when an interrupt happens + */ +void +emu_irq(void *dev) +{ + struct emu_softc *sc = dev; + + sc->e_result = emu_rreg(sc, REG_RESULT); + emu_wreg(sc, REG_RESULT, 0); + + V(sc->e_sem); +} + +/* + * Convert the error codes reported by the "hardware" to errnos. + * Or, on cases that indicate a programming error in emu.c, panic. + */ +static +uint32_t +translate_err(struct emu_softc *sc, uint32_t code) +{ + switch (code) { + case EMU_RES_SUCCESS: return 0; + case EMU_RES_BADHANDLE: + case EMU_RES_BADOP: + case EMU_RES_BADSIZE: + panic("emu%d: got fatal result code %d\n", sc->e_unit, code); + case EMU_RES_BADPATH: return ENOENT; + case EMU_RES_EXISTS: return EEXIST; + case EMU_RES_ISDIR: return EISDIR; + case EMU_RES_MEDIA: return EIO; + case EMU_RES_NOHANDLES: return ENFILE; + case EMU_RES_NOSPACE: return ENOSPC; + case EMU_RES_NOTDIR: return ENOTDIR; + case EMU_RES_UNKNOWN: return EIO; + case EMU_RES_UNSUPP: return ENOSYS; + } + kprintf("emu%d: Unknown result code %d\n", sc->e_unit, code); + return EAGAIN; +} + +/* + * Wait for an operation to complete, and return an errno for the result. + */ +static +int +emu_waitdone(struct emu_softc *sc) +{ + P(sc->e_sem); + return translate_err(sc, sc->e_result); +} + +/* + * Common file open routine (for both VOP_LOOKUP and VOP_CREATE). Not + * for VOP_EACHOPEN. At the hardware level, we need to "open" files in + * order to look at them, so by the time VOP_EACHOPEN is called the + * files are already open. + */ +static +int +emu_open(struct emu_softc *sc, uint32_t handle, const char *name, + bool create, bool excl, mode_t mode, + uint32_t *newhandle, int *newisdir) +{ + uint32_t op; + int result; + + if (strlen(name)+1 > EMU_MAXIO) { + return ENAMETOOLONG; + } + + if (create && excl) { + op = EMU_OP_EXCLCREATE; + } + else if (create) { + op = EMU_OP_CREATE; + } + else { + op = EMU_OP_OPEN; + } + + /* mode isn't supported (yet?) */ + (void)mode; + + lock_acquire(sc->e_lock); + + strcpy(sc->e_iobuf, name); + membar_store_store(); + emu_wreg(sc, REG_IOLEN, strlen(name)); + emu_wreg(sc, REG_HANDLE, handle); + emu_wreg(sc, REG_OPER, op); + result = emu_waitdone(sc); + + if (result==0) { + *newhandle = emu_rreg(sc, REG_HANDLE); + *newisdir = emu_rreg(sc, REG_IOLEN)>0; + } + + lock_release(sc->e_lock); + return result; +} + +/* + * Routine for closing a file we opened at the hardware level. + * This is not necessarily called at VOP_LASTCLOSE time; it's called + * at VOP_RECLAIM time. + */ +static +int +emu_close(struct emu_softc *sc, uint32_t handle) +{ + int result; + bool mine; + int retries = 0; + + mine = lock_do_i_hold(sc->e_lock); + if (!mine) { + lock_acquire(sc->e_lock); + } + + while (1) { + /* Retry operation up to 10 times */ + + emu_wreg(sc, REG_HANDLE, handle); + emu_wreg(sc, REG_OPER, EMU_OP_CLOSE); + result = emu_waitdone(sc); + + if (result==EIO && retries < 10) { + kprintf("emu%d: I/O error on close, retrying\n", + sc->e_unit); + retries++; + continue; + } + break; + } + + if (!mine) { + lock_release(sc->e_lock); + } + return result; +} + +/* + * Common code for read and readdir. + */ +static +int +emu_doread(struct emu_softc *sc, uint32_t handle, uint32_t len, + uint32_t op, struct uio *uio) +{ + int result; + + KASSERT(uio->uio_rw == UIO_READ); + + if (uio->uio_offset > (off_t)0xffffffff) { + /* beyond the largest size the file can have; generate EOF */ + return 0; + } + + lock_acquire(sc->e_lock); + + emu_wreg(sc, REG_HANDLE, handle); + emu_wreg(sc, REG_IOLEN, len); + emu_wreg(sc, REG_OFFSET, uio->uio_offset); + emu_wreg(sc, REG_OPER, op); + result = emu_waitdone(sc); + if (result) { + goto out; + } + + membar_load_load(); + result = uiomove(sc->e_iobuf, emu_rreg(sc, REG_IOLEN), uio); + + uio->uio_offset = emu_rreg(sc, REG_OFFSET); + + out: + lock_release(sc->e_lock); + return result; +} + +/* + * Read from a hardware-level file handle. + */ +static +int +emu_read(struct emu_softc *sc, uint32_t handle, uint32_t len, + struct uio *uio) +{ + return emu_doread(sc, handle, len, EMU_OP_READ, uio); +} + +/* + * Read a directory entry from a hardware-level file handle. + */ +static +int +emu_readdir(struct emu_softc *sc, uint32_t handle, uint32_t len, + struct uio *uio) +{ + return emu_doread(sc, handle, len, EMU_OP_READDIR, uio); +} + +/* + * Write to a hardware-level file handle. + */ +static +int +emu_write(struct emu_softc *sc, uint32_t handle, uint32_t len, + struct uio *uio) +{ + int result; + + KASSERT(uio->uio_rw == UIO_WRITE); + + if (uio->uio_offset > (off_t)0xffffffff) { + return EFBIG; + } + + lock_acquire(sc->e_lock); + + emu_wreg(sc, REG_HANDLE, handle); + emu_wreg(sc, REG_IOLEN, len); + emu_wreg(sc, REG_OFFSET, uio->uio_offset); + + result = uiomove(sc->e_iobuf, len, uio); + membar_store_store(); + if (result) { + goto out; + } + + emu_wreg(sc, REG_OPER, EMU_OP_WRITE); + result = emu_waitdone(sc); + + out: + lock_release(sc->e_lock); + return result; +} + +/* + * Get the file size associated with a hardware-level file handle. + */ +static +int +emu_getsize(struct emu_softc *sc, uint32_t handle, off_t *retval) +{ + int result; + + lock_acquire(sc->e_lock); + + emu_wreg(sc, REG_HANDLE, handle); + emu_wreg(sc, REG_OPER, EMU_OP_GETSIZE); + result = emu_waitdone(sc); + if (result==0) { + *retval = emu_rreg(sc, REG_IOLEN); + } + + lock_release(sc->e_lock); + return result; +} + +/* + * Truncate a hardware-level file handle. + */ +static +int +emu_trunc(struct emu_softc *sc, uint32_t handle, off_t len) +{ + int result; + + KASSERT(len >= 0); + + lock_acquire(sc->e_lock); + + emu_wreg(sc, REG_HANDLE, handle); + emu_wreg(sc, REG_IOLEN, len); + emu_wreg(sc, REG_OPER, EMU_OP_TRUNC); + result = emu_waitdone(sc); + + lock_release(sc->e_lock); + return result; +} + +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// +// vnode functions +// + +// at bottom of this section + +static int emufs_loadvnode(struct emufs_fs *ef, uint32_t handle, int isdir, + struct emufs_vnode **ret); + +/* + * VOP_EACHOPEN on files + */ +static +int +emufs_eachopen(struct vnode *v, int openflags) +{ + /* + * At this level we do not need to handle O_CREAT, O_EXCL, + * O_TRUNC, or O_APPEND. + * + * Any of O_RDONLY, O_WRONLY, and O_RDWR are valid, so we don't need + * to check that either. + */ + + (void)v; + (void)openflags; + + return 0; +} + +/* + * VOP_EACHOPEN on directories + */ +static +int +emufs_eachopendir(struct vnode *v, int openflags) +{ + switch (openflags & O_ACCMODE) { + case O_RDONLY: + break; + case O_WRONLY: + case O_RDWR: + default: + return EISDIR; + } + if (openflags & O_APPEND) { + return EISDIR; + } + + (void)v; + return 0; +} + +/* + * VOP_RECLAIM + * + * Reclaim should make an effort to returning errors other than EBUSY. + */ +static +int +emufs_reclaim(struct vnode *v) +{ + struct emufs_vnode *ev = v->vn_data; + struct emufs_fs *ef = v->vn_fs->fs_data; + unsigned ix, i, num; + int result; + + /* + * Need all of these locks, e_lock to protect the device, + * vfs_biglock to protect the fs-related material, and + * vn_countlock for the reference count. + */ + + vfs_biglock_acquire(); + lock_acquire(ef->ef_emu->e_lock); + spinlock_acquire(&ev->ev_v.vn_countlock); + + if (ev->ev_v.vn_refcount > 1) { + /* consume the reference VOP_DECREF passed us */ + ev->ev_v.vn_refcount--; + + spinlock_release(&ev->ev_v.vn_countlock); + lock_release(ef->ef_emu->e_lock); + vfs_biglock_release(); + return EBUSY; + } + KASSERT(ev->ev_v.vn_refcount == 1); + + /* + * Since we hold e_lock and are the last ref, nobody can increment + * the refcount, so we can release vn_countlock. + */ + spinlock_release(&ev->ev_v.vn_countlock); + + /* emu_close retries on I/O error */ + result = emu_close(ev->ev_emu, ev->ev_handle); + if (result) { + lock_release(ef->ef_emu->e_lock); + vfs_biglock_release(); + return result; + } + + num = vnodearray_num(ef->ef_vnodes); + ix = num; + for (i=0; ief_vnodes, i); + if (vx == v) { + ix = i; + break; + } + } + if (ix == num) { + panic("emu%d: reclaim vnode %u not in vnode pool\n", + ef->ef_emu->e_unit, ev->ev_handle); + } + + vnodearray_remove(ef->ef_vnodes, ix); + vnode_cleanup(&ev->ev_v); + + lock_release(ef->ef_emu->e_lock); + vfs_biglock_release(); + + kfree(ev); + return 0; +} + +/* + * VOP_READ + */ +static +int +emufs_read(struct vnode *v, struct uio *uio) +{ + struct emufs_vnode *ev = v->vn_data; + uint32_t amt; + size_t oldresid; + int result; + + KASSERT(uio->uio_rw==UIO_READ); + + while (uio->uio_resid > 0) { + amt = uio->uio_resid; + if (amt > EMU_MAXIO) { + amt = EMU_MAXIO; + } + + oldresid = uio->uio_resid; + + result = emu_read(ev->ev_emu, ev->ev_handle, amt, uio); + if (result) { + return result; + } + + if (uio->uio_resid == oldresid) { + /* nothing read - EOF */ + break; + } + } + + return 0; +} + +/* + * VOP_READDIR + */ +static +int +emufs_getdirentry(struct vnode *v, struct uio *uio) +{ + struct emufs_vnode *ev = v->vn_data; + uint32_t amt; + + KASSERT(uio->uio_rw==UIO_READ); + + amt = uio->uio_resid; + if (amt > EMU_MAXIO) { + amt = EMU_MAXIO; + } + + return emu_readdir(ev->ev_emu, ev->ev_handle, amt, uio); +} + +/* + * VOP_WRITE + */ +static +int +emufs_write(struct vnode *v, struct uio *uio) +{ + struct emufs_vnode *ev = v->vn_data; + uint32_t amt; + size_t oldresid; + int result; + + KASSERT(uio->uio_rw==UIO_WRITE); + + while (uio->uio_resid > 0) { + amt = uio->uio_resid; + if (amt > EMU_MAXIO) { + amt = EMU_MAXIO; + } + + oldresid = uio->uio_resid; + + result = emu_write(ev->ev_emu, ev->ev_handle, amt, uio); + if (result) { + return result; + } + + if (uio->uio_resid == oldresid) { + /* nothing written...? */ + break; + } + } + + return 0; +} + +/* + * VOP_IOCTL + */ +static +int +emufs_ioctl(struct vnode *v, int op, userptr_t data) +{ + /* + * No ioctls. + */ + + (void)v; + (void)op; + (void)data; + + return EINVAL; +} + +/* + * VOP_STAT + */ +static +int +emufs_stat(struct vnode *v, struct stat *statbuf) +{ + struct emufs_vnode *ev = v->vn_data; + int result; + + bzero(statbuf, sizeof(struct stat)); + + result = emu_getsize(ev->ev_emu, ev->ev_handle, &statbuf->st_size); + if (result) { + return result; + } + + result = VOP_GETTYPE(v, &statbuf->st_mode); + if (result) { + return result; + } + statbuf->st_mode |= 0644; /* possibly a lie */ + statbuf->st_nlink = 1; /* might be a lie, but doesn't matter much */ + statbuf->st_blocks = 0; /* almost certainly a lie */ + + return 0; +} + +/* + * VOP_GETTYPE for files + */ +static +int +emufs_file_gettype(struct vnode *v, uint32_t *result) +{ + (void)v; + *result = S_IFREG; + return 0; +} + +/* + * VOP_GETTYPE for directories + */ +static +int +emufs_dir_gettype(struct vnode *v, uint32_t *result) +{ + (void)v; + *result = S_IFDIR; + return 0; +} + +/* + * VOP_ISSEEKABLE + */ +static +bool +emufs_isseekable(struct vnode *v) +{ + (void)v; + return true; +} + +/* + * VOP_FSYNC + */ +static +int +emufs_fsync(struct vnode *v) +{ + (void)v; + return 0; +} + +/* + * VOP_TRUNCATE + */ +static +int +emufs_truncate(struct vnode *v, off_t len) +{ + struct emufs_vnode *ev = v->vn_data; + return emu_trunc(ev->ev_emu, ev->ev_handle, len); +} + +/* + * VOP_CREAT + */ +static +int +emufs_creat(struct vnode *dir, const char *name, bool excl, mode_t mode, + struct vnode **ret) +{ + struct emufs_vnode *ev = dir->vn_data; + struct emufs_fs *ef = dir->vn_fs->fs_data; + struct emufs_vnode *newguy; + uint32_t handle; + int result; + int isdir; + + result = emu_open(ev->ev_emu, ev->ev_handle, name, true, excl, mode, + &handle, &isdir); + if (result) { + return result; + } + + result = emufs_loadvnode(ef, handle, isdir, &newguy); + if (result) { + emu_close(ev->ev_emu, handle); + return result; + } + + *ret = &newguy->ev_v; + return 0; +} + +/* + * VOP_LOOKUP + */ +static +int +emufs_lookup(struct vnode *dir, char *pathname, struct vnode **ret) +{ + struct emufs_vnode *ev = dir->vn_data; + struct emufs_fs *ef = dir->vn_fs->fs_data; + struct emufs_vnode *newguy; + uint32_t handle; + int result; + int isdir; + + result = emu_open(ev->ev_emu, ev->ev_handle, pathname, false, false, 0, + &handle, &isdir); + if (result) { + return result; + } + + result = emufs_loadvnode(ef, handle, isdir, &newguy); + if (result) { + emu_close(ev->ev_emu, handle); + return result; + } + + *ret = &newguy->ev_v; + return 0; +} + +/* + * VOP_LOOKPARENT + */ +static +int +emufs_lookparent(struct vnode *dir, char *pathname, struct vnode **ret, + char *buf, size_t len) +{ + char *s; + + s = strrchr(pathname, '/'); + if (s==NULL) { + /* just a last component, no directory part */ + if (strlen(pathname)+1 > len) { + return ENAMETOOLONG; + } + VOP_INCREF(dir); + *ret = dir; + strcpy(buf, pathname); + return 0; + } + + *s = 0; + s++; + if (strlen(s)+1 > len) { + return ENAMETOOLONG; + } + strcpy(buf, s); + + return emufs_lookup(dir, pathname, ret); +} + +/* + * VOP_NAMEFILE + */ +static +int +emufs_namefile(struct vnode *v, struct uio *uio) +{ + struct emufs_vnode *ev = v->vn_data; + struct emufs_fs *ef = v->vn_fs->fs_data; + + if (ev == ef->ef_root) { + /* + * Root directory - name is empty string + */ + return 0; + } + + (void)uio; + + return ENOSYS; +} + +/* + * VOP_MMAP + */ +static +int +emufs_mmap(struct vnode *v) +{ + (void)v; + return ENOSYS; +} + +////////////////////////////// + +/* + * Bits not implemented at all on emufs + */ + +static +int +emufs_symlink(struct vnode *v, const char *contents, const char *name) +{ + (void)v; + (void)contents; + (void)name; + return ENOSYS; +} + +static +int +emufs_mkdir(struct vnode *v, const char *name, mode_t mode) +{ + (void)v; + (void)name; + (void)mode; + return ENOSYS; +} + +static +int +emufs_link(struct vnode *v, const char *name, struct vnode *target) +{ + (void)v; + (void)name; + (void)target; + return ENOSYS; +} + +static +int +emufs_remove(struct vnode *v, const char *name) +{ + (void)v; + (void)name; + return ENOSYS; +} + +static +int +emufs_rmdir(struct vnode *v, const char *name) +{ + (void)v; + (void)name; + return ENOSYS; +} + +static +int +emufs_rename(struct vnode *v1, const char *n1, + struct vnode *v2, const char *n2) +{ + (void)v1; + (void)n1; + (void)v2; + (void)n2; + return ENOSYS; +} + +////////////////////////////// + +/* + * Routines that fail + * + * It is kind of silly to write these out each with their particular + * arguments; however, portable C doesn't let you cast function + * pointers with different argument signatures even if the arguments + * are never used. + * + * The BSD approach (all vnode ops take a vnode pointer and a void + * pointer that's cast to a op-specific args structure) avoids this + * problem but is otherwise not very appealing. + */ + +static +int +emufs_void_op_isdir(struct vnode *v) +{ + (void)v; + return EISDIR; +} + +static +int +emufs_uio_op_isdir(struct vnode *v, struct uio *uio) +{ + (void)v; + (void)uio; + return EISDIR; +} + +static +int +emufs_uio_op_notdir(struct vnode *v, struct uio *uio) +{ + (void)v; + (void)uio; + return ENOTDIR; +} + +static +int +emufs_name_op_notdir(struct vnode *v, const char *name) +{ + (void)v; + (void)name; + return ENOTDIR; +} + +static +int +emufs_readlink_notlink(struct vnode *v, struct uio *uio) +{ + (void)v; + (void)uio; + return EINVAL; +} + +static +int +emufs_creat_notdir(struct vnode *v, const char *name, bool excl, mode_t mode, + struct vnode **retval) +{ + (void)v; + (void)name; + (void)excl; + (void)mode; + (void)retval; + return ENOTDIR; +} + +static +int +emufs_symlink_notdir(struct vnode *v, const char *contents, const char *name) +{ + (void)v; + (void)contents; + (void)name; + return ENOTDIR; +} + +static +int +emufs_mkdir_notdir(struct vnode *v, const char *name, mode_t mode) +{ + (void)v; + (void)name; + (void)mode; + return ENOTDIR; +} + +static +int +emufs_link_notdir(struct vnode *v, const char *name, struct vnode *target) +{ + (void)v; + (void)name; + (void)target; + return ENOTDIR; +} + +static +int +emufs_rename_notdir(struct vnode *v1, const char *n1, + struct vnode *v2, const char *n2) +{ + (void)v1; + (void)n1; + (void)v2; + (void)n2; + return ENOTDIR; +} + +static +int +emufs_lookup_notdir(struct vnode *v, char *pathname, struct vnode **result) +{ + (void)v; + (void)pathname; + (void)result; + return ENOTDIR; +} + +static +int +emufs_lookparent_notdir(struct vnode *v, char *pathname, struct vnode **result, + char *buf, size_t len) +{ + (void)v; + (void)pathname; + (void)result; + (void)buf; + (void)len; + return ENOTDIR; +} + + +static +int +emufs_truncate_isdir(struct vnode *v, off_t len) +{ + (void)v; + (void)len; + return ENOTDIR; +} + +////////////////////////////// + +/* + * Function table for emufs files. + */ +static const struct vnode_ops emufs_fileops = { + .vop_magic = VOP_MAGIC, /* mark this a valid vnode ops table */ + + .vop_eachopen = emufs_eachopen, + .vop_reclaim = emufs_reclaim, + + .vop_read = emufs_read, + .vop_readlink = emufs_readlink_notlink, + .vop_getdirentry = emufs_uio_op_notdir, + .vop_write = emufs_write, + .vop_ioctl = emufs_ioctl, + .vop_stat = emufs_stat, + .vop_gettype = emufs_file_gettype, + .vop_isseekable = emufs_isseekable, + .vop_fsync = emufs_fsync, + .vop_mmap = emufs_mmap, + .vop_truncate = emufs_truncate, + .vop_namefile = emufs_uio_op_notdir, + + .vop_creat = emufs_creat_notdir, + .vop_symlink = emufs_symlink_notdir, + .vop_mkdir = emufs_mkdir_notdir, + .vop_link = emufs_link_notdir, + .vop_remove = emufs_name_op_notdir, + .vop_rmdir = emufs_name_op_notdir, + .vop_rename = emufs_rename_notdir, + + .vop_lookup = emufs_lookup_notdir, + .vop_lookparent = emufs_lookparent_notdir, +}; + +/* + * Function table for emufs directories. + */ +static const struct vnode_ops emufs_dirops = { + .vop_magic = VOP_MAGIC, /* mark this a valid vnode ops table */ + + .vop_eachopen = emufs_eachopendir, + .vop_reclaim = emufs_reclaim, + + .vop_read = emufs_uio_op_isdir, + .vop_readlink = emufs_uio_op_isdir, + .vop_getdirentry = emufs_getdirentry, + .vop_write = emufs_uio_op_isdir, + .vop_ioctl = emufs_ioctl, + .vop_stat = emufs_stat, + .vop_gettype = emufs_dir_gettype, + .vop_isseekable = emufs_isseekable, + .vop_fsync = emufs_void_op_isdir, + .vop_mmap = emufs_void_op_isdir, + .vop_truncate = emufs_truncate_isdir, + .vop_namefile = emufs_namefile, + + .vop_creat = emufs_creat, + .vop_symlink = emufs_symlink, + .vop_mkdir = emufs_mkdir, + .vop_link = emufs_link, + .vop_remove = emufs_remove, + .vop_rmdir = emufs_rmdir, + .vop_rename = emufs_rename, + + .vop_lookup = emufs_lookup, + .vop_lookparent = emufs_lookparent, +}; + +/* + * Function to load a vnode into memory. + */ +static +int +emufs_loadvnode(struct emufs_fs *ef, uint32_t handle, int isdir, + struct emufs_vnode **ret) +{ + struct vnode *v; + struct emufs_vnode *ev; + unsigned i, num; + int result; + + vfs_biglock_acquire(); + lock_acquire(ef->ef_emu->e_lock); + + num = vnodearray_num(ef->ef_vnodes); + for (i=0; ief_vnodes, i); + ev = v->vn_data; + if (ev->ev_handle == handle) { + /* Found */ + + VOP_INCREF(&ev->ev_v); + + lock_release(ef->ef_emu->e_lock); + vfs_biglock_release(); + *ret = ev; + return 0; + } + } + + /* Didn't have one; create it */ + + ev = kmalloc(sizeof(struct emufs_vnode)); + if (ev==NULL) { + lock_release(ef->ef_emu->e_lock); + return ENOMEM; + } + + ev->ev_emu = ef->ef_emu; + ev->ev_handle = handle; + + result = vnode_init(&ev->ev_v, isdir ? &emufs_dirops : &emufs_fileops, + &ef->ef_fs, ev); + if (result) { + lock_release(ef->ef_emu->e_lock); + vfs_biglock_release(); + kfree(ev); + return result; + } + + result = vnodearray_add(ef->ef_vnodes, &ev->ev_v, NULL); + if (result) { + /* note: vnode_cleanup undoes vnode_init - it does not kfree */ + vnode_cleanup(&ev->ev_v); + lock_release(ef->ef_emu->e_lock); + vfs_biglock_release(); + kfree(ev); + return result; + } + + lock_release(ef->ef_emu->e_lock); + vfs_biglock_release(); + + *ret = ev; + return 0; +} + +// +//////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////// +// +// Whole-filesystem functions +// + +/* + * FSOP_SYNC + */ +static +int +emufs_sync(struct fs *fs) +{ + (void)fs; + return 0; +} + +/* + * FSOP_GETVOLNAME + */ +static +const char * +emufs_getvolname(struct fs *fs) +{ + /* We don't have a volume name beyond the device name */ + (void)fs; + return NULL; +} + +/* + * FSOP_GETROOT + */ +static +int +emufs_getroot(struct fs *fs, struct vnode **ret) +{ + struct emufs_fs *ef; + + KASSERT(fs != NULL); + + ef = fs->fs_data; + + KASSERT(ef != NULL); + KASSERT(ef->ef_root != NULL); + + VOP_INCREF(&ef->ef_root->ev_v); + *ret = &ef->ef_root->ev_v; + return 0; +} + +/* + * FSOP_UNMOUNT + */ +static +int +emufs_unmount(struct fs *fs) +{ + /* Always prohibit unmount, as we're not really "mounted" */ + (void)fs; + return EBUSY; +} + +/* + * Function table for the emufs file system. + */ +static const struct fs_ops emufs_fsops = { + .fsop_sync = emufs_sync, + .fsop_getvolname = emufs_getvolname, + .fsop_getroot = emufs_getroot, + .fsop_unmount = emufs_unmount, +}; + +/* + * Routine for "mounting" an emufs - we're not really mounted in the + * sense that the VFS understands that term, because we're not + * connected to a block device. + * + * Basically, we just add ourselves to the name list in the VFS layer. + */ +static +int +emufs_addtovfs(struct emu_softc *sc, const char *devname) +{ + struct emufs_fs *ef; + int result; + + ef = kmalloc(sizeof(struct emufs_fs)); + if (ef==NULL) { + return ENOMEM; + } + + ef->ef_fs.fs_data = ef; + ef->ef_fs.fs_ops = &emufs_fsops; + + ef->ef_emu = sc; + ef->ef_root = NULL; + ef->ef_vnodes = vnodearray_create(); + if (ef->ef_vnodes == NULL) { + kfree(ef); + return ENOMEM; + } + + result = emufs_loadvnode(ef, EMU_ROOTHANDLE, 1, &ef->ef_root); + if (result) { + kfree(ef); + return result; + } + + KASSERT(ef->ef_root!=NULL); + + result = vfs_addfs(devname, &ef->ef_fs); + if (result) { + VOP_DECREF(&ef->ef_root->ev_v); + kfree(ef); + } + return result; +} + +// +//////////////////////////////////////////////////////////// + +/* + * Config routine called by autoconf stuff. + * + * Initialize our data, then add ourselves to the VFS layer. + */ +int +config_emu(struct emu_softc *sc, int emuno) +{ + char name[32]; + + sc->e_lock = lock_create("emufs-lock"); + if (sc->e_lock == NULL) { + return ENOMEM; + } + sc->e_sem = sem_create("emufs-sem", 0); + if (sc->e_sem == NULL) { + lock_destroy(sc->e_lock); + sc->e_lock = NULL; + return ENOMEM; + } + sc->e_iobuf = bus_map_area(sc->e_busdata, sc->e_buspos, EMU_BUFFER); + + snprintf(name, sizeof(name), "emu%d", emuno); + + return emufs_addtovfs(sc, name); +} diff --git a/kern/dev/lamebus/emu.h b/kern/dev/lamebus/emu.h new file mode 100644 index 0000000..7c9563e --- /dev/null +++ b/kern/dev/lamebus/emu.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LAMEBUS_EMU_H_ +#define _LAMEBUS_EMU_H_ + + +#define EMU_MAXIO 16384 +#define EMU_ROOTHANDLE 0 + +/* + * The per-device data used by the emufs device driver. + * (Note that this is only a small portion of its actual data; + * all the filesystem stuff goes elsewhere. + */ + +struct emu_softc { + /* Initialized by lower-level attach code */ + void *e_busdata; + uint32_t e_buspos; + int e_unit; + + /* Initialized by config_emu() */ + struct lock *e_lock; + struct semaphore *e_sem; + void *e_iobuf; + + /* Written by the interrupt handler */ + uint32_t e_result; +}; + +/* Functions called by lower-level drivers */ +void emu_irq(/*struct emu_softc*/ void *); + + +#endif /* _LAMEBUS_EMU_H_ */ diff --git a/kern/dev/lamebus/emu_att.c b/kern/dev/lamebus/emu_att.c new file mode 100644 index 0000000..f3eb653 --- /dev/null +++ b/kern/dev/lamebus/emu_att.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Code for probe/attach of the emu device to lamebus. + */ + +#include +#include +#include +#include +#include "autoconf.h" + +/* Lowest revision we support */ +#define LOW_VERSION 1 + +struct emu_softc * +attach_emu_to_lamebus(int emuno, struct lamebus_softc *sc) +{ + struct emu_softc *es; + int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_EMUFS, + LOW_VERSION, NULL); + if (slot < 0) { + return NULL; + } + + es = kmalloc(sizeof(struct emu_softc)); + if (es==NULL) { + return NULL; + } + + es->e_busdata = sc; + es->e_buspos = slot; + es->e_unit = emuno; + + lamebus_mark(sc, slot); + lamebus_attach_interrupt(sc, slot, es, emu_irq); + + return es; +} diff --git a/kern/dev/lamebus/lamebus.c b/kern/dev/lamebus/lamebus.c new file mode 100644 index 0000000..1b1809d --- /dev/null +++ b/kern/dev/lamebus/lamebus.c @@ -0,0 +1,665 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Machine-independent LAMEbus code. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Register offsets within each config region */ +#define CFGREG_VID 0 /* Vendor ID */ +#define CFGREG_DID 4 /* Device ID */ +#define CFGREG_DRL 8 /* Device Revision Level */ + +/* LAMEbus controller private registers (offsets within its config region) */ +#define CTLREG_RAMSZ 0x200 +#define CTLREG_IRQS 0x204 +#define CTLREG_PWR 0x208 +#define CTLREG_IRQE 0x20c +#define CTLREG_CPUS 0x210 +#define CTLREG_CPUE 0x214 +#define CTLREG_SELF 0x218 + +/* LAMEbus CPU control registers (offsets within each per-cpu region) */ +#define CTLCPU_CIRQE 0x000 +#define CTLCPU_CIPI 0x004 +#define CTLCPU_CRAM 0x300 + + +/* + * Read a config register for the given slot. + */ +static +inline +uint32_t +read_cfg_register(struct lamebus_softc *lb, int slot, uint32_t offset) +{ + /* Note that lb might be NULL on some platforms in some contexts. */ + offset += LB_CONFIG_SIZE*slot; + return lamebus_read_register(lb, LB_CONTROLLER_SLOT, offset); +} + +/* + * Write a config register for a given slot. + */ +static +inline +void +write_cfg_register(struct lamebus_softc *lb, int slot, uint32_t offset, + uint32_t val) +{ + offset += LB_CONFIG_SIZE*slot; + lamebus_write_register(lb, LB_CONTROLLER_SLOT, offset, val); +} + +/* + * Read one of the bus controller's registers. + */ +static +inline +uint32_t +read_ctl_register(struct lamebus_softc *lb, uint32_t offset) +{ + /* Note that lb might be NULL on some platforms in some contexts. */ + return read_cfg_register(lb, LB_CONTROLLER_SLOT, offset); +} + +/* + * Write one of the bus controller's registers. + */ +static +inline +void +write_ctl_register(struct lamebus_softc *lb, uint32_t offset, uint32_t val) +{ + write_cfg_register(lb, LB_CONTROLLER_SLOT, offset, val); +} + +/* + * Write one of the bus controller's CPU control registers. + */ +static +inline +void +write_ctlcpu_register(struct lamebus_softc *lb, unsigned hw_cpunum, + uint32_t offset, uint32_t val) +{ + offset += LB_CTLCPU_OFFSET + hw_cpunum * LB_CTLCPU_SIZE; + lamebus_write_register(lb, LB_CONTROLLER_SLOT, offset, val); +} + +/* + * Find and create secondary CPUs. + */ +void +lamebus_find_cpus(struct lamebus_softc *lamebus) +{ + uint32_t mainboard_vid, mainboard_did; + uint32_t cpumask, self, bit, val; + unsigned i, numcpus, bootcpu; + unsigned hwnum[32]; + + mainboard_vid = read_cfg_register(lamebus, LB_CONTROLLER_SLOT, + CFGREG_VID); + mainboard_did = read_cfg_register(lamebus, LB_CONTROLLER_SLOT, + CFGREG_DID); + if (mainboard_vid == LB_VENDOR_CS161 && + mainboard_did == LBCS161_UPBUSCTL) { + /* Old uniprocessor mainboard; no cpu registers. */ + lamebus->ls_uniprocessor = 1; + return; + } + + cpumask = read_ctl_register(lamebus, CTLREG_CPUS); + self = read_ctl_register(lamebus, CTLREG_SELF); + + numcpus = 0; + bootcpu = 0; + for (i=0; i<32; i++) { + bit = (uint32_t)1 << i; + if ((cpumask & bit) != 0) { + if (self & bit) { + bootcpu = numcpus; + curcpu->c_hardware_number = i; + } + hwnum[numcpus] = i; + numcpus++; + } + } + + for (i=0; ils_uniprocessor) { + return; + } + + cpumask = read_ctl_register(lamebus, CTLREG_CPUS); + self = read_ctl_register(lamebus, CTLREG_SELF); + + /* Poke in the startup address. */ + cpunum = 1; + for (i=0; i<32; i++) { + bit = (uint32_t)1 << i; + if ((cpumask & bit) != 0) { + if (self & bit) { + continue; + } + ctlcpuoffset = LB_CTLCPU_OFFSET + i * LB_CTLCPU_SIZE; + cram = lamebus_map_area(lamebus, + LB_CONTROLLER_SLOT, + ctlcpuoffset + CTLCPU_CRAM); + cram[0] = (uint32_t)cpu_start_secondary; + cram[1] = cpunum++; + } + } + /* Ensure all the above writes get flushed. */ + membar_store_store(); + + /* Now, enable them all. */ + write_ctl_register(lamebus, CTLREG_CPUE, cpumask); +} + +/* + * Probe function. + * + * Given a LAMEbus, look for a device that's not already been marked + * in use, has the specified IDs, and has a device revision level at + * least as high as the minimum specified. + * + * Returns the slot number found (0-31) or -1 if nothing suitable was + * found. + * + * If VERSION_RET is not null, return the device version found. This + * allows drivers to blacklist specific versions or otherwise conduct + * more specific checks. + */ + +int +lamebus_probe(struct lamebus_softc *sc, + uint32_t vendorid, uint32_t deviceid, + uint32_t lowver, uint32_t *version_ret) +{ + int slot; + uint32_t val; + + /* + * Because the slot information in sc is used when dispatching + * interrupts, disable interrupts while working with it. + */ + + spinlock_acquire(&sc->ls_lock); + + for (slot=0; slotls_slotsinuse & (1<ls_lock); + return slot; + } + + /* Found nothing */ + + spinlock_release(&sc->ls_lock); + return -1; +} + +/* + * Mark that a slot is in use. + * This prevents the probe routine from returning the same device over + * and over again. + */ +void +lamebus_mark(struct lamebus_softc *sc, int slot) +{ + uint32_t mask = ((uint32_t)1) << slot; + KASSERT(slot>=0 && slot < LB_NSLOTS); + + spinlock_acquire(&sc->ls_lock); + + if ((sc->ls_slotsinuse & mask)!=0) { + panic("lamebus_mark: slot %d already in use\n", slot); + } + + sc->ls_slotsinuse |= mask; + + spinlock_release(&sc->ls_lock); +} + +/* + * Mark that a slot is no longer in use. + */ +void +lamebus_unmark(struct lamebus_softc *sc, int slot) +{ + uint32_t mask = ((uint32_t)1) << slot; + KASSERT(slot>=0 && slot < LB_NSLOTS); + + spinlock_acquire(&sc->ls_lock); + + if ((sc->ls_slotsinuse & mask)==0) { + panic("lamebus_mark: slot %d not marked in use\n", slot); + } + + sc->ls_slotsinuse &= ~mask; + + spinlock_release(&sc->ls_lock); +} + +/* + * Register a function (and a device context pointer) to be called + * when a particular slot signals an interrupt. + */ +void +lamebus_attach_interrupt(struct lamebus_softc *sc, int slot, + void *devdata, + void (*irqfunc)(void *devdata)) +{ + uint32_t mask = ((uint32_t)1) << slot; + KASSERT(slot>=0 && slot < LB_NSLOTS); + + spinlock_acquire(&sc->ls_lock); + + if ((sc->ls_slotsinuse & mask)==0) { + panic("lamebus_attach_interrupt: slot %d not marked in use\n", + slot); + } + + KASSERT(sc->ls_devdata[slot]==NULL); + KASSERT(sc->ls_irqfuncs[slot]==NULL); + + sc->ls_devdata[slot] = devdata; + sc->ls_irqfuncs[slot] = irqfunc; + + spinlock_release(&sc->ls_lock); +} + +/* + * Unregister a function that was being called when a particular slot + * signaled an interrupt. + */ +void +lamebus_detach_interrupt(struct lamebus_softc *sc, int slot) +{ + uint32_t mask = ((uint32_t)1) << slot; + KASSERT(slot>=0 && slot < LB_NSLOTS); + + spinlock_acquire(&sc->ls_lock); + + if ((sc->ls_slotsinuse & mask)==0) { + panic("lamebus_detach_interrupt: slot %d not marked in use\n", + slot); + } + + KASSERT(sc->ls_irqfuncs[slot]!=NULL); + + sc->ls_devdata[slot] = NULL; + sc->ls_irqfuncs[slot] = NULL; + + spinlock_release(&sc->ls_lock); +} + +/* + * Mask/unmask an interrupt using the global IRQE register. + */ +void +lamebus_mask_interrupt(struct lamebus_softc *lamebus, int slot) +{ + uint32_t bits, mask = ((uint32_t)1) << slot; + KASSERT(slot >= 0 && slot < LB_NSLOTS); + + spinlock_acquire(&lamebus->ls_lock); + bits = read_ctl_register(lamebus, CTLREG_IRQE); + bits &= ~mask; + write_ctl_register(lamebus, CTLREG_IRQE, bits); + spinlock_release(&lamebus->ls_lock); +} + +void +lamebus_unmask_interrupt(struct lamebus_softc *lamebus, int slot) +{ + uint32_t bits, mask = ((uint32_t)1) << slot; + KASSERT(slot >= 0 && slot < LB_NSLOTS); + + spinlock_acquire(&lamebus->ls_lock); + bits = read_ctl_register(lamebus, CTLREG_IRQE); + bits |= mask; + write_ctl_register(lamebus, CTLREG_IRQE, bits); + spinlock_release(&lamebus->ls_lock); +} + + +/* + * LAMEbus interrupt handling function. (Machine-independent!) + */ +void +lamebus_interrupt(struct lamebus_softc *lamebus) +{ + /* + * Note that despite the fact that "spl" stands for "set + * priority level", we don't actually support interrupt + * priorities. When an interrupt happens, we look through the + * slots to find the first interrupting device and call its + * interrupt routine, no matter what that device is. + * + * Note that the entire LAMEbus uses only one on-cpu interrupt line. + * Thus, we do not use any on-cpu interrupt priority system either. + */ + + int slot; + uint32_t mask; + uint32_t irqs; + void (*handler)(void *); + void *data; + + /* For keeping track of how many bogus things happen in a row. */ + static int duds = 0; + int duds_this_time = 0; + + /* and we better have a valid bus instance. */ + KASSERT(lamebus != NULL); + + /* Lock the softc */ + spinlock_acquire(&lamebus->ls_lock); + + /* + * Read the LAMEbus controller register that tells us which + * slots are asserting an interrupt condition. + */ + irqs = read_ctl_register(lamebus, CTLREG_IRQS); + + if (irqs == 0) { + /* + * Huh? None of them? Must be a glitch. + */ + kprintf("lamebus: stray interrupt on cpu %u\n", + curcpu->c_number); + duds++; + duds_this_time++; + + /* + * We could just return now, but instead we'll + * continue ahead. Because irqs == 0, nothing in the + * loop will execute, and passing through it gets us + * to the code that checks how many duds we've + * seen. This is important, because we just might get + * a stray interrupt that latches itself on. If that + * happens, we're pretty much toast, but it's better + * to panic and hopefully reset the system than to + * loop forever printing "stray interrupt". + */ + } + + /* + * Go through the bits in the value we got back to see which + * ones are set. + */ + + for (mask=1, slot=0; slotls_slotsinuse & mask)==0) { + /* + * No device driver is using this slot. + */ + duds++; + duds_this_time++; + continue; + } + + if (lamebus->ls_irqfuncs[slot]==NULL) { + /* + * The device driver hasn't installed an interrupt + * handler. + */ + duds++; + duds_this_time++; + continue; + } + + /* + * Call the interrupt handler. Release the spinlock + * while we do so, in case other CPUs are handling + * interrupts on other devices. + */ + handler = lamebus->ls_irqfuncs[slot]; + data = lamebus->ls_devdata[slot]; + spinlock_release(&lamebus->ls_lock); + + handler(data); + + spinlock_acquire(&lamebus->ls_lock); + + /* + * Reload the mask of pending IRQs - if we just called + * hardclock, we might not have come back to this + * context for some time, and it might have changed. + */ + + irqs = read_ctl_register(lamebus, CTLREG_IRQS); + } + + + /* + * If we get interrupts for a slot with no driver or no + * interrupt handler, it's fairly serious. Because LAMEbus + * uses level-triggered interrupts, if we don't shut off the + * condition, we'll keep getting interrupted continuously and + * the system will make no progress. But we don't know how to + * do that if there's no driver or no interrupt handler. + * + * So, if we get too many dud interrupts, panic, since it's + * better to panic and reset than to hang. + * + * If we get through here without seeing any duds this time, + * the condition, whatever it was, has gone away. It might be + * some stupid device we don't have a driver for, or it might + * have been an electrical transient. In any case, warn and + * clear the dud count. + */ + + if (duds_this_time == 0 && duds > 0) { + kprintf("lamebus: %d dud interrupts\n", duds); + duds = 0; + } + + if (duds > 10000) { + panic("lamebus: too many (%d) dud interrupts\n", duds); + } + + /* Unlock the softc */ + spinlock_release(&lamebus->ls_lock); +} + +/* + * Have the bus controller power the system off. + */ +void +lamebus_poweroff(struct lamebus_softc *lamebus) +{ + /* + * Write 0 to the power register to shut the system off. + */ + + cpu_irqoff(); + write_ctl_register(lamebus, CTLREG_PWR, 0); + + /* The power doesn't go off instantly... so halt the cpu. */ + cpu_halt(); +} + +/* + * Ask the bus controller how much memory we have. + */ +uint32_t +lamebus_ramsize(void) +{ + /* + * Note that this has to work before bus initialization. + * On machines where lamebus_read_register doesn't work + * before bus initialization, this function can't be used + * for initial RAM size lookup. + */ + + return read_ctl_register(NULL, CTLREG_RAMSZ); +} + +/* + * Turn on or off the interprocessor interrupt line for a given CPU. + */ +void +lamebus_assert_ipi(struct lamebus_softc *lamebus, struct cpu *target) +{ + if (lamebus->ls_uniprocessor) { + return; + } + write_ctlcpu_register(lamebus, target->c_hardware_number, + CTLCPU_CIPI, 1); +} + +void +lamebus_clear_ipi(struct lamebus_softc *lamebus, struct cpu *target) +{ + if (lamebus->ls_uniprocessor) { + return; + } + write_ctlcpu_register(lamebus, target->c_hardware_number, + CTLCPU_CIPI, 0); +} + +/* + * Initial setup. + * Should be called from mainbus_bootstrap(). + */ +struct lamebus_softc * +lamebus_init(void) +{ + struct lamebus_softc *lamebus; + int i; + + /* Allocate space for lamebus data */ + lamebus = kmalloc(sizeof(struct lamebus_softc)); + if (lamebus==NULL) { + panic("lamebus_init: Out of memory\n"); + } + + spinlock_init(&lamebus->ls_lock); + + /* + * Initialize the LAMEbus data structure. + */ + lamebus->ls_slotsinuse = 1 << LB_CONTROLLER_SLOT; + + for (i=0; ils_devdata[i] = NULL; + lamebus->ls_irqfuncs[i] = NULL; + } + + lamebus->ls_uniprocessor = 0; + + return lamebus; +} diff --git a/kern/dev/lamebus/lamebus.h b/kern/dev/lamebus/lamebus.h new file mode 100644 index 0000000..1575759 --- /dev/null +++ b/kern/dev/lamebus/lamebus.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LAMEBUS_H_ +#define _LAMEBUS_H_ + +#include +#include + +/* + * Linear Always Mapped Extents + * + * Machine-independent definitions. + */ + + +/* Vendors */ +#define LB_VENDOR_CS161 1 + +/* CS161 devices */ +#define LBCS161_UPBUSCTL 1 +#define LBCS161_TIMER 2 +#define LBCS161_DISK 3 +#define LBCS161_SERIAL 4 +#define LBCS161_SCREEN 5 +#define LBCS161_NET 6 +#define LBCS161_EMUFS 7 +#define LBCS161_TRACE 8 +#define LBCS161_RANDOM 9 +#define LBCS161_MPBUSCTL 10 + +/* LAMEbus controller always goes in slot 31 */ +#define LB_CONTROLLER_SLOT 31 + +/* Number of slots */ +#define LB_NSLOTS 32 + +/* LAMEbus controller per-slot config space */ +#define LB_CONFIG_SIZE 1024 + +/* LAMEbus controller per-cpu control space */ +#define LB_CTLCPU_SIZE 1024 + +/* LAMEbus controller slot offset to per-cpu control space */ +#define LB_CTLCPU_OFFSET 32768 + +/* LAMEbus mapping size per slot */ +#define LB_SLOT_SIZE 65536 + +/* Pointer to kind of function called on interrupt */ +typedef void (*lb_irqfunc)(void *devdata); + +/* + * Driver data + */ +struct lamebus_softc { + struct spinlock ls_lock; + + /* Accessed from interrupts; synchronized with ls_lock */ + uint32_t ls_slotsinuse; + void *ls_devdata[LB_NSLOTS]; + lb_irqfunc ls_irqfuncs[LB_NSLOTS]; + + /* Read-only once set early in boot */ + unsigned ls_uniprocessor; +}; + +/* + * Allocate and set up a lamebus_softc for the system. + */ +struct lamebus_softc *lamebus_init(void); + +/* + * Search for and create cpu structures for the CPUs on the mainboard. + */ +void lamebus_find_cpus(struct lamebus_softc *lamebus); + +/* + * Start up secondary CPUs. + */ +void lamebus_start_cpus(struct lamebus_softc *lamebus); + +/* + * Look for a not-in-use slot containing a device whose vendor and device + * ids match those provided, and whose version is in the range between + * lowver and highver, inclusive. + * + * Returns a slot number (0-31) or -1 if no such device is found. + */ +int lamebus_probe(struct lamebus_softc *, + uint32_t vendorid, uint32_t deviceid, + uint32_t lowver, uint32_t *version_ret); + +/* + * Mark a slot in-use (that is, has a device driver attached to it), + * or unmark it. It is a fatal error to mark a slot that is already + * in use, or unmark a slot that is not in use. + */ +void lamebus_mark(struct lamebus_softc *, int slot); +void lamebus_unmark(struct lamebus_softc *, int slot); + +/* + * Attach to an interrupt. + */ +void lamebus_attach_interrupt(struct lamebus_softc *, int slot, + void *devdata, + void (*irqfunc)(void *devdata)); +/* + * Detach from interrupt. + */ +void lamebus_detach_interrupt(struct lamebus_softc *, int slot); + +/* + * Mask/unmask an interrupt. + */ +void lamebus_mask_interrupt(struct lamebus_softc *, int slot); +void lamebus_unmask_interrupt(struct lamebus_softc *, int slot); + +/* + * Function to call to handle a LAMEbus interrupt. + */ +void lamebus_interrupt(struct lamebus_softc *); + +/* + * Have the LAMEbus controller power the system off. + */ +void lamebus_poweroff(struct lamebus_softc *); + +/* + * Ask the bus controller how much memory we have. + */ +size_t lamebus_ramsize(void); + +/* + * Turn on or off the inter-processor interrupt line to a CPU. + */ +void lamebus_assert_ipi(struct lamebus_softc *, struct cpu *targetcpu); +void lamebus_clear_ipi(struct lamebus_softc *, struct cpu *targetcpu); + +/* + * Read/write 32-bit register at offset OFFSET within slot SLOT. + * (Machine dependent.) + */ +uint32_t lamebus_read_register(struct lamebus_softc *, int slot, + uint32_t offset); +void lamebus_write_register(struct lamebus_softc *, int slot, + uint32_t offset, uint32_t val); + +/* + * Map a buffer that starts at offset OFFSET within slot SLOT. + */ +void *lamebus_map_area(struct lamebus_softc *, int slot, + uint32_t offset); + + +#endif /* _LAMEBUS_H_ */ diff --git a/kern/dev/lamebus/lhd.c b/kern/dev/lamebus/lhd.c new file mode 100644 index 0000000..9d9d9b5 --- /dev/null +++ b/kern/dev/lamebus/lhd.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * LAMEbus hard disk (lhd) driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "autoconf.h" + +/* Registers (offsets within slot) */ +#define LHD_REG_NSECT 0 /* Number of sectors */ +#define LHD_REG_STAT 4 /* Status */ +#define LHD_REG_SECT 8 /* Sector for I/O */ +#define LHD_REG_RPM 12 /* Disk rotation speed (revs per minute) */ + +/* Status codes */ +#define LHD_IDLE 0 /* Device idle */ +#define LHD_WORKING 1 /* Operation in progress */ +#define LHD_OK 4 /* Operation succeeded */ +#define LHD_INVSECT 12 /* Invalid sector requested */ +#define LHD_MEDIA 20 /* Media error */ +#define LHD_ISWRITE 2 /* OR with above: I/O is a write */ +#define LHD_STATEMASK 0x1d /* mask for masking out LHD_ISWRITE */ + +/* Buffer (offset within slot) */ +#define LHD_BUFFER 32768 + +/* + * Shortcut for reading a register. + */ +static +inline +uint32_t lhd_rdreg(struct lhd_softc *lh, uint32_t reg) +{ + return bus_read_register(lh->lh_busdata, lh->lh_buspos, reg); +} + +/* + * Shortcut for writing a register. + */ +static +inline +void lhd_wreg(struct lhd_softc *lh, uint32_t reg, uint32_t val) +{ + bus_write_register(lh->lh_busdata, lh->lh_buspos, reg, val); +} + +/* + * Convert a result code from the hardware to an errno value. + */ +static +int lhd_code_to_errno(struct lhd_softc *lh, int code) +{ + switch (code & LHD_STATEMASK) { + case LHD_OK: return 0; + case LHD_INVSECT: return EINVAL; + case LHD_MEDIA: return EIO; + } + kprintf("lhd%d: Unknown result code %d\n", lh->lh_unit, code); + return EAGAIN; +} + +/* + * Record that an I/O has completed: save the result and poke the + * completion semaphore. + */ +static +void +lhd_iodone(struct lhd_softc *lh, int err) +{ + lh->lh_result = err; + V(lh->lh_done); +} + +/* + * Interrupt handler for lhd. + * Read the status register; if an operation finished, clear the status + * register and report completion. + */ +void +lhd_irq(void *vlh) +{ + struct lhd_softc *lh = vlh; + uint32_t val; + + val = lhd_rdreg(lh, LHD_REG_STAT); + + switch (val & LHD_STATEMASK) { + case LHD_IDLE: + case LHD_WORKING: + break; + case LHD_OK: + case LHD_INVSECT: + case LHD_MEDIA: + lhd_wreg(lh, LHD_REG_STAT, 0); + lhd_iodone(lh, lhd_code_to_errno(lh, val)); + break; + } +} + +/* + * Function called when we are open()'d. + */ +static +int +lhd_eachopen(struct device *d, int openflags) +{ + /* + * Don't need to do anything. + */ + (void)d; + (void)openflags; + + return 0; +} + +/* + * Function for handling ioctls. + */ +static +int +lhd_ioctl(struct device *d, int op, userptr_t data) +{ + /* + * We don't support any ioctls. + */ + (void)d; + (void)op; + (void)data; + return EIOCTL; +} + +#if 0 +/* + * Reset the device. + * This could be used, for instance, on timeout, if you implement suitable + * facilities. + */ +static +void +lhd_reset(struct lhd_softc *lh) +{ + lhd_wreg(lh, LHD_REG_STAT, 0); +} +#endif + +/* + * I/O function (for both reads and writes) + */ +static +int +lhd_io(struct device *d, struct uio *uio) +{ + struct lhd_softc *lh = d->d_data; + + uint32_t sector = uio->uio_offset / LHD_SECTSIZE; + uint32_t sectoff = uio->uio_offset % LHD_SECTSIZE; + uint32_t len = uio->uio_resid / LHD_SECTSIZE; + uint32_t lenoff = uio->uio_resid % LHD_SECTSIZE; + uint32_t i; + uint32_t statval = LHD_WORKING; + int result; + + /* Don't allow I/O that isn't sector-aligned. */ + if (sectoff != 0 || lenoff != 0) { + return EINVAL; + } + + /* Don't allow I/O past the end of the disk. */ + /* XXX this check can overflow */ + if (sector+len > lh->lh_dev.d_blocks) { + return EINVAL; + } + + /* Set up the value to write into the status register. */ + if (uio->uio_rw==UIO_WRITE) { + statval |= LHD_ISWRITE; + } + + /* Loop over all the sectors we were asked to do. */ + for (i=0; ilh_clear); + + /* + * Are we writing? If so, transfer the data to the + * on-card buffer. + */ + if (uio->uio_rw == UIO_WRITE) { + result = uiomove(lh->lh_buf, LHD_SECTSIZE, uio); + membar_store_store(); + if (result) { + V(lh->lh_clear); + return result; + } + } + + /* Tell it what sector we want... */ + lhd_wreg(lh, LHD_REG_SECT, sector+i); + + /* and start the operation. */ + lhd_wreg(lh, LHD_REG_STAT, statval); + + /* Now wait until the interrupt handler tells us we're done. */ + P(lh->lh_done); + + /* Get the result value saved by the interrupt handler. */ + result = lh->lh_result; + + /* + * Are we reading? If so, and if we succeeded, + * transfer the data out of the on-card buffer. + */ + if (result==0 && uio->uio_rw==UIO_READ) { + membar_load_load(); + result = uiomove(lh->lh_buf, LHD_SECTSIZE, uio); + } + + /* Tell another thread it's cleared to go ahead. */ + V(lh->lh_clear); + + /* If we failed, return the error. */ + if (result) { + return result; + } + } + + return 0; +} + +static const struct device_ops lhd_devops = { + .devop_eachopen = lhd_eachopen, + .devop_io = lhd_io, + .devop_ioctl = lhd_ioctl, +}; + +/* + * Setup routine called by autoconf.c when an lhd is found. + */ +int +config_lhd(struct lhd_softc *lh, int lhdno) +{ + char name[32]; + + /* Figure out what our name is. */ + snprintf(name, sizeof(name), "lhd%d", lhdno); + + /* Get a pointer to the on-chip buffer. */ + lh->lh_buf = bus_map_area(lh->lh_busdata, lh->lh_buspos, LHD_BUFFER); + + /* Create the semaphores. */ + lh->lh_clear = sem_create("lhd-clear", 1); + if (lh->lh_clear == NULL) { + return ENOMEM; + } + lh->lh_done = sem_create("lhd-done", 0); + if (lh->lh_done == NULL) { + sem_destroy(lh->lh_clear); + lh->lh_clear = NULL; + return ENOMEM; + } + + /* Set up the VFS device structure. */ + lh->lh_dev.d_ops = &lhd_devops; + lh->lh_dev.d_blocks = bus_read_register(lh->lh_busdata, lh->lh_buspos, + LHD_REG_NSECT); + lh->lh_dev.d_blocksize = LHD_SECTSIZE; + lh->lh_dev.d_data = lh; + + /* Add the VFS device structure to the VFS device list. */ + return vfs_adddev(name, &lh->lh_dev, 1); +} diff --git a/kern/dev/lamebus/lhd.h b/kern/dev/lamebus/lhd.h new file mode 100644 index 0000000..d03ef8a --- /dev/null +++ b/kern/dev/lamebus/lhd.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LAMEBUS_LHD_H_ +#define _LAMEBUS_LHD_H_ + +#include + +/* + * Our sector size + */ +#define LHD_SECTSIZE 512 + +/* + * Hardware device data associated with lhd (LAMEbus hard disk) + */ +struct lhd_softc { + /* Initialized by lower-level attach code */ + void *lh_busdata; /* The bus we're on */ + uint32_t lh_buspos; /* Our slot on that bus */ + int lh_unit; /* What number lhd we are */ + + /* + * Initialized by config_lhd + */ + + void *lh_buf; /* Pointer to on-card I/O buffer */ + int lh_result; /* Result from I/O operation */ + struct semaphore *lh_clear; /* Synchronization */ + struct semaphore *lh_done; + + struct device lh_dev; /* VFS device structure */ +}; + +/* Functions called by lower-level drivers */ +void lhd_irq(/*struct lhd_softc*/ void *); /* Interrupt handler */ + +#endif /* _LAMEBUS_LHD_H_ */ diff --git a/kern/dev/lamebus/lhd_att.c b/kern/dev/lamebus/lhd_att.c new file mode 100644 index 0000000..161387b --- /dev/null +++ b/kern/dev/lamebus/lhd_att.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Code for probe/attach of lhd to LAMEbus. + */ +#include +#include +#include +#include +#include "autoconf.h" + +/* Lowest revision we support */ +#define LOW_VERSION 2 + +struct lhd_softc * +attach_lhd_to_lamebus(int lhdno, struct lamebus_softc *sc) +{ + struct lhd_softc *lh; + int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_DISK, + LOW_VERSION, NULL); + if (slot < 0) { + /* None found */ + return NULL; + } + + lh = kmalloc(sizeof(struct lhd_softc)); + if (lh==NULL) { + /* Out of memory */ + return NULL; + } + + /* Record what the lhd is attached to */ + lh->lh_busdata = sc; + lh->lh_buspos = slot; + lh->lh_unit = lhdno; + + /* Mark the slot in use and collect interrupts */ + lamebus_mark(sc, slot); + lamebus_attach_interrupt(sc, slot, lh, lhd_irq); + + return lh; +} diff --git a/kern/dev/lamebus/lnet.c b/kern/dev/lamebus/lnet.c new file mode 100644 index 0000000..d8af40b --- /dev/null +++ b/kern/dev/lamebus/lnet.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +/*#include */ /* not yet */ +#include "autoconf.h" + +int +config_lnet(struct lnet_softc *sc, int lnetno) +{ + (void)sc; + + kprintf("lnet%d: No network support in system\n", lnetno); + + return ENODEV; +} + + diff --git a/kern/dev/lamebus/lnet_att.c b/kern/dev/lamebus/lnet_att.c new file mode 100644 index 0000000..0a84133 --- /dev/null +++ b/kern/dev/lamebus/lnet_att.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include "autoconf.h" + +/* Lowest revision we support */ +#define LOW_VERSION 1 +/* Highest revision we support */ +#define HIGH_VERSION 1 + +struct lnet_softc * +attach_lnet_to_lamebus(int lnetno, struct lamebus_softc *sc) +{ + int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_NET, + LOW_VERSION, HIGH_VERSION); + if (slot < 0) { + return NULL; + } + + kprintf("lnet%d: No network support in system\n", lnetno); + + return NULL; +} diff --git a/kern/dev/lamebus/lrandom.c b/kern/dev/lamebus/lrandom.c new file mode 100644 index 0000000..e997e27 --- /dev/null +++ b/kern/dev/lamebus/lrandom.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Driver for LAMEbus random generator card + */ +#include +#include +#include +#include +#include +#include "autoconf.h" + +/* Registers (offsets within slot) */ +#define LR_REG_RAND 0 /* random register */ + +/* Constants */ +#define LR_RANDMAX 0xffffffff + +int +config_lrandom(struct lrandom_softc *lr, int lrandomno) +{ + (void)lrandomno; + (void)lr; + return 0; +} + +uint32_t +lrandom_random(void *devdata) +{ + struct lrandom_softc *lr = devdata; + return bus_read_register(lr->lr_bus, lr->lr_buspos, LR_REG_RAND); +} + +uint32_t +lrandom_randmax(void *devdata) +{ + (void)devdata; + return LR_RANDMAX; +} + +int +lrandom_read(void *devdata, struct uio *uio) +{ + struct lrandom_softc *lr = devdata; + uint32_t val; + int result; + + while (uio->uio_resid > 0) { + val = bus_read_register(lr->lr_bus, lr->lr_buspos, + LR_REG_RAND); + result = uiomove(&val, sizeof(val), uio); + if (result) { + return result; + } + } + + return 0; +} diff --git a/kern/dev/lamebus/lrandom.h b/kern/dev/lamebus/lrandom.h new file mode 100644 index 0000000..4087fd0 --- /dev/null +++ b/kern/dev/lamebus/lrandom.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LAMEBUS_LRANDOM_H_ +#define _LAMEBUS_LRANDOM_H_ + +struct uio; + +struct lrandom_softc { + /* Initialized by lower-level attach routine */ + void *lr_bus; + uint32_t lr_buspos; +}; + +/* Functions called by higher-level drivers */ +uint32_t lrandom_random(/*struct lrandom_softc*/ void *devdata); +uint32_t lrandom_randmax(/*struct lrandom_softc*/ void *devdata); +int lrandom_read(/*struct lrandom_softc*/ void *, struct uio *); + +#endif /* _LAMEBUS_LRANDOM_H_ */ diff --git a/kern/dev/lamebus/lrandom_att.c b/kern/dev/lamebus/lrandom_att.c new file mode 100644 index 0000000..8cb2176 --- /dev/null +++ b/kern/dev/lamebus/lrandom_att.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include "autoconf.h" + +/* Lowest revision we support */ +#define LOW_VERSION 1 + +struct lrandom_softc * +attach_lrandom_to_lamebus(int lrandomno, struct lamebus_softc *sc) +{ + struct lrandom_softc *lr; + int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_RANDOM, + LOW_VERSION, NULL); + if (slot < 0) { + return NULL; + } + + lr = kmalloc(sizeof(struct lrandom_softc)); + if (lr==NULL) { + return NULL; + } + + (void)lrandomno; // unused + + lr->lr_bus = sc; + lr->lr_buspos = slot; + + lamebus_mark(sc, slot); + + return lr; +} diff --git a/kern/dev/lamebus/lscreen.c b/kern/dev/lamebus/lscreen.c new file mode 100644 index 0000000..9bdee81 --- /dev/null +++ b/kern/dev/lamebus/lscreen.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Driver for full-screen console. + * + * As of this writing the full-screen console is not supported in + * System/161, so this driver is untested and probably broken. + */ +#include +#include +#include +#include +#include +#include "autoconf.h" + +/* Registers (offsets within slot) */ +#define LSCR_REG_POSN 0 /* Cursor position */ +#define LSCR_REG_SIZE 4 /* Display size */ +#define LSCR_REG_CHAR 8 /* Character in */ +#define LSCR_REG_RIRQ 12 /* Read interrupt status */ + +/* Bits in the IRQ registers */ +#define LSCR_IRQ_ENABLE 1 +#define LSCR_IRQ_ACTIVE 2 + +/* Offset within slot of screen buffer */ +#define LSCR_SCREEN 32768 + +/* Convert a 32-bit X/Y pair to X and Y coordinates. */ +static +inline +void +splitxy(uint32_t xy, unsigned *x, unsigned *y) +{ + *x = xy >> 16; + *y = xy & 0xffff; +} + +/* Convert X and Y coordinates to a single 32-bit value. */ +static +inline +uint32_t +mergexy(unsigned x, unsigned y) +{ + uint32_t val = x; + + return (val << 16) | y; +} + +//////////////////////////////////////////////////////////// + +/* + * Interrupt handler. + */ +void +lscreen_irq(void *vsc) +{ + struct lscreen_softc *sc = vsc; + uint32_t ch, x; + + spinlock_acquire(&sc->ls_lock); + + x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSCR_REG_RIRQ); + if (x & LSCR_IRQ_ACTIVE) { + ch = bus_read_register(sc->ls_busdata, sc->ls_buspos, + LSCR_REG_CHAR); + bus_write_register(sc->ls_busdata, sc->ls_buspos, + LSCR_REG_RIRQ, LSCR_IRQ_ENABLE); + + spinlock_release(&sc->ls_lock); + if (sc->ls_input) { + sc->ls_input(sc->ls_devdata, ch); + } + } + else { + spinlock_release(&sc->ls_lock); + } +} + +//////////////////////////////////////////////////////////// + +/* + * Handle a newline on the screen. + */ +static +void +lscreen_newline(struct lscreen_softc *sc) +{ + if (sc->ls_cy >= sc->ls_height-1) { + /* + * Scroll + */ + + memmove(sc->ls_screen, sc->ls_screen + sc->ls_width, + sc->ls_width * (sc->ls_height-1)); + bzero(sc->ls_screen + sc->ls_width * (sc->ls_height-1), + sc->ls_width); + } + else { + sc->ls_cy++; + } + sc->ls_cx=0; +} + +/* + * Handle a printable character being written to the screen. + */ +static +void +lscreen_char(struct lscreen_softc *sc, int ch) +{ + if (sc->ls_cx >= sc->ls_width) { + lscreen_newline(sc); + } + + sc->ls_screen[sc->ls_cy*sc->ls_width + sc->ls_cx] = ch; + sc->ls_cx++; +} + +/* + * Send a character to the screen. + * This should probably know about backspace and tab. + */ +void +lscreen_write(void *vsc, int ch) +{ + struct lscreen_softc *sc = vsc; + int ccx, ccy; + + spinlock_acquire(&sc->ls_lock); + + switch (ch) { + case '\n': lscreen_newline(sc); break; + default: lscreen_char(sc, ch); break; + } + + /* + * ccx/ccy = corrected cursor position + * (The cursor marks the next space text will appear in. But + * at the very end of the line, it should not move off the edge.) + */ + ccx = sc->ls_cx; + ccy = sc->ls_cy; + if (ccx==sc->ls_width) { + ccx--; + } + + /* Set the cursor position */ + bus_write_register(sc->ls_busdata, sc->ls_buspos, + LSCR_REG_POSN, mergexy(ccx, ccy)); + + spinlock_release(&sc->ls_lock); +} + +//////////////////////////////////////////////////////////// + +/* + * Setup routine called by autoconf.c when an lscreen is found. + */ +int +config_lscreen(struct lscreen_softc *sc, int lscreenno) +{ + uint32_t val; + + (void)lscreenno; + + spinlock_init(&sc->ls_lock); + + /* + * Enable interrupting. + */ + + bus_write_register(sc->ls_busdata, sc->ls_buspos, + LSCR_REG_RIRQ, LSCR_IRQ_ENABLE); + + /* + * Get screen size. + */ + val = bus_read_register(sc->ls_busdata, sc->ls_buspos, + LSCR_REG_SIZE); + splitxy(val, &sc->ls_width, &sc->ls_height); + + /* + * Get cursor position. + */ + val = bus_read_register(sc->ls_busdata, sc->ls_buspos, + LSCR_REG_POSN); + splitxy(val, &sc->ls_cx, &sc->ls_cy); + + /* + * Get a pointer to the memory-mapped screen area. + */ + sc->ls_screen = bus_map_area(sc->ls_busdata, sc->ls_buspos, + LSCR_SCREEN); + + return 0; +} + diff --git a/kern/dev/lamebus/lscreen.h b/kern/dev/lamebus/lscreen.h new file mode 100644 index 0000000..16fa405 --- /dev/null +++ b/kern/dev/lamebus/lscreen.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LAMEBUS_LSCREEN_H_ +#define _LAMEBUS_LSCREEN_H_ + +/* + * Hardware device data for memory-mapped fullscreen text console. + */ +struct lscreen_softc { + /* Initialized by config function */ + struct spinlock ls_lock; // protects data and device regs + unsigned ls_width, ls_height; // screen size + unsigned ls_cx, ls_cy; // cursor position + char *ls_screen; // memory-mapped screen buffer + + /* Initialized by lower-level attachment function */ + void *ls_busdata; // bus we're on + uint32_t ls_buspos; // position on that bus + + /* Initialized by higher-level attachment function */ + void *ls_devdata; // data and functions for + void (*ls_start)(void *devdata); // upper device (perhaps + void (*ls_input)(void *devdata, int ch); // console) +}; + +/* Functions called by lower-level drivers */ +void lscreen_irq(/*struct lser_softc*/ void *sc); // interrupt handler + +/* Functions called by higher-level drivers */ +void lscreen_write(/*struct lser_softc*/ void *sc, int ch); // output function + +#endif /* _LAMEBUS_LSCREEN_H_ */ diff --git a/kern/dev/lamebus/lscreen_att.c b/kern/dev/lamebus/lscreen_att.c new file mode 100644 index 0000000..07d9845 --- /dev/null +++ b/kern/dev/lamebus/lscreen_att.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Code for probe/attach of lscreen to LAMEbus. + */ +#include +#include +#include +#include +#include "autoconf.h" + +/* Lowest revision we support */ +#define LOW_VERSION 1 +/* Highest revision we support */ +#define HIGH_VERSION 1 + +struct lscreen_softc * +attach_lscreen_to_lamebus(int lscreenno, struct lamebus_softc *sc) +{ + struct lscreen_softc *ls; + int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_SCREEN, + LOW_VERSION, HIGH_VERSION); + if (slot < 0) { + /* Not found */ + return NULL; + } + + ls = kmalloc(sizeof(struct lscreen_softc)); + if (ls==NULL) { + /* Out of memory */ + return NULL; + } + + /* Record what it's attached to */ + ls->ls_busdata = sc; + ls->ls_buspos = slot; + + /* Mark the slot in use and hook the interrupt */ + lamebus_mark(sc, slot); + lamebus_attach_interrupt(sc, slot, ls, lscreen_irq); + + return ls; +} diff --git a/kern/dev/lamebus/lser.c b/kern/dev/lamebus/lser.c new file mode 100644 index 0000000..178d22f --- /dev/null +++ b/kern/dev/lamebus/lser.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include "autoconf.h" + +/* Registers (offsets within slot) */ +#define LSER_REG_CHAR 0 /* Character in/out */ +#define LSER_REG_WIRQ 4 /* Write interrupt status */ +#define LSER_REG_RIRQ 8 /* Read interrupt status */ + +/* Bits in the IRQ registers */ +#define LSER_IRQ_ENABLE 1 +#define LSER_IRQ_ACTIVE 2 +#define LSER_IRQ_FORCE 4 + +void +lser_irq(void *vsc) +{ + struct lser_softc *sc = vsc; + uint32_t x; + bool clear_to_write = false; + bool got_a_read = false; + uint32_t ch = 0; + + spinlock_acquire(&sc->ls_lock); + + x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_WIRQ); + if (x & LSER_IRQ_ACTIVE) { + x = LSER_IRQ_ENABLE; + sc->ls_wbusy = 0; + clear_to_write = true; + bus_write_register(sc->ls_busdata, sc->ls_buspos, + LSER_REG_WIRQ, x); + } + + x = bus_read_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_RIRQ); + if (x & LSER_IRQ_ACTIVE) { + x = LSER_IRQ_ENABLE; + ch = bus_read_register(sc->ls_busdata, sc->ls_buspos, + LSER_REG_CHAR); + got_a_read = true; + bus_write_register(sc->ls_busdata, sc->ls_buspos, + LSER_REG_RIRQ, x); + } + + spinlock_release(&sc->ls_lock); + + if (clear_to_write && sc->ls_start != NULL) { + sc->ls_start(sc->ls_devdata); + } + if (got_a_read && sc->ls_input != NULL) { + sc->ls_input(sc->ls_devdata, ch); + } +} + +void +lser_write(void *vls, int ch) +{ + struct lser_softc *ls = vls; + + spinlock_acquire(&ls->ls_lock); + + if (ls->ls_wbusy) { + /* + * We're not clear to write. + * + * This should not happen. It's the job of the driver + * attached to us to not write until we call + * ls->ls_start. + * + * (Note: if we're the console, the panic will go to + * lser_writepolled for printing, because we hold a + * spinlock and interrupts are off; it won't recurse.) + */ + panic("lser: Not clear to write\n"); + } + ls->ls_wbusy = true; + + bus_write_register(ls->ls_busdata, ls->ls_buspos, LSER_REG_CHAR, ch); + + spinlock_release(&ls->ls_lock); +} + +static +void +lser_poll_until_write(struct lser_softc *sc) +{ + uint32_t val; + + KASSERT(spinlock_do_i_hold(&sc->ls_lock)); + + do { + val = bus_read_register(sc->ls_busdata, sc->ls_buspos, + LSER_REG_WIRQ); + } + while ((val & LSER_IRQ_ACTIVE) == 0); +} + +void +lser_writepolled(void *vsc, int ch) +{ + struct lser_softc *sc = vsc; + bool irqpending; + + spinlock_acquire(&sc->ls_lock); + + if (sc->ls_wbusy) { + irqpending = true; + lser_poll_until_write(sc); + /* Clear the ready condition, but leave the IRQ asserted */ + bus_write_register(sc->ls_busdata, sc->ls_buspos, + LSER_REG_WIRQ, + LSER_IRQ_FORCE|LSER_IRQ_ENABLE); + } + else { + irqpending = false; + /* Clear the interrupt enable bit */ + bus_write_register(sc->ls_busdata, sc->ls_buspos, + LSER_REG_WIRQ, 0); + } + + /* Send the character. */ + bus_write_register(sc->ls_busdata, sc->ls_buspos, LSER_REG_CHAR, ch); + + /* Wait until it's done. */ + lser_poll_until_write(sc); + + /* + * If there wasn't already an IRQ pending, clear the ready + * condition and turn interruption back on. But if there was, + * leave the register alone, with the ready condition set (and + * the force bit still on); in due course we'll get to the + * interrupt handler and they'll be cleared. + */ + if (!irqpending) { + bus_write_register(sc->ls_busdata, sc->ls_buspos, + LSER_REG_WIRQ, LSER_IRQ_ENABLE); + } + + spinlock_release(&sc->ls_lock); +} + +int +config_lser(struct lser_softc *sc, int lserno) +{ + (void)lserno; + + /* + * Enable interrupting. + */ + + spinlock_init(&sc->ls_lock); + sc->ls_wbusy = false; + + bus_write_register(sc->ls_busdata, sc->ls_buspos, + LSER_REG_RIRQ, LSER_IRQ_ENABLE); + bus_write_register(sc->ls_busdata, sc->ls_buspos, + LSER_REG_WIRQ, LSER_IRQ_ENABLE); + + return 0; +} diff --git a/kern/dev/lamebus/lser.h b/kern/dev/lamebus/lser.h new file mode 100644 index 0000000..be45670 --- /dev/null +++ b/kern/dev/lamebus/lser.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LAMEBUS_LSER_H_ +#define _LAMEBUS_LSER_H_ + +#include + +struct lser_softc { + /* Initialized by config function */ + struct spinlock ls_lock; /* protects ls_wbusy and device regs */ + volatile bool ls_wbusy; /* true if write in progress */ + + /* Initialized by lower-level attachment function */ + void *ls_busdata; + uint32_t ls_buspos; + + /* Initialized by higher-level attachment function */ + void *ls_devdata; + void (*ls_start)(void *devdata); + void (*ls_input)(void *devdata, int ch); +}; + +/* Functions called by lower-level drivers */ +void lser_irq(/*struct lser_softc*/ void *sc); + +/* Functions called by higher-level drivers */ +void lser_write(/*struct lser_softc*/ void *sc, int ch); +void lser_writepolled(/*struct lser_softc*/ void *sc, int ch); + +#endif /* _LAMEBUS_LSER_H_ */ diff --git a/kern/dev/lamebus/lser_att.c b/kern/dev/lamebus/lser_att.c new file mode 100644 index 0000000..cff43c1 --- /dev/null +++ b/kern/dev/lamebus/lser_att.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include "autoconf.h" + +/* Lowest revision we support */ +#define LOW_VERSION 1 + +struct lser_softc * +attach_lser_to_lamebus(int lserno, struct lamebus_softc *sc) +{ + struct lser_softc *ls; + int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_SERIAL, + LOW_VERSION, NULL); + if (slot < 0) { + return NULL; + } + + ls = kmalloc(sizeof(struct lser_softc)); + if (ls==NULL) { + return NULL; + } + + (void)lserno; // unused + + ls->ls_busdata = sc; + ls->ls_buspos = slot; + + lamebus_mark(sc, slot); + lamebus_attach_interrupt(sc, slot, ls, lser_irq); + + return ls; +} diff --git a/kern/dev/lamebus/ltimer.c b/kern/dev/lamebus/ltimer.c new file mode 100644 index 0000000..bb123d8 --- /dev/null +++ b/kern/dev/lamebus/ltimer.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Driver for LAMEbus clock/timer card + */ +#include +#include +#include +#include +#include +#include +#include "autoconf.h" + +/* Registers (offsets within slot) */ +#define LT_REG_SEC 0 /* time of day: seconds */ +#define LT_REG_NSEC 4 /* time of day: nanoseconds */ +#define LT_REG_ROE 8 /* Restart On countdown-timer Expiry flag */ +#define LT_REG_IRQ 12 /* Interrupt status register */ +#define LT_REG_COUNT 16 /* Time for countdown timer (usec) */ +#define LT_REG_SPKR 20 /* Beep control */ + +/* Granularity of countdown timer (usec) */ +#define LT_GRANULARITY 1000000 + +static bool havetimerclock; + +/* + * Setup routine called by autoconf stuff when an ltimer is found. + */ +int +config_ltimer(struct ltimer_softc *lt, int ltimerno) +{ + /* + * Running on System/161 2.x, we always use the processor + * on-chip timer for hardclock and we don't need ltimer as + * hardclock. + * + * Ideally there should be code here that will use an ltimer + * for hardclock if nothing else is available; e.g. if we + * wanted to make OS/161 2.x run on System/161 1.x. However, + * that requires a good bit more infrastructure for handling + * timers than we have and it doesn't seem worthwhile. + * + * It would also require some hacking, because all CPUs need + * to receive timer interrupts. (Exercise: how would you make + * sure all CPUs receive exactly one timer interrupt? Remember + * that LAMEbus uses level-triggered interrupts, so the + * hardware interrupt line will cause repeated interrupts if + * it's not reset on the device; but if it's reset on the + * device before all CPUs manage to see it, those CPUs won't + * be interrupted at all.) + * + * Note that the beep and rtclock devices *do* attach to + * ltimer. + */ + (void)ltimerno; + lt->lt_hardclock = 0; + + /* + * We do, however, use ltimer for the timer clock, since the + * on-chip timer can't do that. + */ + if (!havetimerclock) { + havetimerclock = true; + lt->lt_timerclock = 1; + + /* Wire it to go off once every second. */ + bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_ROE, 1); + bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_COUNT, + LT_GRANULARITY); + } + + return 0; +} + +/* + * Interrupt handler. + */ +void +ltimer_irq(void *vlt) +{ + struct ltimer_softc *lt = vlt; + uint32_t val; + + val = bus_read_register(lt->lt_bus, lt->lt_buspos, LT_REG_IRQ); + if (val) { + /* + * Only call hardclock if we're responsible for hardclock. + * (Any additional timer devices are unused.) + */ + if (lt->lt_hardclock) { + hardclock(); + } + /* + * Likewise for timerclock. + */ + if (lt->lt_timerclock) { + timerclock(); + } + } +} + +/* + * The timer device will beep if you write to the beep register. It + * doesn't matter what value you write. This function is called if + * the beep device is attached to this timer. + */ +void +ltimer_beep(void *vlt) +{ + struct ltimer_softc *lt = vlt; + + bus_write_register(lt->lt_bus, lt->lt_buspos, LT_REG_SPKR, 440); +} + +/* + * The timer device also has a realtime clock on it. + * This function gets called if the rtclock device is attached + * to this timer. + */ +void +ltimer_gettime(void *vlt, struct timespec *ts) +{ + struct ltimer_softc *lt = vlt; + uint32_t secs1, secs2; + int spl; + + /* + * Read the seconds twice, on either side of the nanoseconds. + * If nsecs is small, use the *later* value of seconds, in case + * the nanoseconds turned over between the time we got the earlier + * value and the time we got nsecs. + * + * Note that the clock in the ltimer device is accurate down + * to a single processor cycle, so this might actually matter + * now and then. + * + * Do it with interrupts off on the current processor to avoid + * getting garbage if we get an interrupt among the register + * reads. + */ + + spl = splhigh(); + + secs1 = bus_read_register(lt->lt_bus, lt->lt_buspos, + LT_REG_SEC); + ts->tv_nsec = bus_read_register(lt->lt_bus, lt->lt_buspos, + LT_REG_NSEC); + secs2 = bus_read_register(lt->lt_bus, lt->lt_buspos, + LT_REG_SEC); + + splx(spl); + + if (ts->tv_nsec < 5000000) { + ts->tv_sec = secs2; + } + else { + ts->tv_sec = secs1; + } +} diff --git a/kern/dev/lamebus/ltimer.h b/kern/dev/lamebus/ltimer.h new file mode 100644 index 0000000..3fdd70f --- /dev/null +++ b/kern/dev/lamebus/ltimer.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LAMEBUS_LTIMER_H_ +#define _LAMEBUS_LTIMER_H_ + +struct timespec; + +/* + * Hardware device data for LAMEbus timer device + */ +struct ltimer_softc { + /* Initialized by config function */ + int lt_hardclock; /* true if we should call hardclock() */ + int lt_timerclock; /* true if we should call timerclock() */ + + /* Initialized by lower-level attach routine */ + void *lt_bus; /* bus we're on */ + uint32_t lt_buspos; /* position (slot) on that bus */ +}; + +/* Functions called by lower-level drivers */ +void ltimer_irq(/*struct ltimer_softc*/ void *lt); // interrupt handler + +/* Functions called by higher-level devices */ +void ltimer_beep(/*struct ltimer_softc*/ void *devdata); // for beep device +void ltimer_gettime(/*struct ltimer_softc*/ void *devdata, + struct timespec *ts); // for rtclock + +#endif /* _LAMEBUS_LTIMER_H_ */ diff --git a/kern/dev/lamebus/ltimer_att.c b/kern/dev/lamebus/ltimer_att.c new file mode 100644 index 0000000..2507d6a --- /dev/null +++ b/kern/dev/lamebus/ltimer_att.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Routine for probing/attaching ltimer to LAMEbus. + */ +#include +#include +#include +#include +#include "autoconf.h" + +/* Lowest revision we support */ +#define LOW_VERSION 1 + +struct ltimer_softc * +attach_ltimer_to_lamebus(int ltimerno, struct lamebus_softc *sc) +{ + struct ltimer_softc *lt; + int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_TIMER, + LOW_VERSION, NULL); + if (slot < 0) { + /* No ltimer (or no additional ltimer) found */ + return NULL; + } + + lt = kmalloc(sizeof(struct ltimer_softc)); + if (lt==NULL) { + /* out of memory */ + return NULL; + } + + (void)ltimerno; // unused + + /* Record what bus it's on */ + lt->lt_bus = sc; + lt->lt_buspos = slot; + + /* Mark the slot in use and hook that slot's interrupt */ + lamebus_mark(sc, slot); + lamebus_attach_interrupt(sc, slot, lt, ltimer_irq); + + return lt; +} diff --git a/kern/dev/lamebus/ltrace.c b/kern/dev/lamebus/ltrace.c new file mode 100644 index 0000000..d9f7a49 --- /dev/null +++ b/kern/dev/lamebus/ltrace.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include "autoconf.h" + +/* Registers (offsets within slot) */ +#define LTRACE_REG_TRON 0 /* trace on */ +#define LTRACE_REG_TROFF 4 /* trace off */ +#define LTRACE_REG_DEBUG 8 /* debug code */ +#define LTRACE_REG_DUMP 12 /* dump the system */ +#define LTRACE_REG_STOP 16 /* stop for the debugger */ +#define LTRACE_REG_PROFEN 20 /* turn profiling on/off */ +#define LTRACE_REG_PROFCL 24 /* clear the profile */ + +static struct ltrace_softc *the_trace; + +void +ltrace_on(uint32_t code) +{ + if (the_trace != NULL) { + bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos, + LTRACE_REG_TRON, code); + } +} + +void +ltrace_off(uint32_t code) +{ + if (the_trace != NULL) { + bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos, + LTRACE_REG_TROFF, code); + } +} + +void +ltrace_debug(uint32_t code) +{ + if (the_trace != NULL) { + bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos, + LTRACE_REG_DEBUG, code); + } +} + +void +ltrace_dump(uint32_t code) +{ + if (the_trace != NULL) { + bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos, + LTRACE_REG_DUMP, code); + } +} + +void +ltrace_stop(uint32_t code) +{ + if (the_trace != NULL && the_trace->lt_canstop) { + bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos, + LTRACE_REG_STOP, code); + } +} + +void +ltrace_setprof(uint32_t onoff) +{ + if (the_trace != NULL && the_trace->lt_canprof) { + bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos, + LTRACE_REG_PROFEN, onoff); + } +} + +void +ltrace_eraseprof(void) +{ + if (the_trace != NULL && the_trace->lt_canprof) { + bus_write_register(the_trace->lt_busdata, the_trace->lt_buspos, + LTRACE_REG_PROFCL, 1); + } +} + +int +config_ltrace(struct ltrace_softc *sc, int ltraceno) +{ + (void)ltraceno; + the_trace = sc; + return 0; +} diff --git a/kern/dev/lamebus/ltrace.h b/kern/dev/lamebus/ltrace.h new file mode 100644 index 0000000..14c9d06 --- /dev/null +++ b/kern/dev/lamebus/ltrace.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LAMEBUS_LTRACE_H_ +#define _LAMEBUS_LTRACE_H_ + +struct ltrace_softc { + /* Initialized by lower-level attachment function */ + void *lt_busdata; + uint32_t lt_buspos; + bool lt_canstop; + bool lt_canprof; +}; + +/* + * Functions provided for debug hacking: + * ltrace_on: turns on the trace161 tracing flag CODE. + * ltrace_off: turns off the trace161 tracing flag CODE. + * ltrace_debug: causes sys161/trace161 to print a message with CODE. + * ltrace_dump: causes trace161 to do a complete state dump, tagged CODE. + * ltrace_stop: causes sys161/trace161 to drop to the debugger. + * ltrace_setprof: turn on and off trace161 profile collection. + * ltrace_eraseprof: discard trace161 profile collected so far. + * + * The flags for ltrace_on/off are the characters used to control + * tracing on the trace161 command line. See the System/161 manual for + * more information. + * + * ltrace_debug is for printing simple indications that a certain + * piece of code has been reached, like one might use kprintf, except + * that it is less invasive than kprintf. Think of it as setting the + * value of a readout on the system's front panel. (In real life, + * since computers don't have front panels with blinking lights any + * more, people often use the speaker or the top left corner of the + * screen for this purpose.) + * + * ltrace_dump dumps the entire system state and is primarily intended + * for regression testing of System/161. It might or might not prove + * useful for debugging as well. + * + * Calling ltrace_stop behaves similarly to hardwiring a breakpoint + * instruction in your code, except that debuggers have trouble + * stepping past hardwired breakpoints. Currently the value of the + * code is ignored. + * + * ltrace_setprof can be used to dynamically turn profiling on and + * off, if trace161 is collecting a profile. (Otherwise it does + * nothing.) This can be used to e.g. profile only code that executes + * while holding a given lock. + * + * ltrace_eraseprof can be used to clear the accumulated profile + * data, if trace161 is collecting a profile. (Otherwise it does + * nothing.) This can be used to e.g. exclude bootup actions from your + * profile. + */ +void ltrace_on(uint32_t code); +void ltrace_off(uint32_t code); +void ltrace_debug(uint32_t code); +void ltrace_dump(uint32_t code); +void ltrace_stop(uint32_t code); +void ltrace_setprof(uint32_t onoff); +void ltrace_eraseprof(void); + +#endif /* _LAMEBUS_LTRACE_H_ */ diff --git a/kern/dev/lamebus/ltrace_att.c b/kern/dev/lamebus/ltrace_att.c new file mode 100644 index 0000000..69e7e76 --- /dev/null +++ b/kern/dev/lamebus/ltrace_att.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include "autoconf.h" + +/* Lowest revision we support */ +#define LOW_VERSION 1 +/* Revision that supports ltrace_stop() */ +#define STOP_VERSION 2 +/* Revision that supports ltrace_prof() */ +#define PROF_VERSION 3 + +struct ltrace_softc * +attach_ltrace_to_lamebus(int ltraceno, struct lamebus_softc *sc) +{ + struct ltrace_softc *lt; + uint32_t drl; + int slot = lamebus_probe(sc, LB_VENDOR_CS161, LBCS161_TRACE, + LOW_VERSION, &drl); + if (slot < 0) { + return NULL; + } + + lt = kmalloc(sizeof(struct ltrace_softc)); + if (lt==NULL) { + return NULL; + } + + (void)ltraceno; // unused + + lt->lt_busdata = sc; + lt->lt_buspos = slot; + lt->lt_canstop = drl >= STOP_VERSION; + lt->lt_canprof = drl >= PROF_VERSION; + + lamebus_mark(sc, slot); + + return lt; +} diff --git a/kern/dev/lamebus/random_lrandom.c b/kern/dev/lamebus/random_lrandom.c new file mode 100644 index 0000000..145fd74 --- /dev/null +++ b/kern/dev/lamebus/random_lrandom.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Attachment code for having the generic random device use the LAMEbus + * random device. + */ + +#include +#include +#include +#include +#include "autoconf.h" + +struct random_softc * +attach_random_to_lrandom(int randomno, struct lrandom_softc *ls) +{ + struct random_softc *rs = kmalloc(sizeof(struct random_softc)); + if (rs==NULL) { + return NULL; + } + + (void)randomno; // unused + + rs->rs_devdata = ls; + rs->rs_random = lrandom_random; + rs->rs_randmax = lrandom_randmax; + rs->rs_read = lrandom_read; + + return rs; +} diff --git a/kern/dev/lamebus/rtclock_ltimer.c b/kern/dev/lamebus/rtclock_ltimer.c new file mode 100644 index 0000000..10ccb23 --- /dev/null +++ b/kern/dev/lamebus/rtclock_ltimer.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Code for attaching the (generic) rtclock device to the LAMEbus ltimer. + * + * rtclock is a generic clock interface that gets its clock service from + * an actual hardware clock of some kind. (Theoretically it could also + * get its clock service from a clock maintained in software, as is the + * case on most systems. However, no such driver has been written yet.) + * + * ltimer can provide this clock service. + */ + +#include +#include +#include +#include +#include "autoconf.h" + +struct rtclock_softc * +attach_rtclock_to_ltimer(int rtclockno, struct ltimer_softc *ls) +{ + /* + * No need to probe; ltimer always has a clock. + * Just allocate the rtclock, set our fields, and return it. + */ + struct rtclock_softc *rtc = kmalloc(sizeof(struct rtclock_softc)); + if (rtc==NULL) { + /* Out of memory */ + return NULL; + } + + (void)rtclockno; // unused + + rtc->rtc_devdata = ls; + rtc->rtc_gettime = ltimer_gettime; + + return rtc; +} diff --git a/kern/fs/semfs/semfs.h b/kern/fs/semfs/semfs.h new file mode 100644 index 0000000..93d153c --- /dev/null +++ b/kern/fs/semfs/semfs.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef SEMFS_H +#define SEMFS_H + +#include +#include +#include + +#ifndef SEMFS_INLINE +#define SEMFS_INLINE INLINE +#endif + +/* + * Constants + */ + +#define SEMFS_ROOTDIR 0xffffffffU /* semnum for root dir */ + +/* + * A user-facing semaphore. + * + * We don't use the kernel-level semaphore to implement it (although + * that would be tidy) because we'd have to violate its abstraction. + * XXX: or would we? review once all this is done. + */ +struct semfs_sem { + struct lock *sems_lock; /* Lock to protect count */ + struct cv *sems_cv; /* CV to wait */ + unsigned sems_count; /* Semaphore count */ + bool sems_hasvnode; /* The vnode exists */ + bool sems_linked; /* In the directory */ +}; +DECLARRAY(semfs_sem, SEMFS_INLINE); + +/* + * Directory entry; name and reference to a semaphore. + */ +struct semfs_direntry { + char *semd_name; /* Name */ + unsigned semd_semnum; /* Which semaphore */ +}; +DECLARRAY(semfs_direntry, SEMFS_INLINE); + +/* + * Vnode. These are separate from the semaphore structures so they can + * come and go at the whim of VOP_RECLAIM. (It might seem tidier to + * ignore VOP_RECLAIM and destroy vnodes only when the underlying + * objects are removed; but it ends up being more complicated in + * practice. XXX: review after finishing) + */ +struct semfs_vnode { + struct vnode semv_absvn; /* Abstract vnode */ + struct semfs *semv_semfs; /* Back-pointer to fs */ + unsigned semv_semnum; /* Which semaphore */ +}; + +/* + * The structure for the semaphore file system. Ordinarily there + * is only one of these. + */ +struct semfs { + struct fs semfs_absfs; /* Abstract fs object */ + + struct lock *semfs_tablelock; /* Lock for following */ + struct vnodearray *semfs_vnodes; /* Currently extant vnodes */ + struct semfs_semarray *semfs_sems; /* Semaphores */ + + struct lock *semfs_dirlock; /* Lock for following */ + struct semfs_direntryarray *semfs_dents; /* The root directory */ +}; + +/* + * Arrays + */ + +DEFARRAY(semfs_sem, SEMFS_INLINE); +DEFARRAY(semfs_direntry, SEMFS_INLINE); + + +/* + * Functions. + */ + +/* in semfs_obj.c */ +struct semfs_sem *semfs_sem_create(const char *name); +int semfs_sem_insert(struct semfs *, struct semfs_sem *, unsigned *); +void semfs_sem_destroy(struct semfs_sem *); +struct semfs_direntry *semfs_direntry_create(const char *name, unsigned semno); +void semfs_direntry_destroy(struct semfs_direntry *); + +/* in semfs_vnops.c */ +int semfs_getvnode(struct semfs *, unsigned, struct vnode **ret); + + +#endif /* SEMFS_H */ diff --git a/kern/fs/semfs/semfs_fsops.c b/kern/fs/semfs/semfs_fsops.c new file mode 100644 index 0000000..7fcf4ac --- /dev/null +++ b/kern/fs/semfs/semfs_fsops.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "semfs.h" + +//////////////////////////////////////////////////////////// +// fs-level operations + +/* + * Sync doesn't need to do anything. + */ +static +int +semfs_sync(struct fs *fs) +{ + (void)fs; + return 0; +} + +/* + * We have only one volume name and it's hardwired. + */ +static +const char * +semfs_getvolname(struct fs *fs) +{ + (void)fs; + return "sem"; +} + +/* + * Get the root directory vnode. + */ +static +int +semfs_getroot(struct fs *fs, struct vnode **ret) +{ + struct semfs *semfs = fs->fs_data; + struct vnode *vn; + int result; + + result = semfs_getvnode(semfs, SEMFS_ROOTDIR, &vn); + if (result) { + kprintf("semfs: couldn't load root vnode: %s\n", + strerror(result)); + return result; + } + *ret = vn; + return 0; +} + +//////////////////////////////////////////////////////////// +// mount and unmount logic + + +/* + * Destructor for struct semfs. + */ +static +void +semfs_destroy(struct semfs *semfs) +{ + struct semfs_sem *sem; + struct semfs_direntry *dent; + unsigned i, num; + + num = semfs_semarray_num(semfs->semfs_sems); + for (i=0; isemfs_sems, i); + semfs_sem_destroy(sem); + } + semfs_semarray_setsize(semfs->semfs_sems, 0); + + num = semfs_direntryarray_num(semfs->semfs_dents); + for (i=0; isemfs_dents, i); + semfs_direntry_destroy(dent); + } + semfs_direntryarray_setsize(semfs->semfs_dents, 0); + + semfs_direntryarray_destroy(semfs->semfs_dents); + lock_destroy(semfs->semfs_dirlock); + semfs_semarray_destroy(semfs->semfs_sems); + vnodearray_destroy(semfs->semfs_vnodes); + lock_destroy(semfs->semfs_tablelock); + kfree(semfs); +} + +/* + * Unmount routine. XXX: Since semfs is attached at boot and can't be + * remounted, maybe unmounting it shouldn't be allowed. + */ +static +int +semfs_unmount(struct fs *fs) +{ + struct semfs *semfs = fs->fs_data; + + lock_acquire(semfs->semfs_tablelock); + if (vnodearray_num(semfs->semfs_vnodes) > 0) { + lock_release(semfs->semfs_tablelock); + return EBUSY; + } + + lock_release(semfs->semfs_tablelock); + semfs_destroy(semfs); + + return 0; +} + +/* + * Operations table. + */ +static const struct fs_ops semfs_fsops = { + .fsop_sync = semfs_sync, + .fsop_getvolname = semfs_getvolname, + .fsop_getroot = semfs_getroot, + .fsop_unmount = semfs_unmount, +}; + +/* + * Constructor for struct semfs. + */ +static +struct semfs * +semfs_create(void) +{ + struct semfs *semfs; + + semfs = kmalloc(sizeof(*semfs)); + if (semfs == NULL) { + goto fail_total; + } + + semfs->semfs_tablelock = lock_create("semfs_table"); + if (semfs->semfs_tablelock == NULL) { + goto fail_semfs; + } + semfs->semfs_vnodes = vnodearray_create(); + if (semfs->semfs_vnodes == NULL) { + goto fail_tablelock; + } + semfs->semfs_sems = semfs_semarray_create(); + if (semfs->semfs_sems == NULL) { + goto fail_vnodes; + } + + semfs->semfs_dirlock = lock_create("semfs_dir"); + if (semfs->semfs_dirlock == NULL) { + goto fail_sems; + } + semfs->semfs_dents = semfs_direntryarray_create(); + if (semfs->semfs_dents == NULL) { + goto fail_dirlock; + } + + semfs->semfs_absfs.fs_data = semfs; + semfs->semfs_absfs.fs_ops = &semfs_fsops; + return semfs; + + fail_dirlock: + lock_destroy(semfs->semfs_dirlock); + fail_sems: + semfs_semarray_destroy(semfs->semfs_sems); + fail_vnodes: + vnodearray_destroy(semfs->semfs_vnodes); + fail_tablelock: + lock_destroy(semfs->semfs_tablelock); + fail_semfs: + kfree(semfs); + fail_total: + return NULL; +} + +/* + * Create the semfs. There is only one semfs and it's attached as + * "sem:" during bootup. + */ +void +semfs_bootstrap(void) +{ + struct semfs *semfs; + int result; + + semfs = semfs_create(); + if (semfs == NULL) { + panic("Out of memory creating semfs\n"); + } + result = vfs_addfs("sem", &semfs->semfs_absfs); + if (result) { + panic("Attaching semfs: %s\n", strerror(result)); + } +} diff --git a/kern/fs/semfs/semfs_obj.c b/kern/fs/semfs/semfs_obj.c new file mode 100644 index 0000000..9f8018a --- /dev/null +++ b/kern/fs/semfs/semfs_obj.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#define SEMFS_INLINE +#include "semfs.h" + +//////////////////////////////////////////////////////////// +// semfs_sem + +/* + * Constructor for semfs_sem. + */ +struct semfs_sem * +semfs_sem_create(const char *name) +{ + struct semfs_sem *sem; + char lockname[32]; + char cvname[32]; + + snprintf(lockname, sizeof(lockname), "sem:l.%s", name); + snprintf(cvname, sizeof(cvname), "sem:%s", name); + + sem = kmalloc(sizeof(*sem)); + if (sem == NULL) { + goto fail_return; + } + sem->sems_lock = lock_create(lockname); + if (sem->sems_lock == NULL) { + goto fail_sem; + } + sem->sems_cv = cv_create(cvname); + if (sem->sems_cv == NULL) { + goto fail_lock; + } + sem->sems_count = 0; + sem->sems_hasvnode = false; + sem->sems_linked = false; + return sem; + + fail_lock: + lock_destroy(sem->sems_lock); + fail_sem: + kfree(sem); + fail_return: + return NULL; +} + +/* + * Destructor for semfs_sem. + */ +void +semfs_sem_destroy(struct semfs_sem *sem) +{ + cv_destroy(sem->sems_cv); + lock_destroy(sem->sems_lock); + kfree(sem); +} + +/* + * Helper to insert a semfs_sem into the semaphore table. + */ +int +semfs_sem_insert(struct semfs *semfs, struct semfs_sem *sem, unsigned *ret) +{ + unsigned i, num; + + KASSERT(lock_do_i_hold(semfs->semfs_tablelock)); + num = semfs_semarray_num(semfs->semfs_sems); + if (num == SEMFS_ROOTDIR) { + /* Too many */ + return ENOSPC; + } + for (i=0; isemfs_sems, i) == NULL) { + semfs_semarray_set(semfs->semfs_sems, i, sem); + *ret = i; + return 0; + } + } + return semfs_semarray_add(semfs->semfs_sems, sem, ret); +} + +//////////////////////////////////////////////////////////// +// semfs_direntry + +/* + * Constructor for semfs_direntry. + */ +struct semfs_direntry * +semfs_direntry_create(const char *name, unsigned semnum) +{ + struct semfs_direntry *dent; + + dent = kmalloc(sizeof(*dent)); + if (dent == NULL) { + return NULL; + } + dent->semd_name = kstrdup(name); + if (dent->semd_name == NULL) { + kfree(dent); + return NULL; + } + dent->semd_semnum = semnum; + return dent; +} + +/* + * Destructor for semfs_direntry. + */ +void +semfs_direntry_destroy(struct semfs_direntry *dent) +{ + kfree(dent->semd_name); + kfree(dent); +} diff --git a/kern/fs/semfs/semfs_vnops.c b/kern/fs/semfs/semfs_vnops.c new file mode 100644 index 0000000..8813f71 --- /dev/null +++ b/kern/fs/semfs/semfs_vnops.c @@ -0,0 +1,799 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "semfs.h" + +//////////////////////////////////////////////////////////// +// basic ops + +static +int +semfs_eachopen(struct vnode *vn, int openflags) +{ + struct semfs_vnode *semv = vn->vn_data; + + if (semv->semv_semnum == SEMFS_ROOTDIR) { + if ((openflags & O_ACCMODE) != O_RDONLY) { + return EISDIR; + } + if (openflags & O_APPEND) { + return EISDIR; + } + } + + return 0; +} + +static +int +semfs_ioctl(struct vnode *vn, int op, userptr_t data) +{ + (void)vn; + (void)op; + (void)data; + return EINVAL; +} + +static +int +semfs_gettype(struct vnode *vn, mode_t *ret) +{ + struct semfs_vnode *semv = vn->vn_data; + + *ret = semv->semv_semnum == SEMFS_ROOTDIR ? S_IFDIR : S_IFREG; + return 0; +} + +static +bool +semfs_isseekable(struct vnode *vn) +{ + struct semfs_vnode *semv = vn->vn_data; + + if (semv->semv_semnum != SEMFS_ROOTDIR) { + /* seeking a semaphore doesn't mean anything */ + return false; + } + return true; +} + +static +int +semfs_fsync(struct vnode *vn) +{ + (void)vn; + return 0; +} + +//////////////////////////////////////////////////////////// +// semaphore ops + +/* + * XXX fold these two together + */ + +static +struct semfs_sem * +semfs_getsembynum(struct semfs *semfs, unsigned semnum) +{ + struct semfs_sem *sem; + + lock_acquire(semfs->semfs_tablelock); + sem = semfs_semarray_get(semfs->semfs_sems, semnum); + lock_release(semfs->semfs_tablelock); + + return sem; +} + +static +struct semfs_sem * +semfs_getsem(struct semfs_vnode *semv) +{ + struct semfs *semfs = semv->semv_semfs; + + return semfs_getsembynum(semfs, semv->semv_semnum); +} + +/* + * Wakeup helper. We only need to wake up if there are sleepers, which + * should only be the case if the old count is 0; and we only + * potentially need to wake more than one sleeper if the new count + * will be more than 1. + */ +static +void +semfs_wakeup(struct semfs_sem *sem, unsigned newcount) +{ + if (sem->sems_count > 0 || newcount == 0) { + return; + } + if (newcount == 1) { + cv_signal(sem->sems_cv, sem->sems_lock); + } + else { + cv_broadcast(sem->sems_cv, sem->sems_lock); + } +} + +/* + * stat() for semaphore vnodes + */ +static +int +semfs_semstat(struct vnode *vn, struct stat *buf) +{ + struct semfs_vnode *semv = vn->vn_data; + struct semfs_sem *sem; + + sem = semfs_getsem(semv); + + bzero(buf, sizeof(*buf)); + + lock_acquire(sem->sems_lock); + buf->st_size = sem->sems_count; + buf->st_nlink = sem->sems_linked ? 1 : 0; + lock_release(sem->sems_lock); + + buf->st_mode = S_IFREG | 0666; + buf->st_blocks = 0; + buf->st_dev = 0; + buf->st_ino = semv->semv_semnum; + + return 0; +} + +/* + * Read. This is P(); decrease the count by the amount read. + * Don't actually bother to transfer any data. + */ +static +int +semfs_read(struct vnode *vn, struct uio *uio) +{ + struct semfs_vnode *semv = vn->vn_data; + struct semfs_sem *sem; + size_t consume; + + sem = semfs_getsem(semv); + + lock_acquire(sem->sems_lock); + while (uio->uio_resid > 0) { + if (sem->sems_count > 0) { + consume = uio->uio_resid; + if (consume > sem->sems_count) { + consume = sem->sems_count; + } + DEBUG(DB_SEMFS, "semfs: sem%u: P, count %u -> %u\n", + semv->semv_semnum, sem->sems_count, + sem->sems_count - consume); + sem->sems_count -= consume; + /* don't bother advancing the uio data pointers */ + uio->uio_offset += consume; + uio->uio_resid -= consume; + } + if (uio->uio_resid == 0) { + break; + } + if (sem->sems_count == 0) { + DEBUG(DB_SEMFS, "semfs: sem%u: blocking\n", + semv->semv_semnum); + cv_wait(sem->sems_cv, sem->sems_lock); + } + } + lock_release(sem->sems_lock); + return 0; +} + +/* + * Write. This is V(); increase the count by the amount written. + * Don't actually bother to transfer any data. + */ +static +int +semfs_write(struct vnode *vn, struct uio *uio) +{ + struct semfs_vnode *semv = vn->vn_data; + struct semfs_sem *sem; + unsigned newcount; + + sem = semfs_getsem(semv); + + lock_acquire(sem->sems_lock); + while (uio->uio_resid > 0) { + newcount = sem->sems_count + uio->uio_resid; + if (newcount < sem->sems_count) { + /* overflow */ + lock_release(sem->sems_lock); + return EFBIG; + } + DEBUG(DB_SEMFS, "semfs: sem%u: V, count %u -> %u\n", + semv->semv_semnum, sem->sems_count, newcount); + semfs_wakeup(sem, newcount); + sem->sems_count = newcount; + uio->uio_offset += uio->uio_resid; + uio->uio_resid = 0; + } + lock_release(sem->sems_lock); + return 0; +} + +/* + * Truncate. Set the count to the specified value. + * + * This is slightly cheesy but it allows open(..., O_TRUNC) to reset a + * semaphore as one would expect. Also it allows creating semaphores + * and then initializing their counts to values other than zero. + */ +static +int +semfs_truncate(struct vnode *vn, off_t len) +{ + /* We should just use UINT_MAX but we don't have it in the kernel */ + const unsigned max = (unsigned)-1; + + struct semfs_vnode *semv = vn->vn_data; + struct semfs_sem *sem; + unsigned newcount; + + if (len < 0) { + return EINVAL; + } + if (len > (off_t)max) { + return EFBIG; + } + newcount = len; + + sem = semfs_getsem(semv); + + lock_acquire(sem->sems_lock); + semfs_wakeup(sem, newcount); + sem->sems_count = newcount; + lock_release(sem->sems_lock); + + return 0; +} + +//////////////////////////////////////////////////////////// +// directory ops + +/* + * Directory read. Note that there's only one directory (the semfs + * root) that has all the semaphores in it. + */ +static +int +semfs_getdirentry(struct vnode *dirvn, struct uio *uio) +{ + struct semfs_vnode *dirsemv = dirvn->vn_data; + struct semfs *semfs = dirsemv->semv_semfs; + struct semfs_direntry *dent; + unsigned num, pos; + int result; + + KASSERT(uio->uio_offset >= 0); + pos = uio->uio_offset; + + lock_acquire(semfs->semfs_dirlock); + + num = semfs_direntryarray_num(semfs->semfs_dents); + if (pos >= num) { + /* EOF */ + result = 0; + } + else { + dent = semfs_direntryarray_get(semfs->semfs_dents, pos); + result = uiomove(dent->semd_name, strlen(dent->semd_name), + uio); + } + + lock_release(semfs->semfs_dirlock); + return result; +} + +/* + * stat() for dirs + */ +static +int +semfs_dirstat(struct vnode *vn, struct stat *buf) +{ + struct semfs_vnode *semv = vn->vn_data; + struct semfs *semfs = semv->semv_semfs; + + bzero(buf, sizeof(*buf)); + + lock_acquire(semfs->semfs_dirlock); + buf->st_size = semfs_direntryarray_num(semfs->semfs_dents); + lock_release(semfs->semfs_dirlock); + + buf->st_mode = S_IFDIR | 1777; + buf->st_nlink = 2; + buf->st_blocks = 0; + buf->st_dev = 0; + buf->st_ino = SEMFS_ROOTDIR; + + return 0; +} + +/* + * Backend for getcwd. Since we don't support subdirs, it's easy; send + * back the empty string. + */ +static +int +semfs_namefile(struct vnode *vn, struct uio *uio) +{ + (void)vn; + (void)uio; + return 0; +} + +/* + * Create a semaphore. + */ +static +int +semfs_creat(struct vnode *dirvn, const char *name, bool excl, mode_t mode, + struct vnode **resultvn) +{ + struct semfs_vnode *dirsemv = dirvn->vn_data; + struct semfs *semfs = dirsemv->semv_semfs; + struct semfs_direntry *dent; + struct semfs_sem *sem; + unsigned i, num, empty, semnum; + int result; + + (void)mode; + if (!strcmp(name, ".") || !strcmp(name, "..")) { + return EEXIST; + } + + lock_acquire(semfs->semfs_dirlock); + num = semfs_direntryarray_num(semfs->semfs_dents); + empty = num; + for (i=0; isemfs_dents, i); + if (dent == NULL) { + if (empty == num) { + empty = i; + } + continue; + } + if (!strcmp(dent->semd_name, name)) { + /* found */ + if (excl) { + lock_release(semfs->semfs_dirlock); + return EEXIST; + } + result = semfs_getvnode(semfs, dent->semd_semnum, + resultvn); + lock_release(semfs->semfs_dirlock); + return result; + } + } + + /* create it */ + sem = semfs_sem_create(name); + if (sem == NULL) { + result = ENOMEM; + goto fail_unlock; + } + lock_acquire(semfs->semfs_tablelock); + result = semfs_sem_insert(semfs, sem, &semnum); + lock_release(semfs->semfs_tablelock); + if (result) { + goto fail_uncreate; + } + + dent = semfs_direntry_create(name, semnum); + if (dent == NULL) { + goto fail_uninsert; + } + + if (empty < num) { + semfs_direntryarray_set(semfs->semfs_dents, empty, dent); + } + else { + result = semfs_direntryarray_add(semfs->semfs_dents, dent, + &empty); + if (result) { + goto fail_undent; + } + } + + result = semfs_getvnode(semfs, semnum, resultvn); + if (result) { + goto fail_undir; + } + + sem->sems_linked = true; + lock_release(semfs->semfs_dirlock); + return 0; + + fail_undir: + semfs_direntryarray_set(semfs->semfs_dents, empty, NULL); + fail_undent: + semfs_direntry_destroy(dent); + fail_uninsert: + lock_acquire(semfs->semfs_tablelock); + semfs_semarray_set(semfs->semfs_sems, semnum, NULL); + lock_release(semfs->semfs_tablelock); + fail_uncreate: + semfs_sem_destroy(sem); + fail_unlock: + lock_release(semfs->semfs_dirlock); + return result; +} + +/* + * Unlink a semaphore. As with other files, it may not actually + * go away if it's currently open. + */ +static +int +semfs_remove(struct vnode *dirvn, const char *name) +{ + struct semfs_vnode *dirsemv = dirvn->vn_data; + struct semfs *semfs = dirsemv->semv_semfs; + struct semfs_direntry *dent; + struct semfs_sem *sem; + unsigned i, num; + int result; + + if (!strcmp(name, ".") || !strcmp(name, "..")) { + return EINVAL; + } + + lock_acquire(semfs->semfs_dirlock); + num = semfs_direntryarray_num(semfs->semfs_dents); + for (i=0; isemfs_dents, i); + if (dent == NULL) { + continue; + } + if (!strcmp(name, dent->semd_name)) { + /* found */ + sem = semfs_getsembynum(semfs, dent->semd_semnum); + lock_acquire(sem->sems_lock); + KASSERT(sem->sems_linked); + sem->sems_linked = false; + if (sem->sems_hasvnode == false) { + lock_acquire(semfs->semfs_tablelock); + semfs_semarray_set(semfs->semfs_sems, + dent->semd_semnum, NULL); + lock_release(semfs->semfs_tablelock); + lock_release(sem->sems_lock); + semfs_sem_destroy(sem); + } + else { + lock_release(sem->sems_lock); + } + semfs_direntryarray_set(semfs->semfs_dents, i, NULL); + semfs_direntry_destroy(dent); + result = 0; + goto out; + } + } + result = ENOENT; + out: + lock_release(semfs->semfs_dirlock); + return result; +} + +/* + * Lookup: get a semaphore by name. + */ +static +int +semfs_lookup(struct vnode *dirvn, char *path, struct vnode **resultvn) +{ + struct semfs_vnode *dirsemv = dirvn->vn_data; + struct semfs *semfs = dirsemv->semv_semfs; + struct semfs_direntry *dent; + unsigned i, num; + int result; + + if (!strcmp(path, ".") || !strcmp(path, "..")) { + VOP_INCREF(dirvn); + *resultvn = dirvn; + return 0; + } + + lock_acquire(semfs->semfs_dirlock); + num = semfs_direntryarray_num(semfs->semfs_dents); + for (i=0; isemfs_dents, i); + if (dent == NULL) { + continue; + } + if (!strcmp(path, dent->semd_name)) { + result = semfs_getvnode(semfs, dent->semd_semnum, + resultvn); + lock_release(semfs->semfs_dirlock); + return result; + } + } + lock_release(semfs->semfs_dirlock); + return ENOENT; +} + +/* + * Lookparent: because we don't have subdirs, just return the root + * dir and copy the name. + */ +static +int +semfs_lookparent(struct vnode *dirvn, char *path, + struct vnode **resultdirvn, char *namebuf, size_t bufmax) +{ + if (strlen(path)+1 > bufmax) { + return ENAMETOOLONG; + } + strcpy(namebuf, path); + + VOP_INCREF(dirvn); + *resultdirvn = dirvn; + return 0; +} + +//////////////////////////////////////////////////////////// +// vnode lifecycle operations + +/* + * Destructor for semfs_vnode. + */ +static +void +semfs_vnode_destroy(struct semfs_vnode *semv) +{ + vnode_cleanup(&semv->semv_absvn); + kfree(semv); +} + +/* + * Reclaim - drop a vnode that's no longer in use. + */ +static +int +semfs_reclaim(struct vnode *vn) +{ + struct semfs_vnode *semv = vn->vn_data; + struct semfs *semfs = semv->semv_semfs; + struct vnode *vn2; + struct semfs_sem *sem; + unsigned i, num; + + lock_acquire(semfs->semfs_tablelock); + + /* vnode refcount is protected by the vnode's ->vn_countlock */ + spinlock_acquire(&vn->vn_countlock); + if (vn->vn_refcount > 1) { + /* consume the reference VOP_DECREF passed us */ + vn->vn_refcount--; + + spinlock_release(&vn->vn_countlock); + lock_release(semfs->semfs_tablelock); + return EBUSY; + } + + spinlock_release(&vn->vn_countlock); + + /* remove from the table */ + num = vnodearray_num(semfs->semfs_vnodes); + for (i=0; isemfs_vnodes, i); + if (vn2 == vn) { + vnodearray_remove(semfs->semfs_vnodes, i); + break; + } + } + + if (semv->semv_semnum != SEMFS_ROOTDIR) { + sem = semfs_semarray_get(semfs->semfs_sems, semv->semv_semnum); + KASSERT(sem->sems_hasvnode); + sem->sems_hasvnode = false; + if (sem->sems_linked == false) { + semfs_semarray_set(semfs->semfs_sems, + semv->semv_semnum, NULL); + semfs_sem_destroy(sem); + } + } + + /* done with the table */ + lock_release(semfs->semfs_tablelock); + + /* destroy it */ + semfs_vnode_destroy(semv); + return 0; +} + +/* + * Vnode ops table for dirs. + */ +static const struct vnode_ops semfs_dirops = { + .vop_magic = VOP_MAGIC, + + .vop_eachopen = semfs_eachopen, + .vop_reclaim = semfs_reclaim, + + .vop_read = vopfail_uio_isdir, + .vop_readlink = vopfail_uio_isdir, + .vop_getdirentry = semfs_getdirentry, + .vop_write = vopfail_uio_isdir, + .vop_ioctl = semfs_ioctl, + .vop_stat = semfs_dirstat, + .vop_gettype = semfs_gettype, + .vop_isseekable = semfs_isseekable, + .vop_fsync = semfs_fsync, + .vop_mmap = vopfail_mmap_isdir, + .vop_truncate = vopfail_truncate_isdir, + .vop_namefile = semfs_namefile, + + .vop_creat = semfs_creat, + .vop_symlink = vopfail_symlink_nosys, + .vop_mkdir = vopfail_mkdir_nosys, + .vop_link = vopfail_link_nosys, + .vop_remove = semfs_remove, + .vop_rmdir = vopfail_string_nosys, + .vop_rename = vopfail_rename_nosys, + .vop_lookup = semfs_lookup, + .vop_lookparent = semfs_lookparent, +}; + +/* + * Vnode ops table for semaphores (files). + */ +static const struct vnode_ops semfs_semops = { + .vop_magic = VOP_MAGIC, + + .vop_eachopen = semfs_eachopen, + .vop_reclaim = semfs_reclaim, + + .vop_read = semfs_read, + .vop_readlink = vopfail_uio_inval, + .vop_getdirentry = vopfail_uio_notdir, + .vop_write = semfs_write, + .vop_ioctl = semfs_ioctl, + .vop_stat = semfs_semstat, + .vop_gettype = semfs_gettype, + .vop_isseekable = semfs_isseekable, + .vop_fsync = semfs_fsync, + .vop_mmap = vopfail_mmap_perm, + .vop_truncate = semfs_truncate, + .vop_namefile = vopfail_uio_notdir, + + .vop_creat = vopfail_creat_notdir, + .vop_symlink = vopfail_symlink_notdir, + .vop_mkdir = vopfail_mkdir_notdir, + .vop_link = vopfail_link_notdir, + .vop_remove = vopfail_string_notdir, + .vop_rmdir = vopfail_string_notdir, + .vop_rename = vopfail_rename_notdir, + .vop_lookup = vopfail_lookup_notdir, + .vop_lookparent = vopfail_lookparent_notdir, +}; + +/* + * Constructor for semfs vnodes. + */ +static +struct semfs_vnode * +semfs_vnode_create(struct semfs *semfs, unsigned semnum) +{ + const struct vnode_ops *optable; + struct semfs_vnode *semv; + int result; + + if (semnum == SEMFS_ROOTDIR) { + optable = &semfs_dirops; + } + else { + optable = &semfs_semops; + } + + semv = kmalloc(sizeof(*semv)); + if (semv == NULL) { + return NULL; + } + + semv->semv_semfs = semfs; + semv->semv_semnum = semnum; + + result = vnode_init(&semv->semv_absvn, optable, + &semfs->semfs_absfs, semv); + /* vnode_init doesn't actually fail */ + KASSERT(result == 0); + + return semv; +} + +/* + * Look up the vnode for a semaphore by number; if it doesn't exist, + * create it. + */ +int +semfs_getvnode(struct semfs *semfs, unsigned semnum, struct vnode **ret) +{ + struct vnode *vn; + struct semfs_vnode *semv; + struct semfs_sem *sem; + unsigned i, num; + int result; + + /* Lock the vnode table */ + lock_acquire(semfs->semfs_tablelock); + + /* Look for it */ + num = vnodearray_num(semfs->semfs_vnodes); + for (i=0; isemfs_vnodes, i); + semv = vn->vn_data; + if (semv->semv_semnum == semnum) { + VOP_INCREF(vn); + lock_release(semfs->semfs_tablelock); + *ret = vn; + return 0; + } + } + + /* Make it */ + semv = semfs_vnode_create(semfs, semnum); + if (semv == NULL) { + lock_release(semfs->semfs_tablelock); + return ENOMEM; + } + result = vnodearray_add(semfs->semfs_vnodes, &semv->semv_absvn, NULL); + if (result) { + semfs_vnode_destroy(semv); + lock_release(semfs->semfs_tablelock); + return ENOMEM; + } + if (semnum != SEMFS_ROOTDIR) { + sem = semfs_semarray_get(semfs->semfs_sems, semnum); + KASSERT(sem != NULL); + KASSERT(sem->sems_hasvnode == false); + sem->sems_hasvnode = true; + } + lock_release(semfs->semfs_tablelock); + + *ret = &semv->semv_absvn; + return 0; +} diff --git a/kern/fs/sfs/sfs_balloc.c b/kern/fs/sfs/sfs_balloc.c new file mode 100644 index 0000000..b931aa0 --- /dev/null +++ b/kern/fs/sfs/sfs_balloc.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * SFS filesystem + * + * Block allocation. + */ +#include +#include +#include +#include +#include "sfsprivate.h" + +/* + * Zero out a disk block. + */ +static +int +sfs_clearblock(struct sfs_fs *sfs, daddr_t block) +{ + /* static -> automatically initialized to zero */ + static char zeros[SFS_BLOCKSIZE]; + + return sfs_writeblock(sfs, block, zeros, SFS_BLOCKSIZE); +} + +/* + * Allocate a block. + */ +int +sfs_balloc(struct sfs_fs *sfs, daddr_t *diskblock) +{ + int result; + + result = bitmap_alloc(sfs->sfs_freemap, diskblock); + if (result) { + return result; + } + sfs->sfs_freemapdirty = true; + + if (*diskblock >= sfs->sfs_sb.sb_nblocks) { + panic("sfs: %s: balloc: invalid block %u\n", + sfs->sfs_sb.sb_volname, *diskblock); + } + + /* Clear block before returning it */ + result = sfs_clearblock(sfs, *diskblock); + if (result) { + bitmap_unmark(sfs->sfs_freemap, *diskblock); + } + return result; +} + +/* + * Free a block. + */ +void +sfs_bfree(struct sfs_fs *sfs, daddr_t diskblock) +{ + bitmap_unmark(sfs->sfs_freemap, diskblock); + sfs->sfs_freemapdirty = true; +} + +/* + * Check if a block is in use. + */ +int +sfs_bused(struct sfs_fs *sfs, daddr_t diskblock) +{ + if (diskblock >= sfs->sfs_sb.sb_nblocks) { + panic("sfs: %s: sfs_bused called on out of range block %u\n", + sfs->sfs_sb.sb_volname, diskblock); + } + return bitmap_isset(sfs->sfs_freemap, diskblock); +} + diff --git a/kern/fs/sfs/sfs_bmap.c b/kern/fs/sfs/sfs_bmap.c new file mode 100644 index 0000000..5352a38 --- /dev/null +++ b/kern/fs/sfs/sfs_bmap.c @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * SFS filesystem + * + * Block mapping logic. + */ +#include +#include +#include +#include +#include +#include "sfsprivate.h" + +/* + * Look up the disk block number (from 0 up to the number of blocks on + * the disk) given a file and the logical block number within that + * file. If DOALLOC is set, and no such block exists, one will be + * allocated. + */ +int +sfs_bmap(struct sfs_vnode *sv, uint32_t fileblock, bool doalloc, + daddr_t *diskblock) +{ + /* + * I/O buffer for handling indirect blocks. + * + * Note: in real life (and when you've done the fs assignment) + * you would get space from the disk buffer cache for this, + * not use a static area. + */ + static uint32_t idbuf[SFS_DBPERIDB]; + + struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data; + daddr_t block; + daddr_t idblock; + uint32_t idnum, idoff; + int result; + + KASSERT(sizeof(idbuf)==SFS_BLOCKSIZE); + + /* Since we're using a static buffer, we'd better be locked. */ + KASSERT(vfs_biglock_do_i_hold()); + + /* + * If the block we want is one of the direct blocks... + */ + if (fileblock < SFS_NDIRECT) { + /* + * Get the block number + */ + block = sv->sv_i.sfi_direct[fileblock]; + + /* + * Do we need to allocate? + */ + if (block==0 && doalloc) { + result = sfs_balloc(sfs, &block); + if (result) { + return result; + } + + /* Remember what we allocated; mark inode dirty */ + sv->sv_i.sfi_direct[fileblock] = block; + sv->sv_dirty = true; + } + + /* + * Hand back the block + */ + if (block != 0 && !sfs_bused(sfs, block)) { + panic("sfs: %s: Data block %u (block %u of file %u) " + "marked free\n", sfs->sfs_sb.sb_volname, + block, fileblock, sv->sv_ino); + } + *diskblock = block; + return 0; + } + + /* + * It's not a direct block; it must be in the indirect block. + * Subtract off the number of direct blocks, so FILEBLOCK is + * now the offset into the indirect block space. + */ + + fileblock -= SFS_NDIRECT; + + /* Get the indirect block number and offset w/i that indirect block */ + idnum = fileblock / SFS_DBPERIDB; + idoff = fileblock % SFS_DBPERIDB; + + /* + * We only have one indirect block. If the offset we were asked for + * is too large, we can't handle it, so fail. + */ + if (idnum >= SFS_NINDIRECT) { + return EFBIG; + } + + /* Get the disk block number of the indirect block. */ + idblock = sv->sv_i.sfi_indirect; + + if (idblock==0 && !doalloc) { + /* + * There's no indirect block allocated. We weren't + * asked to allocate anything, so pretend the indirect + * block was filled with all zeros. + */ + *diskblock = 0; + return 0; + } + else if (idblock==0) { + /* + * There's no indirect block allocated, but we need to + * allocate a block whose number needs to be stored in + * the indirect block. Thus, we need to allocate an + * indirect block. + */ + result = sfs_balloc(sfs, &idblock); + if (result) { + return result; + } + + /* Remember the block we just allocated */ + sv->sv_i.sfi_indirect = idblock; + + /* Mark the inode dirty */ + sv->sv_dirty = true; + + /* Clear the indirect block buffer */ + bzero(idbuf, sizeof(idbuf)); + } + else { + /* + * We already have an indirect block allocated; load it. + */ + result = sfs_readblock(sfs, idblock, idbuf, sizeof(idbuf)); + if (result) { + return result; + } + } + + /* Get the block out of the indirect block buffer */ + block = idbuf[idoff]; + + /* If there's no block there, allocate one */ + if (block==0 && doalloc) { + result = sfs_balloc(sfs, &block); + if (result) { + return result; + } + + /* Remember the block we allocated */ + idbuf[idoff] = block; + + /* The indirect block is now dirty; write it back */ + result = sfs_writeblock(sfs, idblock, idbuf, sizeof(idbuf)); + if (result) { + return result; + } + } + + /* Hand back the result and return. */ + if (block != 0 && !sfs_bused(sfs, block)) { + panic("sfs: %s: Data block %u (block %u of file %u) " + "marked free\n", sfs->sfs_sb.sb_volname, + block, fileblock, sv->sv_ino); + } + *diskblock = block; + return 0; +} + +/* + * Called for ftruncate() and from sfs_reclaim. + */ +int +sfs_itrunc(struct sfs_vnode *sv, off_t len) +{ + /* + * I/O buffer for handling the indirect block. + * + * Note: in real life (and when you've done the fs assignment) + * you would get space from the disk buffer cache for this, + * not use a static area. + */ + static uint32_t idbuf[SFS_DBPERIDB]; + + struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data; + + /* Length in blocks (divide rounding up) */ + uint32_t blocklen = DIVROUNDUP(len, SFS_BLOCKSIZE); + + uint32_t i, j; + daddr_t block, idblock; + uint32_t baseblock, highblock; + int result; + int hasnonzero, iddirty; + + KASSERT(sizeof(idbuf)==SFS_BLOCKSIZE); + + vfs_biglock_acquire(); + + /* + * Go through the direct blocks. Discard any that are + * past the limit we're truncating to. + */ + for (i=0; isv_i.sfi_direct[i]; + if (i >= blocklen && block != 0) { + sfs_bfree(sfs, block); + sv->sv_i.sfi_direct[i] = 0; + sv->sv_dirty = true; + } + } + + /* Indirect block number */ + idblock = sv->sv_i.sfi_indirect; + + /* The lowest block in the indirect block */ + baseblock = SFS_NDIRECT; + + /* The highest block in the indirect block */ + highblock = baseblock + SFS_DBPERIDB - 1; + + if (blocklen < highblock && idblock != 0) { + /* We're past the proposed EOF; may need to free stuff */ + + /* Read the indirect block */ + result = sfs_readblock(sfs, idblock, idbuf, sizeof(idbuf)); + if (result) { + vfs_biglock_release(); + return result; + } + + hasnonzero = 0; + iddirty = 0; + for (j=0; jsv_i.sfi_indirect = 0; + sv->sv_dirty = true; + } + else if (iddirty) { + /* The indirect block is dirty; write it back */ + result = sfs_writeblock(sfs, idblock, idbuf, + sizeof(idbuf)); + if (result) { + vfs_biglock_release(); + return result; + } + } + } + + /* Set the file size */ + sv->sv_i.sfi_size = len; + + /* Mark the inode dirty */ + sv->sv_dirty = true; + + vfs_biglock_release(); + return 0; +} + diff --git a/kern/fs/sfs/sfs_dir.c b/kern/fs/sfs/sfs_dir.c new file mode 100644 index 0000000..5e494b0 --- /dev/null +++ b/kern/fs/sfs/sfs_dir.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * SFS filesystem + * + * Directory I/O + */ +#include +#include +#include +#include +#include +#include "sfsprivate.h" + +/* + * Read the directory entry out of slot SLOT of a directory vnode. + * The "slot" is the index of the directory entry, starting at 0. + */ +static +int +sfs_readdir(struct sfs_vnode *sv, int slot, struct sfs_direntry *sd) +{ + off_t actualpos; + + /* Compute the actual position in the directory to read. */ + actualpos = slot * sizeof(struct sfs_direntry); + + return sfs_metaio(sv, actualpos, sd, sizeof(*sd), UIO_READ); +} + +/* + * Write (overwrite) the directory entry in slot SLOT of a directory + * vnode. + */ +static +int +sfs_writedir(struct sfs_vnode *sv, int slot, struct sfs_direntry *sd) +{ + off_t actualpos; + + /* Compute the actual position in the directory. */ + KASSERT(slot>=0); + actualpos = slot * sizeof(struct sfs_direntry); + + return sfs_metaio(sv, actualpos, sd, sizeof(*sd), UIO_WRITE); +} + +/* + * Compute the number of entries in a directory. + * This actually computes the number of existing slots, and does not + * account for empty slots. + */ +static +int +sfs_dir_nentries(struct sfs_vnode *sv) +{ + struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data; + off_t size; + + KASSERT(sv->sv_i.sfi_type == SFS_TYPE_DIR); + + size = sv->sv_i.sfi_size; + if (size % sizeof(struct sfs_direntry) != 0) { + panic("sfs: %s: directory %u: Invalid size %llu\n", + sfs->sfs_sb.sb_volname, sv->sv_ino, size); + } + + return size / sizeof(struct sfs_direntry); +} + +/* + * Search a directory for a particular filename in a directory, and + * return its inode number, its slot, and/or the slot number of an + * empty directory slot if one is found. + */ +int +sfs_dir_findname(struct sfs_vnode *sv, const char *name, + uint32_t *ino, int *slot, int *emptyslot) +{ + struct sfs_direntry tsd; + int found, nentries, i, result; + + nentries = sfs_dir_nentries(sv); + + /* For each slot... */ + found = 0; + for (i=0; i sizeof(sd.sfd_name)) { + return ENAMETOOLONG; + } + + /* If we didn't get an empty slot, add the entry at the end. */ + if (emptyslot < 0) { + emptyslot = sfs_dir_nentries(sv); + } + + /* Set up the entry. */ + bzero(&sd, sizeof(sd)); + sd.sfd_ino = ino; + strcpy(sd.sfd_name, name); + + /* Hand back the slot, if so requested. */ + if (slot) { + *slot = emptyslot; + } + + /* Write the entry. */ + return sfs_writedir(sv, emptyslot, &sd); +} + +/* + * Unlink a name in a directory, by slot number. + */ +int +sfs_dir_unlink(struct sfs_vnode *sv, int slot) +{ + struct sfs_direntry sd; + + /* Initialize a suitable directory entry... */ + bzero(&sd, sizeof(sd)); + sd.sfd_ino = SFS_NOINO; + + /* ... and write it */ + return sfs_writedir(sv, slot, &sd); +} + +/* + * Look for a name in a directory and hand back a vnode for the + * file, if there is one. + */ +int +sfs_lookonce(struct sfs_vnode *sv, const char *name, + struct sfs_vnode **ret, + int *slot) +{ + struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data; + uint32_t ino; + int result; + + result = sfs_dir_findname(sv, name, &ino, slot, NULL); + if (result) { + return result; + } + + result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, ret); + if (result) { + return result; + } + + if ((*ret)->sv_i.sfi_linkcount == 0) { + panic("sfs: %s: name %s (inode %u) in dir %u has " + "linkcount 0\n", sfs->sfs_sb.sb_volname, + name, (*ret)->sv_ino, sv->sv_ino); + } + + return 0; +} + diff --git a/kern/fs/sfs/sfs_fsops.c b/kern/fs/sfs/sfs_fsops.c new file mode 100644 index 0000000..fef9927 --- /dev/null +++ b/kern/fs/sfs/sfs_fsops.c @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * SFS filesystem + * + * Filesystem-level interface routines. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sfsprivate.h" + + +/* Shortcuts for the size macros in kern/sfs.h */ +#define SFS_FS_NBLOCKS(sfs) ((sfs)->sfs_sb.sb_nblocks) +#define SFS_FS_FREEMAPBITS(sfs) SFS_FREEMAPBITS(SFS_FS_NBLOCKS(sfs)) +#define SFS_FS_FREEMAPBLOCKS(sfs) SFS_FREEMAPBLOCKS(SFS_FS_NBLOCKS(sfs)) + +/* + * Routine for doing I/O (reads or writes) on the free block bitmap. + * We always do the whole bitmap at once; writing individual sectors + * might or might not be a worthwhile optimization. + * + * The free block bitmap consists of SFS_FREEMAPBLOCKS 512-byte + * sectors of bits, one bit for each sector on the filesystem. The + * number of blocks in the bitmap is thus rounded up to the nearest + * multiple of 512*8 = 4096. (This rounded number is SFS_FREEMAPBITS.) + * This means that the bitmap will (in general) contain space for some + * number of invalid sectors that are actually beyond the end of the + * disk device. This is ok. These sectors are supposed to be marked + * "in use" by mksfs and never get marked "free". + * + * The sectors used by the superblock and the bitmap itself are + * likewise marked in use by mksfs. + */ +static +int +sfs_freemapio(struct sfs_fs *sfs, enum uio_rw rw) +{ + uint32_t j, freemapblocks; + char *freemapdata; + int result; + + /* Number of blocks in the free block bitmap. */ + freemapblocks = SFS_FS_FREEMAPBLOCKS(sfs); + + /* Pointer to our freemap data in memory. */ + freemapdata = bitmap_getdata(sfs->sfs_freemap); + + /* For each block in the free block bitmap... */ + for (j=0; jsfs_vnodes); + for (i=0; isfs_vnodes, i); + VOP_FSYNC(v); + } + return 0; +} + +/* + * Sync routine for the freemap. + */ +static +int +sfs_sync_freemap(struct sfs_fs *sfs) +{ + int result; + + if (sfs->sfs_freemapdirty) { + result = sfs_freemapio(sfs, UIO_WRITE); + if (result) { + return result; + } + sfs->sfs_freemapdirty = false; + } + + return 0; +} + +/* + * Sync routine for the superblock. + */ +static +int +sfs_sync_superblock(struct sfs_fs *sfs) +{ + int result; + + if (sfs->sfs_superdirty) { + result = sfs_writeblock(sfs, SFS_SUPER_BLOCK, &sfs->sfs_sb, + sizeof(sfs->sfs_sb)); + if (result) { + return result; + } + sfs->sfs_superdirty = false; + } + return 0; +} + +/* + * Sync routine. This is what gets invoked if you do FS_SYNC on the + * sfs filesystem structure. + */ +static +int +sfs_sync(struct fs *fs) +{ + struct sfs_fs *sfs; + int result; + + vfs_biglock_acquire(); + + /* + * Get the sfs_fs from the generic abstract fs. + * + * Note that the abstract struct fs, which is all the VFS + * layer knows about, is actually a member of struct sfs_fs. + * The pointer in the struct fs points back to the top of the + * struct sfs_fs - essentially the same object. This can be a + * little confusing at first. + * + * The following diagram may help: + * + * struct sfs_fs <-------------\ + * : | + * : sfs_absfs (struct fs) | <------\ + * : : | | + * : : various members | | + * : : | | + * : : fs_data ----------/ | + * : : ...|... + * : . VFS . + * : . layer . + * : other members ....... + * : + * : + * + * This construct is repeated with vnodes and devices and other + * similar things all over the place in OS/161, so taking the + * time to straighten it out in your mind is worthwhile. + */ + + sfs = fs->fs_data; + + /* If any vnodes need to be written, write them. */ + result = sfs_sync_vnodes(sfs); + if (result) { + vfs_biglock_release(); + return result; + } + + /* If the free block map needs to be written, write it. */ + result = sfs_sync_freemap(sfs); + if (result) { + vfs_biglock_release(); + return result; + } + + /* If the superblock needs to be written, write it. */ + result = sfs_sync_superblock(sfs); + if (result) { + vfs_biglock_release(); + return result; + } + + vfs_biglock_release(); + return 0; +} + +/* + * Routine to retrieve the volume name. Filesystems can be referred + * to by their volume name followed by a colon as well as the name + * of the device they're mounted on. + */ +static +const char * +sfs_getvolname(struct fs *fs) +{ + struct sfs_fs *sfs = fs->fs_data; + const char *ret; + + vfs_biglock_acquire(); + ret = sfs->sfs_sb.sb_volname; + vfs_biglock_release(); + + return ret; +} + +/* + * Destructor for struct sfs_fs. + */ +static +void +sfs_fs_destroy(struct sfs_fs *sfs) +{ + if (sfs->sfs_freemap != NULL) { + bitmap_destroy(sfs->sfs_freemap); + } + vnodearray_destroy(sfs->sfs_vnodes); + KASSERT(sfs->sfs_device == NULL); + kfree(sfs); +} + +/* + * Unmount code. + * + * VFS calls FS_SYNC on the filesystem prior to unmounting it. + */ +static +int +sfs_unmount(struct fs *fs) +{ + struct sfs_fs *sfs = fs->fs_data; + + vfs_biglock_acquire(); + + /* Do we have any files open? If so, can't unmount. */ + if (vnodearray_num(sfs->sfs_vnodes) > 0) { + vfs_biglock_release(); + return EBUSY; + } + + /* We should have just had sfs_sync called. */ + KASSERT(sfs->sfs_superdirty == false); + KASSERT(sfs->sfs_freemapdirty == false); + + /* The vfs layer takes care of the device for us */ + sfs->sfs_device = NULL; + + /* Destroy the fs object; once we start nuking stuff we can't fail. */ + sfs_fs_destroy(sfs); + + /* nothing else to do */ + vfs_biglock_release(); + return 0; +} + +/* + * File system operations table. + */ +static const struct fs_ops sfs_fsops = { + .fsop_sync = sfs_sync, + .fsop_getvolname = sfs_getvolname, + .fsop_getroot = sfs_getroot, + .fsop_unmount = sfs_unmount, +}; + +/* + * Basic constructor for struct sfs_fs. This initializes all fields + * but skips stuff that requires reading the volume, like allocating + * the freemap. + */ +static +struct sfs_fs * +sfs_fs_create(void) +{ + struct sfs_fs *sfs; + + /* + * Make sure our on-disk structures aren't messed up + */ + COMPILE_ASSERT(sizeof(struct sfs_superblock)==SFS_BLOCKSIZE); + COMPILE_ASSERT(sizeof(struct sfs_dinode)==SFS_BLOCKSIZE); + COMPILE_ASSERT(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0); + + /* Allocate object */ + sfs = kmalloc(sizeof(struct sfs_fs)); + if (sfs==NULL) { + goto fail; + } + + /* + * Fill in fields + */ + + /* abstract vfs-level fs */ + sfs->sfs_absfs.fs_data = sfs; + sfs->sfs_absfs.fs_ops = &sfs_fsops; + + /* superblock */ + /* (ignore sfs_super, we'll read in over it shortly) */ + sfs->sfs_superdirty = false; + + /* device we mount on */ + sfs->sfs_device = NULL; + + /* vnode table */ + sfs->sfs_vnodes = vnodearray_create(); + if (sfs->sfs_vnodes == NULL) { + goto cleanup_object; + } + + /* freemap */ + sfs->sfs_freemap = NULL; + sfs->sfs_freemapdirty = false; + + return sfs; + +cleanup_object: + kfree(sfs); +fail: + return NULL; +} + +/* + * Mount routine. + * + * The way mount works is that you call vfs_mount and pass it a + * filesystem-specific mount routine. Said routine takes a device and + * hands back a pointer to an abstract filesystem. You can also pass + * a void pointer through. + * + * This organization makes cleanup on error easier. Hint: it may also + * be easier to synchronize correctly; it is important not to get two + * filesystems with the same name mounted at once, or two filesystems + * mounted on the same device at once. + */ +static +int +sfs_domount(void *options, struct device *dev, struct fs **ret) +{ + int result; + struct sfs_fs *sfs; + + vfs_biglock_acquire(); + + /* We don't pass any options through mount */ + (void)options; + + /* + * We can't mount on devices with the wrong sector size. + * + * (Note: for all intents and purposes here, "sector" and + * "block" are interchangeable terms. Technically a filesystem + * block may be composed of several hardware sectors, but we + * don't do that in sfs.) + */ + if (dev->d_blocksize != SFS_BLOCKSIZE) { + vfs_biglock_release(); + kprintf("sfs: Cannot mount on device with blocksize %zu\n", + dev->d_blocksize); + return ENXIO; + } + + sfs = sfs_fs_create(); + if (sfs == NULL) { + vfs_biglock_release(); + return ENOMEM; + } + + /* Set the device so we can use sfs_readblock() */ + sfs->sfs_device = dev; + + /* Load superblock */ + result = sfs_readblock(sfs, SFS_SUPER_BLOCK, &sfs->sfs_sb, + sizeof(sfs->sfs_sb)); + if (result) { + sfs->sfs_device = NULL; + sfs_fs_destroy(sfs); + vfs_biglock_release(); + return result; + } + + /* Make some simple sanity checks */ + + if (sfs->sfs_sb.sb_magic != SFS_MAGIC) { + kprintf("sfs: Wrong magic number in superblock " + "(0x%x, should be 0x%x)\n", + sfs->sfs_sb.sb_magic, + SFS_MAGIC); + sfs->sfs_device = NULL; + sfs_fs_destroy(sfs); + vfs_biglock_release(); + return EINVAL; + } + + if (sfs->sfs_sb.sb_nblocks > dev->d_blocks) { + kprintf("sfs: warning - fs has %u blocks, device has %u\n", + sfs->sfs_sb.sb_nblocks, dev->d_blocks); + } + + /* Ensure null termination of the volume name */ + sfs->sfs_sb.sb_volname[sizeof(sfs->sfs_sb.sb_volname)-1] = 0; + + /* Load free block bitmap */ + sfs->sfs_freemap = bitmap_create(SFS_FS_FREEMAPBITS(sfs)); + if (sfs->sfs_freemap == NULL) { + sfs->sfs_device = NULL; + sfs_fs_destroy(sfs); + vfs_biglock_release(); + return ENOMEM; + } + result = sfs_freemapio(sfs, UIO_READ); + if (result) { + sfs->sfs_device = NULL; + sfs_fs_destroy(sfs); + vfs_biglock_release(); + return result; + } + + /* Hand back the abstract fs */ + *ret = &sfs->sfs_absfs; + + vfs_biglock_release(); + return 0; +} + +/* + * Actual function called from high-level code to mount an sfs. + */ +int +sfs_mount(const char *device) +{ + return vfs_mount(device, NULL, sfs_domount); +} diff --git a/kern/fs/sfs/sfs_inode.c b/kern/fs/sfs/sfs_inode.c new file mode 100644 index 0000000..1649736 --- /dev/null +++ b/kern/fs/sfs/sfs_inode.c @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * SFS filesystem + * + * Inode-level operations and vnode/inode lifecycle logic. + */ +#include +#include +#include +#include +#include +#include "sfsprivate.h" + + +/* + * Write an on-disk inode structure back out to disk. + */ +int +sfs_sync_inode(struct sfs_vnode *sv) +{ + struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data; + int result; + + if (sv->sv_dirty) { + result = sfs_writeblock(sfs, sv->sv_ino, &sv->sv_i, + sizeof(sv->sv_i)); + if (result) { + return result; + } + sv->sv_dirty = false; + } + return 0; +} + +/* + * Called when the vnode refcount (in-memory usage count) hits zero. + * + * This function should try to avoid returning errors other than EBUSY. + */ +int +sfs_reclaim(struct vnode *v) +{ + struct sfs_vnode *sv = v->vn_data; + struct sfs_fs *sfs = v->vn_fs->fs_data; + unsigned ix, i, num; + int result; + + vfs_biglock_acquire(); + + /* + * Make sure someone else hasn't picked up the vnode since the + * decision was made to reclaim it. (You must also synchronize + * this with sfs_loadvnode.) + */ + spinlock_acquire(&v->vn_countlock); + if (v->vn_refcount != 1) { + + /* consume the reference VOP_DECREF gave us */ + KASSERT(v->vn_refcount>1); + v->vn_refcount--; + + spinlock_release(&v->vn_countlock); + vfs_biglock_release(); + return EBUSY; + } + spinlock_release(&v->vn_countlock); + + /* If there are no on-disk references to the file either, erase it. */ + if (sv->sv_i.sfi_linkcount == 0) { + result = sfs_itrunc(sv, 0); + if (result) { + vfs_biglock_release(); + return result; + } + } + + /* Sync the inode to disk */ + result = sfs_sync_inode(sv); + if (result) { + vfs_biglock_release(); + return result; + } + + /* If there are no on-disk references, discard the inode */ + if (sv->sv_i.sfi_linkcount==0) { + sfs_bfree(sfs, sv->sv_ino); + } + + /* Remove the vnode structure from the table in the struct sfs_fs. */ + num = vnodearray_num(sfs->sfs_vnodes); + ix = num; + for (i=0; isfs_vnodes, i); + struct sfs_vnode *sv2 = v2->vn_data; + if (sv2 == sv) { + ix = i; + break; + } + } + if (ix == num) { + panic("sfs: %s: reclaim vnode %u not in vnode pool\n", + sfs->sfs_sb.sb_volname, sv->sv_ino); + } + vnodearray_remove(sfs->sfs_vnodes, ix); + + vnode_cleanup(&sv->sv_absvn); + + vfs_biglock_release(); + + /* Release the storage for the vnode structure itself. */ + kfree(sv); + + /* Done */ + return 0; +} + +/* + * Function to load a inode into memory as a vnode, or dig up one + * that's already resident. + */ +int +sfs_loadvnode(struct sfs_fs *sfs, uint32_t ino, int forcetype, + struct sfs_vnode **ret) +{ + struct vnode *v; + struct sfs_vnode *sv; + const struct vnode_ops *ops; + unsigned i, num; + int result; + + /* Look in the vnodes table */ + num = vnodearray_num(sfs->sfs_vnodes); + + /* Linear search. Is this too slow? You decide. */ + for (i=0; isfs_vnodes, i); + sv = v->vn_data; + + /* Every inode in memory must be in an allocated block */ + if (!sfs_bused(sfs, sv->sv_ino)) { + panic("sfs: %s: Found inode %u in unallocated block\n", + sfs->sfs_sb.sb_volname, sv->sv_ino); + } + + if (sv->sv_ino==ino) { + /* Found */ + + /* forcetype is only allowed when creating objects */ + KASSERT(forcetype==SFS_TYPE_INVAL); + + VOP_INCREF(&sv->sv_absvn); + *ret = sv; + return 0; + } + } + + /* Didn't have it loaded; load it */ + + sv = kmalloc(sizeof(struct sfs_vnode)); + if (sv==NULL) { + return ENOMEM; + } + + /* Must be in an allocated block */ + if (!sfs_bused(sfs, ino)) { + panic("sfs: %s: Tried to load inode %u from " + "unallocated block\n", sfs->sfs_sb.sb_volname, ino); + } + + /* Read the block the inode is in */ + result = sfs_readblock(sfs, ino, &sv->sv_i, sizeof(sv->sv_i)); + if (result) { + kfree(sv); + return result; + } + + /* Not dirty yet */ + sv->sv_dirty = false; + + /* + * FORCETYPE is set if we're creating a new file, because the + * block on disk will have been zeroed out by sfs_balloc and + * thus the type recorded there will be SFS_TYPE_INVAL. + */ + if (forcetype != SFS_TYPE_INVAL) { + KASSERT(sv->sv_i.sfi_type == SFS_TYPE_INVAL); + sv->sv_i.sfi_type = forcetype; + sv->sv_dirty = true; + } + + /* + * Choose the function table based on the object type. + */ + switch (sv->sv_i.sfi_type) { + case SFS_TYPE_FILE: + ops = &sfs_fileops; + break; + case SFS_TYPE_DIR: + ops = &sfs_dirops; + break; + default: + panic("sfs: %s: loadvnode: Invalid inode type " + "(inode %u, type %u)\n", sfs->sfs_sb.sb_volname, + ino, sv->sv_i.sfi_type); + } + + /* Call the common vnode initializer */ + result = vnode_init(&sv->sv_absvn, ops, &sfs->sfs_absfs, sv); + if (result) { + kfree(sv); + return result; + } + + /* Set the other fields in our vnode structure */ + sv->sv_ino = ino; + + /* Add it to our table */ + result = vnodearray_add(sfs->sfs_vnodes, &sv->sv_absvn, NULL); + if (result) { + vnode_cleanup(&sv->sv_absvn); + kfree(sv); + return result; + } + + /* Hand it back */ + *ret = sv; + return 0; +} + +/* + * Create a new filesystem object and hand back its vnode. + */ +int +sfs_makeobj(struct sfs_fs *sfs, int type, struct sfs_vnode **ret) +{ + uint32_t ino; + int result; + + /* + * First, get an inode. (Each inode is a block, and the inode + * number is the block number, so just get a block.) + */ + + result = sfs_balloc(sfs, &ino); + if (result) { + return result; + } + + /* + * Now load a vnode for it. + */ + + result = sfs_loadvnode(sfs, ino, type, ret); + if (result) { + sfs_bfree(sfs, ino); + } + return result; +} + +/* + * Get vnode for the root of the filesystem. + * The root vnode is always found in block 1 (SFS_ROOTDIR_INO). + */ +int +sfs_getroot(struct fs *fs, struct vnode **ret) +{ + struct sfs_fs *sfs = fs->fs_data; + struct sfs_vnode *sv; + int result; + + vfs_biglock_acquire(); + + result = sfs_loadvnode(sfs, SFS_ROOTDIR_INO, SFS_TYPE_INVAL, &sv); + if (result) { + kprintf("sfs: %s: getroot: Cannot load root vnode\n", + sfs->sfs_sb.sb_volname); + vfs_biglock_release(); + return result; + } + + if (sv->sv_i.sfi_type != SFS_TYPE_DIR) { + kprintf("sfs: %s: getroot: not directory (type %u)\n", + sfs->sfs_sb.sb_volname, sv->sv_i.sfi_type); + vfs_biglock_release(); + return EINVAL; + } + + vfs_biglock_release(); + + *ret = &sv->sv_absvn; + return 0; +} diff --git a/kern/fs/sfs/sfs_io.c b/kern/fs/sfs/sfs_io.c new file mode 100644 index 0000000..4454d05 --- /dev/null +++ b/kern/fs/sfs/sfs_io.c @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * SFS filesystem + * + * I/O plumbing. + */ +#include +#include +#include +#include +#include +#include +#include +#include "sfsprivate.h" + +//////////////////////////////////////////////////////////// +// +// Basic block-level I/O routines + +/* + * Note: sfs_readblock is used to read the superblock + * early in mount, before sfs is fully (or even mostly) + * initialized, and so may not use anything from sfs + * except sfs_device. + */ + +/* + * Read or write a block, retrying I/O errors. + */ +static +int +sfs_rwblock(struct sfs_fs *sfs, struct uio *uio) +{ + int result; + int tries=0; + + KASSERT(vfs_biglock_do_i_hold()); + + DEBUG(DB_SFS, "sfs: %s %llu\n", + uio->uio_rw == UIO_READ ? "read" : "write", + uio->uio_offset / SFS_BLOCKSIZE); + + retry: + result = DEVOP_IO(sfs->sfs_device, uio); + if (result == EINVAL) { + /* + * This means the sector we requested was out of range, + * or the seek address we gave wasn't sector-aligned, + * or a couple of other things that are our fault. + */ + panic("sfs: %s: DEVOP_IO returned EINVAL\n", + sfs->sfs_sb.sb_volname); + } + if (result == EIO) { + if (tries == 0) { + tries++; + kprintf("sfs: %s: block %llu I/O error, retrying\n", + sfs->sfs_sb.sb_volname, + uio->uio_offset / SFS_BLOCKSIZE); + goto retry; + } + else if (tries < 10) { + tries++; + goto retry; + } + else { + kprintf("sfs: %s: block %llu I/O error, giving up " + "after %d retries\n", + sfs->sfs_sb.sb_volname, + uio->uio_offset / SFS_BLOCKSIZE, tries); + } + } + return result; +} + +/* + * Read a block. + */ +int +sfs_readblock(struct sfs_fs *sfs, daddr_t block, void *data, size_t len) +{ + struct iovec iov; + struct uio ku; + + KASSERT(len == SFS_BLOCKSIZE); + + SFSUIO(&iov, &ku, data, block, UIO_READ); + return sfs_rwblock(sfs, &ku); +} + +/* + * Write a block. + */ +int +sfs_writeblock(struct sfs_fs *sfs, daddr_t block, void *data, size_t len) +{ + struct iovec iov; + struct uio ku; + + KASSERT(len == SFS_BLOCKSIZE); + + SFSUIO(&iov, &ku, data, block, UIO_WRITE); + return sfs_rwblock(sfs, &ku); +} + +//////////////////////////////////////////////////////////// +// +// File-level I/O + +/* + * Do I/O to a block of a file that doesn't cover the whole block. We + * need to read in the original block first, even if we're writing, so + * we don't clobber the portion of the block we're not intending to + * write over. + * + * SKIPSTART is the number of bytes to skip past at the beginning of + * the sector; LEN is the number of bytes to actually read or write. + * UIO is the area to do the I/O into. + */ +static +int +sfs_partialio(struct sfs_vnode *sv, struct uio *uio, + uint32_t skipstart, uint32_t len) +{ + /* + * I/O buffer for handling partial sectors. + * + * Note: in real life (and when you've done the fs assignment) + * you would get space from the disk buffer cache for this, + * not use a static area. + */ + static char iobuf[SFS_BLOCKSIZE]; + + struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data; + daddr_t diskblock; + uint32_t fileblock; + int result; + + /* Allocate missing blocks if and only if we're writing */ + bool doalloc = (uio->uio_rw==UIO_WRITE); + + KASSERT(skipstart + len <= SFS_BLOCKSIZE); + + /* We're using a global static buffer; it had better be locked */ + KASSERT(vfs_biglock_do_i_hold()); + + /* Compute the block offset of this block in the file */ + fileblock = uio->uio_offset / SFS_BLOCKSIZE; + + /* Get the disk block number */ + result = sfs_bmap(sv, fileblock, doalloc, &diskblock); + if (result) { + return result; + } + + if (diskblock == 0) { + /* + * There was no block mapped at this point in the file. + * Zero the buffer. + */ + KASSERT(uio->uio_rw == UIO_READ); + bzero(iobuf, sizeof(iobuf)); + } + else { + /* + * Read the block. + */ + result = sfs_readblock(sfs, diskblock, iobuf, sizeof(iobuf)); + if (result) { + return result; + } + } + + /* + * Now perform the requested operation into/out of the buffer. + */ + result = uiomove(iobuf+skipstart, len, uio); + if (result) { + return result; + } + + /* + * If it was a write, write back the modified block. + */ + if (uio->uio_rw == UIO_WRITE) { + result = sfs_writeblock(sfs, diskblock, iobuf, sizeof(iobuf)); + if (result) { + return result; + } + } + + return 0; +} + +/* + * Do I/O (either read or write) of a single whole block. + */ +static +int +sfs_blockio(struct sfs_vnode *sv, struct uio *uio) +{ + struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data; + daddr_t diskblock; + uint32_t fileblock; + int result; + bool doalloc = (uio->uio_rw==UIO_WRITE); + off_t saveoff; + off_t diskoff; + off_t saveres; + off_t diskres; + + /* Get the block number within the file */ + fileblock = uio->uio_offset / SFS_BLOCKSIZE; + + /* Look up the disk block number */ + result = sfs_bmap(sv, fileblock, doalloc, &diskblock); + if (result) { + return result; + } + + if (diskblock == 0) { + /* + * No block - fill with zeros. + * + * We must be reading, or sfs_bmap would have + * allocated a block for us. + */ + KASSERT(uio->uio_rw == UIO_READ); + return uiomovezeros(SFS_BLOCKSIZE, uio); + } + + /* + * Do the I/O directly to the uio region. Save the uio_offset, + * and substitute one that makes sense to the device. + */ + saveoff = uio->uio_offset; + diskoff = diskblock * SFS_BLOCKSIZE; + uio->uio_offset = diskoff; + + /* + * Temporarily set the residue to be one block size. + */ + KASSERT(uio->uio_resid >= SFS_BLOCKSIZE); + saveres = uio->uio_resid; + diskres = SFS_BLOCKSIZE; + uio->uio_resid = diskres; + + result = sfs_rwblock(sfs, uio); + + /* + * Now, restore the original uio_offset and uio_resid and update + * them by the amount of I/O done. + */ + uio->uio_offset = (uio->uio_offset - diskoff) + saveoff; + uio->uio_resid = (uio->uio_resid - diskres) + saveres; + + return result; +} + +/* + * Do I/O of a whole region of data, whether or not it's block-aligned. + */ +int +sfs_io(struct sfs_vnode *sv, struct uio *uio) +{ + uint32_t blkoff; + uint32_t nblocks, i; + int result = 0; + uint32_t origresid, extraresid = 0; + + origresid = uio->uio_resid; + + /* + * If reading, check for EOF. If we can read a partial area, + * remember how much extra there was in EXTRARESID so we can + * add it back to uio_resid at the end. + */ + if (uio->uio_rw == UIO_READ) { + off_t size = sv->sv_i.sfi_size; + off_t endpos = uio->uio_offset + uio->uio_resid; + + if (uio->uio_offset >= size) { + /* At or past EOF - just return */ + return 0; + } + + if (endpos > size) { + extraresid = endpos - size; + KASSERT(uio->uio_resid > extraresid); + uio->uio_resid -= extraresid; + } + } + + /* + * First, do any leading partial block. + */ + blkoff = uio->uio_offset % SFS_BLOCKSIZE; + if (blkoff != 0) { + /* Number of bytes at beginning of block to skip */ + uint32_t skip = blkoff; + + /* Number of bytes to read/write after that point */ + uint32_t len = SFS_BLOCKSIZE - blkoff; + + /* ...which might be less than the rest of the block */ + if (len > uio->uio_resid) { + len = uio->uio_resid; + } + + /* Call sfs_partialio() to do it. */ + result = sfs_partialio(sv, uio, skip, len); + if (result) { + goto out; + } + } + + /* If we're done, quit. */ + if (uio->uio_resid==0) { + goto out; + } + + /* + * Now we should be block-aligned. Do the remaining whole blocks. + */ + KASSERT(uio->uio_offset % SFS_BLOCKSIZE == 0); + nblocks = uio->uio_resid / SFS_BLOCKSIZE; + for (i=0; iuio_resid < SFS_BLOCKSIZE); + + if (uio->uio_resid > 0) { + result = sfs_partialio(sv, uio, 0, uio->uio_resid); + if (result) { + goto out; + } + } + + out: + + /* If writing and we did anything, adjust file length */ + if (uio->uio_resid != origresid && + uio->uio_rw == UIO_WRITE && + uio->uio_offset > (off_t)sv->sv_i.sfi_size) { + sv->sv_i.sfi_size = uio->uio_offset; + sv->sv_dirty = true; + } + + /* Add in any extra amount we couldn't read because of EOF */ + uio->uio_resid += extraresid; + + /* Done */ + return result; +} + +//////////////////////////////////////////////////////////// +// Metadata I/O + +/* + * This is much the same as sfs_partialio, but intended for use with + * metadata (e.g. directory entries). It assumes the objects being + * handled are smaller than whole blocks, do not cross block + * boundaries, and originate in the kernel. + * + * It is separate from sfs_partialio because, although there is no + * such code in this version of SFS, it is often desirable when doing + * more advanced things to handle metadata and user data I/O + * differently. + */ +int +sfs_metaio(struct sfs_vnode *sv, off_t actualpos, void *data, size_t len, + enum uio_rw rw) +{ + struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data; + off_t endpos; + uint32_t vnblock; + uint32_t blockoffset; + daddr_t diskblock; + bool doalloc; + int result; + + /* + * I/O buffer for metadata ops. + * + * Note: in real life (and when you've done the fs assignment) you + * would get space from the disk buffer cache for this, not use a + * static area. + */ + static char metaiobuf[SFS_BLOCKSIZE]; + + /* We're using a global static buffer; it had better be locked */ + KASSERT(vfs_biglock_do_i_hold()); + + /* Figure out which block of the vnode (directory, whatever) this is */ + vnblock = actualpos / SFS_BLOCKSIZE; + blockoffset = actualpos % SFS_BLOCKSIZE; + + /* Get the disk block number */ + doalloc = (rw == UIO_WRITE); + result = sfs_bmap(sv, vnblock, doalloc, &diskblock); + if (result) { + return result; + } + + if (diskblock == 0) { + /* Should only get block 0 back if doalloc is false */ + KASSERT(rw == UIO_READ); + + /* Sparse file, read as zeros. */ + bzero(data, len); + return 0; + } + + /* Read the block */ + result = sfs_readblock(sfs, diskblock, metaiobuf, sizeof(metaiobuf)); + if (result) { + return result; + } + + if (rw == UIO_READ) { + /* Copy out the selected region */ + memcpy(data, metaiobuf + blockoffset, len); + } + else { + /* Update the selected region */ + memcpy(metaiobuf + blockoffset, data, len); + + /* Write the block back */ + result = sfs_writeblock(sfs, diskblock, + metaiobuf, sizeof(metaiobuf)); + if (result) { + return result; + } + + /* Update the vnode size if needed */ + endpos = actualpos + len; + if (endpos > (off_t)sv->sv_i.sfi_size) { + sv->sv_i.sfi_size = endpos; + sv->sv_dirty = true; + } + } + + /* Done */ + return 0; +} diff --git a/kern/fs/sfs/sfs_vnops.c b/kern/fs/sfs/sfs_vnops.c new file mode 100644 index 0000000..7500ba7 --- /dev/null +++ b/kern/fs/sfs/sfs_vnops.c @@ -0,0 +1,650 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * SFS filesystem + * + * File-level (vnode) interface routines. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "sfsprivate.h" + +//////////////////////////////////////////////////////////// +// Vnode operations. + +/* + * This is called on *each* open(). + */ +static +int +sfs_eachopen(struct vnode *v, int openflags) +{ + /* + * At this level we do not need to handle O_CREAT, O_EXCL, + * O_TRUNC, or O_APPEND. + * + * Any of O_RDONLY, O_WRONLY, and O_RDWR are valid, so we don't need + * to check that either. + */ + + (void)v; + (void)openflags; + + return 0; +} + +/* + * This is called on *each* open() of a directory. + * Directories may only be open for read. + */ +static +int +sfs_eachopendir(struct vnode *v, int openflags) +{ + switch (openflags & O_ACCMODE) { + case O_RDONLY: + break; + case O_WRONLY: + case O_RDWR: + default: + return EISDIR; + } + if (openflags & O_APPEND) { + return EISDIR; + } + + (void)v; + return 0; +} + +/* + * Called for read(). sfs_io() does the work. + */ +static +int +sfs_read(struct vnode *v, struct uio *uio) +{ + struct sfs_vnode *sv = v->vn_data; + int result; + + KASSERT(uio->uio_rw==UIO_READ); + + vfs_biglock_acquire(); + result = sfs_io(sv, uio); + vfs_biglock_release(); + + return result; +} + +/* + * Called for write(). sfs_io() does the work. + */ +static +int +sfs_write(struct vnode *v, struct uio *uio) +{ + struct sfs_vnode *sv = v->vn_data; + int result; + + KASSERT(uio->uio_rw==UIO_WRITE); + + vfs_biglock_acquire(); + result = sfs_io(sv, uio); + vfs_biglock_release(); + + return result; +} + +/* + * Called for ioctl() + */ +static +int +sfs_ioctl(struct vnode *v, int op, userptr_t data) +{ + /* + * No ioctls. + */ + + (void)v; + (void)op; + (void)data; + + return EINVAL; +} + +/* + * Called for stat/fstat/lstat. + */ +static +int +sfs_stat(struct vnode *v, struct stat *statbuf) +{ + struct sfs_vnode *sv = v->vn_data; + int result; + + /* Fill in the stat structure */ + bzero(statbuf, sizeof(struct stat)); + + result = VOP_GETTYPE(v, &statbuf->st_mode); + if (result) { + return result; + } + + statbuf->st_size = sv->sv_i.sfi_size; + statbuf->st_nlink = sv->sv_i.sfi_linkcount; + + /* We don't support this yet */ + statbuf->st_blocks = 0; + + /* Fill in other fields as desired/possible... */ + + return 0; +} + +/* + * Return the type of the file (types as per kern/stat.h) + */ +static +int +sfs_gettype(struct vnode *v, uint32_t *ret) +{ + struct sfs_vnode *sv = v->vn_data; + struct sfs_fs *sfs = v->vn_fs->fs_data; + + vfs_biglock_acquire(); + + switch (sv->sv_i.sfi_type) { + case SFS_TYPE_FILE: + *ret = S_IFREG; + vfs_biglock_release(); + return 0; + case SFS_TYPE_DIR: + *ret = S_IFDIR; + vfs_biglock_release(); + return 0; + } + panic("sfs: %s: gettype: Invalid inode type (inode %u, type %u)\n", + sfs->sfs_sb.sb_volname, sv->sv_ino, sv->sv_i.sfi_type); + return EINVAL; +} + +/* + * Check if seeking is allowed. The answer is "yes". + */ +static +bool +sfs_isseekable(struct vnode *v) +{ + (void)v; + return true; +} + +/* + * Called for fsync(), and also on filesystem unmount, global sync(), + * and some other cases. + */ +static +int +sfs_fsync(struct vnode *v) +{ + struct sfs_vnode *sv = v->vn_data; + int result; + + vfs_biglock_acquire(); + result = sfs_sync_inode(sv); + vfs_biglock_release(); + + return result; +} + +/* + * Called for mmap(). + */ +static +int +sfs_mmap(struct vnode *v /* add stuff as needed */) +{ + (void)v; + return ENOSYS; +} + +/* + * Truncate a file. + */ +static +int +sfs_truncate(struct vnode *v, off_t len) +{ + struct sfs_vnode *sv = v->vn_data; + + return sfs_itrunc(sv, len); +} + +/* + * Get the full pathname for a file. This only needs to work on directories. + * Since we don't support subdirectories, assume it's the root directory + * and hand back the empty string. (The VFS layer takes care of the + * device name, leading slash, etc.) + */ +static +int +sfs_namefile(struct vnode *vv, struct uio *uio) +{ + struct sfs_vnode *sv = vv->vn_data; + KASSERT(sv->sv_ino == SFS_ROOTDIR_INO); + + /* send back the empty string - just return */ + + (void)uio; + + return 0; +} + +/* + * Create a file. If EXCL is set, insist that the filename not already + * exist; otherwise, if it already exists, just open it. + */ +static +int +sfs_creat(struct vnode *v, const char *name, bool excl, mode_t mode, + struct vnode **ret) +{ + struct sfs_fs *sfs = v->vn_fs->fs_data; + struct sfs_vnode *sv = v->vn_data; + struct sfs_vnode *newguy; + uint32_t ino; + int result; + + vfs_biglock_acquire(); + + /* Look up the name */ + result = sfs_dir_findname(sv, name, &ino, NULL, NULL); + if (result!=0 && result!=ENOENT) { + vfs_biglock_release(); + return result; + } + + /* If it exists and we didn't want it to, fail */ + if (result==0 && excl) { + vfs_biglock_release(); + return EEXIST; + } + + if (result==0) { + /* We got something; load its vnode and return */ + result = sfs_loadvnode(sfs, ino, SFS_TYPE_INVAL, &newguy); + if (result) { + vfs_biglock_release(); + return result; + } + *ret = &newguy->sv_absvn; + vfs_biglock_release(); + return 0; + } + + /* Didn't exist - create it */ + result = sfs_makeobj(sfs, SFS_TYPE_FILE, &newguy); + if (result) { + vfs_biglock_release(); + return result; + } + + /* We don't currently support file permissions; ignore MODE */ + (void)mode; + + /* Link it into the directory */ + result = sfs_dir_link(sv, name, newguy->sv_ino, NULL); + if (result) { + VOP_DECREF(&newguy->sv_absvn); + vfs_biglock_release(); + return result; + } + + /* Update the linkcount of the new file */ + newguy->sv_i.sfi_linkcount++; + + /* and consequently mark it dirty. */ + newguy->sv_dirty = true; + + *ret = &newguy->sv_absvn; + + vfs_biglock_release(); + return 0; +} + +/* + * Make a hard link to a file. + * The VFS layer should prevent this being called unless both + * vnodes are ours. + */ +static +int +sfs_link(struct vnode *dir, const char *name, struct vnode *file) +{ + struct sfs_vnode *sv = dir->vn_data; + struct sfs_vnode *f = file->vn_data; + int result; + + KASSERT(file->vn_fs == dir->vn_fs); + + vfs_biglock_acquire(); + + /* Hard links to directories aren't allowed. */ + if (f->sv_i.sfi_type == SFS_TYPE_DIR) { + vfs_biglock_release(); + return EINVAL; + } + + /* Create the link */ + result = sfs_dir_link(sv, name, f->sv_ino, NULL); + if (result) { + vfs_biglock_release(); + return result; + } + + /* and update the link count, marking the inode dirty */ + f->sv_i.sfi_linkcount++; + f->sv_dirty = true; + + vfs_biglock_release(); + return 0; +} + +/* + * Delete a file. + */ +static +int +sfs_remove(struct vnode *dir, const char *name) +{ + struct sfs_vnode *sv = dir->vn_data; + struct sfs_vnode *victim; + int slot; + int result; + + vfs_biglock_acquire(); + + /* Look for the file and fetch a vnode for it. */ + result = sfs_lookonce(sv, name, &victim, &slot); + if (result) { + vfs_biglock_release(); + return result; + } + + /* Erase its directory entry. */ + result = sfs_dir_unlink(sv, slot); + if (result==0) { + /* If we succeeded, decrement the link count. */ + KASSERT(victim->sv_i.sfi_linkcount > 0); + victim->sv_i.sfi_linkcount--; + victim->sv_dirty = true; + } + + /* Discard the reference that sfs_lookonce got us */ + VOP_DECREF(&victim->sv_absvn); + + vfs_biglock_release(); + return result; +} + +/* + * Rename a file. + * + * Since we don't support subdirectories, assumes that the two + * directories passed are the same. + */ +static +int +sfs_rename(struct vnode *d1, const char *n1, + struct vnode *d2, const char *n2) +{ + struct sfs_vnode *sv = d1->vn_data; + struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data; + struct sfs_vnode *g1; + int slot1, slot2; + int result, result2; + + vfs_biglock_acquire(); + + KASSERT(d1==d2); + KASSERT(sv->sv_ino == SFS_ROOTDIR_INO); + + /* Look up the old name of the file and get its inode and slot number*/ + result = sfs_lookonce(sv, n1, &g1, &slot1); + if (result) { + vfs_biglock_release(); + return result; + } + + /* We don't support subdirectories */ + KASSERT(g1->sv_i.sfi_type == SFS_TYPE_FILE); + + /* + * Link it under the new name. + * + * We could theoretically just overwrite the original + * directory entry, except that we need to check to make sure + * the new name doesn't already exist; might as well use the + * existing link routine. + */ + result = sfs_dir_link(sv, n2, g1->sv_ino, &slot2); + if (result) { + goto puke; + } + + /* Increment the link count, and mark inode dirty */ + g1->sv_i.sfi_linkcount++; + g1->sv_dirty = true; + + /* Unlink the old slot */ + result = sfs_dir_unlink(sv, slot1); + if (result) { + goto puke_harder; + } + + /* + * Decrement the link count again, and mark the inode dirty again, + * in case it's been synced behind our back. + */ + KASSERT(g1->sv_i.sfi_linkcount>0); + g1->sv_i.sfi_linkcount--; + g1->sv_dirty = true; + + /* Let go of the reference to g1 */ + VOP_DECREF(&g1->sv_absvn); + + vfs_biglock_release(); + return 0; + + puke_harder: + /* + * Error recovery: try to undo what we already did + */ + result2 = sfs_dir_unlink(sv, slot2); + if (result2) { + kprintf("sfs: %s: rename: %s\n", + sfs->sfs_sb.sb_volname, strerror(result)); + kprintf("sfs: %s: rename: while cleaning up: %s\n", + sfs->sfs_sb.sb_volname, strerror(result2)); + panic("sfs: %s: rename: Cannot recover\n", + sfs->sfs_sb.sb_volname); + } + g1->sv_i.sfi_linkcount--; + puke: + /* Let go of the reference to g1 */ + VOP_DECREF(&g1->sv_absvn); + vfs_biglock_release(); + return result; +} + +/* + * lookparent returns the last path component as a string and the + * directory it's in as a vnode. + * + * Since we don't support subdirectories, this is very easy - + * return the root dir and copy the path. + */ +static +int +sfs_lookparent(struct vnode *v, char *path, struct vnode **ret, + char *buf, size_t buflen) +{ + struct sfs_vnode *sv = v->vn_data; + + vfs_biglock_acquire(); + + if (sv->sv_i.sfi_type != SFS_TYPE_DIR) { + vfs_biglock_release(); + return ENOTDIR; + } + + if (strlen(path)+1 > buflen) { + vfs_biglock_release(); + return ENAMETOOLONG; + } + strcpy(buf, path); + + VOP_INCREF(&sv->sv_absvn); + *ret = &sv->sv_absvn; + + vfs_biglock_release(); + return 0; +} + +/* + * Lookup gets a vnode for a pathname. + * + * Since we don't support subdirectories, it's easy - just look up the + * name. + */ +static +int +sfs_lookup(struct vnode *v, char *path, struct vnode **ret) +{ + struct sfs_vnode *sv = v->vn_data; + struct sfs_vnode *final; + int result; + + vfs_biglock_acquire(); + + if (sv->sv_i.sfi_type != SFS_TYPE_DIR) { + vfs_biglock_release(); + return ENOTDIR; + } + + result = sfs_lookonce(sv, path, &final, NULL); + if (result) { + vfs_biglock_release(); + return result; + } + + *ret = &final->sv_absvn; + + vfs_biglock_release(); + return 0; +} + +//////////////////////////////////////////////////////////// +// Ops tables + +/* + * Function table for sfs files. + */ +const struct vnode_ops sfs_fileops = { + .vop_magic = VOP_MAGIC, /* mark this a valid vnode ops table */ + + .vop_eachopen = sfs_eachopen, + .vop_reclaim = sfs_reclaim, + + .vop_read = sfs_read, + .vop_readlink = vopfail_uio_notdir, + .vop_getdirentry = vopfail_uio_notdir, + .vop_write = sfs_write, + .vop_ioctl = sfs_ioctl, + .vop_stat = sfs_stat, + .vop_gettype = sfs_gettype, + .vop_isseekable = sfs_isseekable, + .vop_fsync = sfs_fsync, + .vop_mmap = sfs_mmap, + .vop_truncate = sfs_truncate, + .vop_namefile = vopfail_uio_notdir, + + .vop_creat = vopfail_creat_notdir, + .vop_symlink = vopfail_symlink_notdir, + .vop_mkdir = vopfail_mkdir_notdir, + .vop_link = vopfail_link_notdir, + .vop_remove = vopfail_string_notdir, + .vop_rmdir = vopfail_string_notdir, + .vop_rename = vopfail_rename_notdir, + + .vop_lookup = vopfail_lookup_notdir, + .vop_lookparent = vopfail_lookparent_notdir, +}; + +/* + * Function table for the sfs directory. + */ +const struct vnode_ops sfs_dirops = { + .vop_magic = VOP_MAGIC, /* mark this a valid vnode ops table */ + + .vop_eachopen = sfs_eachopendir, + .vop_reclaim = sfs_reclaim, + + .vop_read = vopfail_uio_isdir, + .vop_readlink = vopfail_uio_inval, + .vop_getdirentry = vopfail_uio_nosys, + .vop_write = vopfail_uio_isdir, + .vop_ioctl = sfs_ioctl, + .vop_stat = sfs_stat, + .vop_gettype = sfs_gettype, + .vop_isseekable = sfs_isseekable, + .vop_fsync = sfs_fsync, + .vop_mmap = vopfail_mmap_isdir, + .vop_truncate = vopfail_truncate_isdir, + .vop_namefile = sfs_namefile, + + .vop_creat = sfs_creat, + .vop_symlink = vopfail_symlink_nosys, + .vop_mkdir = vopfail_mkdir_nosys, + .vop_link = sfs_link, + .vop_remove = sfs_remove, + .vop_rmdir = vopfail_string_nosys, + .vop_rename = sfs_rename, + + .vop_lookup = sfs_lookup, + .vop_lookparent = sfs_lookparent, +}; diff --git a/kern/fs/sfs/sfsprivate.h b/kern/fs/sfs/sfsprivate.h new file mode 100644 index 0000000..dd3d35c --- /dev/null +++ b/kern/fs/sfs/sfsprivate.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SFSPRIVATE_H_ +#define _SFSPRIVATE_H_ + +#include /* for uio_rw */ + + +/* ops tables (in sfs_vnops.c) */ +extern const struct vnode_ops sfs_fileops; +extern const struct vnode_ops sfs_dirops; + +/* Macro for initializing a uio structure */ +#define SFSUIO(iov, uio, ptr, block, rw) \ + uio_kinit(iov, uio, ptr, SFS_BLOCKSIZE, ((off_t)(block))*SFS_BLOCKSIZE, rw) + + +/* Functions in sfs_balloc.c */ +int sfs_balloc(struct sfs_fs *sfs, daddr_t *diskblock); +void sfs_bfree(struct sfs_fs *sfs, daddr_t diskblock); +int sfs_bused(struct sfs_fs *sfs, daddr_t diskblock); + +/* Functions in sfs_bmap.c */ +int sfs_bmap(struct sfs_vnode *sv, uint32_t fileblock, bool doalloc, + daddr_t *diskblock); +int sfs_itrunc(struct sfs_vnode *sv, off_t len); + +/* Functions in sfs_dir.c */ +int sfs_dir_findname(struct sfs_vnode *sv, const char *name, + uint32_t *ino, int *slot, int *emptyslot); +int sfs_dir_link(struct sfs_vnode *sv, const char *name, uint32_t ino, + int *slot); +int sfs_dir_unlink(struct sfs_vnode *sv, int slot); +int sfs_lookonce(struct sfs_vnode *sv, const char *name, + struct sfs_vnode **ret, + int *slot); + +/* Functions in sfs_inode.c */ +int sfs_sync_inode(struct sfs_vnode *sv); +int sfs_reclaim(struct vnode *v); +int sfs_loadvnode(struct sfs_fs *sfs, uint32_t ino, int forcetype, + struct sfs_vnode **ret); +int sfs_makeobj(struct sfs_fs *sfs, int type, struct sfs_vnode **ret); +int sfs_getroot(struct fs *fs, struct vnode **ret); + +/* Functions in sfs_io.c */ +int sfs_readblock(struct sfs_fs *sfs, daddr_t block, void *data, size_t len); +int sfs_writeblock(struct sfs_fs *sfs, daddr_t block, void *data, size_t len); +int sfs_io(struct sfs_vnode *sv, struct uio *uio); +int sfs_metaio(struct sfs_vnode *sv, off_t pos, void *data, size_t len, + enum uio_rw rw); + + +#endif /* _SFSPRIVATE_H_ */ diff --git a/kern/gdbscripts/array b/kern/gdbscripts/array new file mode 100644 index 0000000..e28f0b3 --- /dev/null +++ b/kern/gdbscripts/array @@ -0,0 +1,79 @@ +# gdb scripts for dumping resizeable arrays. +# +# Unfortunately, there does not seem to be a way to do this without +# cutting and pasting for every type. + +define plainarray + set $n = $arg0.num + set $i = 0 + printf "%u items\n", $n + while ($i < $n) + print $arg0.v[$i] + set $i++ + end +end +document plainarray +Print a plain (untyped) resizeable array. +Usage: plainarray myarray +end + +define array + set $n = $arg0.arr.num + set $i = 0 + printf "%u items\n", $n + while ($i < $n) + print $arg0.arr.v[$i] + set $i++ + end +end +document array +Print the pointers in a typed resizeable array. +(Use plainarray for an untyped resizeable array.) +Usage: array allcpus +end + +define cpuarray + set $n = $arg0.arr.num + set $i = 0 + printf "%u cpus\n", $n + while ($i < $n) + printf "cpu %u:\n", $i + print *(struct cpu *)($arg0.arr.v[$i]) + set $i++ + end +end +document cpuarray +Print an array of struct cpu. +Usage: cpuarray allcpus +end + +define threadarray + set $n = $arg0.arr.num + set $i = 0 + printf "%u threads\n", $n + while ($i < $n) + printf "thread %u:\n", $i + print *(struct thread *)($arg0.arr.v[$i]) + set $i++ + end +end +document threadarray +Print an array of struct thread. +Usage: threadarray curproc->p_threads +end + +define vnodearray + set $n = $arg0.arr.num + set $i = 0 + printf "%u vnodes\n", $n + while ($i < $n) + printf "vnode %u:\n", $i + print *(struct vnode *)($arg0.arr.v[$i]) + set $i++ + end +end +document vnodearray +Print an array of struct vnode. +Usage: vnodearray sfs->sfs_vnodes +end + diff --git a/kern/gdbscripts/mips-userland b/kern/gdbscripts/mips-userland new file mode 100644 index 0000000..0485261 --- /dev/null +++ b/kern/gdbscripts/mips-userland @@ -0,0 +1,40 @@ +# commands to interact with userland + +define load-userprogram + init-if-undefined $userprog_loaded = 0 + if !$userprog_loaded || !$_streq($arg0, $cur_userprog) + add-symbol-file $arg0 0x4000b0 + # remove after adding the new file in case add-symbol-file fails + if $userprog_loaded + remove-symbol-file -a 0x4000b0 + end + set $userprog_loaded = 1 + set $cur_userprog = $arg0 + end +end +document load-userprogram +Loads a single user program into gdb's symbol table, removing +the previous user program loaded if one exists. +Usage: load-userprogram +end +alias -a lu = load-userprogram + +define auto-userprogram + set $pname = curthread->t_proc->p_name + if $pname != 0 && $pname[0] != 0 && !$_streq($pname, "[kernel]") + if $pname[0] == '/' + set $pname = $pname + 1 + end + # This dumbness works around the fact that gdb doesn't + # expand convenience variables when you execute commands. + # And setting the third parameter to True silences the command. + python gdb.execute("load-userprogram " + str(gdb.parse_and_eval("$pname")).split()[1], False, True) + end +end +document auto-userprogram +Calls load-userprogram on whatever is curproc->p_name. It is meant +to work with kernels that set p_name to an absolute path to the +program, and it is designed to be called from hook-stop. +Usage: auto-userprogram +end + diff --git a/kern/gdbscripts/wchan b/kern/gdbscripts/wchan new file mode 100644 index 0000000..e1ace3b --- /dev/null +++ b/kern/gdbscripts/wchan @@ -0,0 +1,85 @@ +# gdb scripts for manipulating wchans + +define allwchans + set $n = allwchans.arr.num + set $i = 0 + while ($i < $n) + set $p = (struct wchan *)(allwchans.arr.v[$i]) + set $pnm = $p->wc_name + set $pth = &$p->wc_threads + set $pct = $pth->tl_count + printf "wchan %u @0x%x: %-16s %u\n", $i, $p, $pnm, $pct + set $i++ + end +end +document allwchans +Dump the allwchans table. +Usage: allwchans +end + +define wchan + set $p = (struct wchan *)(allwchans.arr.v[$arg0]) + set $pnm = $p->wc_name + set $pth = $p->wc_threads + set $pct = $pth.tl_count + printf "wchan %u @0x%x: %-16s %u:\n", $arg0, $p, $pnm, $pct + threadlist $pth +end +document wchan +Dump a particular wchan. +Usage: wchan N +(where N is the index into allwchans[] reported by allwchans) +end + +define threadlist + set $t = $arg0.tl_head.tln_next->tln_self + while ($t != 0) + printf "thread %s @0x%x\n", $t->t_name, $t + set $t = $t->t_listnode.tln_next->tln_self + end +end +document threadlist +Dump a threadlist. +Usage: threadlist mycpu->c_runqueue +end + +define allcpus + set $n = allcpus.arr.num + set $i = 0 + while ($i < $n) + set $c = (struct cpu *)(allcpus.arr.v[$i]) + set $id = $c->c_isidle + set $ln = $c->c_spinlocks + set $t = $c->c_curthread + set $zom = $c->c_zombies.tl_count + set $rn = $c->c_runqueue.tl_count + printf "cpu %u @0x%x: ", $i, $c + if ($id) + printf "idle, " + else + printf "running, " + end + printf "%u spinlocks, ", $ln + if ($t) + printf "current: %s @0x%x\n", $t->t_name, $t + else + printf "no current thread (?)\n" + end + if ($zom > 0) + printf "%u zombies:\n", $zom + threadlist $c->c_zombies + end + if ($rn > 0) + printf "%u threads in run queue:\n", $rn + threadlist $c->c_zombies + else + printf "run queue empty\n" + end + printf "\n" + set $i++ + end +end +document allcpus +Dump all cpus. +Usage: allcpus +end diff --git a/kern/include/addrspace.h b/kern/include/addrspace.h new file mode 100644 index 0000000..b1a3b7f --- /dev/null +++ b/kern/include/addrspace.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ADDRSPACE_H_ +#define _ADDRSPACE_H_ + +/* + * Address space structure and operations. + */ + + +#include +#include "opt-dumbvm.h" + +struct vnode; + + +/* + * Address space - data structure associated with the virtual memory + * space of a process. + * + * You write this. + */ + +struct addrspace { +#if OPT_DUMBVM + vaddr_t as_vbase1; + paddr_t as_pbase1; + size_t as_npages1; + vaddr_t as_vbase2; + paddr_t as_pbase2; + size_t as_npages2; + paddr_t as_stackpbase; +#else + /* Put stuff here for your VM system */ +#endif +}; + +/* + * Functions in addrspace.c: + * + * as_create - create a new empty address space. You need to make + * sure this gets called in all the right places. You + * may find you want to change the argument list. May + * return NULL on out-of-memory error. + * + * as_copy - create a new address space that is an exact copy of + * an old one. Probably calls as_create to get a new + * empty address space and fill it in, but that's up to + * you. + * + * as_activate - make curproc's address space the one currently + * "seen" by the processor. + * + * as_deactivate - unload curproc's address space so it isn't + * currently "seen" by the processor. This is used to + * avoid potentially "seeing" it while it's being + * destroyed. + * + * as_destroy - dispose of an address space. You may need to change + * the way this works if implementing user-level threads. + * + * as_define_region - set up a region of memory within the address + * space. + * + * as_prepare_load - this is called before actually loading from an + * executable into the address space. + * + * as_complete_load - this is called when loading from an executable + * is complete. + * + * as_define_stack - set up the stack region in the address space. + * (Normally called *after* as_complete_load().) Hands + * back the initial stack pointer for the new process. + * + * Note that when using dumbvm, addrspace.c is not used and these + * functions are found in dumbvm.c. + */ + +struct addrspace *as_create(void); +int as_copy(struct addrspace *src, struct addrspace **ret); +void as_activate(void); +void as_deactivate(void); +void as_destroy(struct addrspace *); + +int as_define_region(struct addrspace *as, + vaddr_t vaddr, size_t sz, + int readable, + int writeable, + int executable); +int as_prepare_load(struct addrspace *as); +int as_complete_load(struct addrspace *as); +int as_define_stack(struct addrspace *as, vaddr_t *initstackptr); + + +/* + * Functions in loadelf.c + * load_elf - load an ELF user program executable into the current + * address space. Returns the entry point (initial PC) + * in the space pointed to by ENTRYPOINT. + */ + +int load_elf(struct vnode *v, vaddr_t *entrypoint); + + +#endif /* _ADDRSPACE_H_ */ diff --git a/kern/include/array.h b/kern/include/array.h new file mode 100644 index 0000000..2b12874 --- /dev/null +++ b/kern/include/array.h @@ -0,0 +1,269 @@ +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ARRAY_H_ +#define _ARRAY_H_ + +#include +#include + +#define ARRAYS_CHECKED + +#ifdef ARRAYS_CHECKED +#define ARRAYASSERT KASSERT +#else +#define ARRAYASSERT(x) ((void)(x)) +#endif + +#ifndef ARRAYINLINE +#define ARRAYINLINE INLINE +#endif + +/* + * Base array type (resizeable array of void pointers) and operations. + * + * create - allocate an array. + * destroy - destroy an allocated array. + * init - initialize an array in space externally allocated. + * cleanup - clean up an array in space externally allocated. + * num - return number of elements in array. + * get - return element no. INDEX. + * set - set element no. INDEX to VAL. + * preallocate - allocate space without changing size; may fail and + * return error. + * setsize - change size to NUM elements; may fail and return error. + * add - append VAL to end of array; return its index in INDEX_RET if + * INDEX_RET isn't null; may fail and return error. + * remove - excise entry INDEX and slide following entries down to + * close the resulting gap. + * + * Note that expanding an array with setsize doesn't initialize the new + * elements. (Usually the caller is about to store into them anyway.) + */ + +struct array { + void **v; + unsigned num, max; +}; + +struct array *array_create(void); +void array_destroy(struct array *); +void array_init(struct array *); +void array_cleanup(struct array *); +ARRAYINLINE unsigned array_num(const struct array *); +ARRAYINLINE void *array_get(const struct array *, unsigned index); +ARRAYINLINE void array_set(const struct array *, unsigned index, void *val); +int array_preallocate(struct array *, unsigned num); +int array_setsize(struct array *, unsigned num); +ARRAYINLINE int array_add(struct array *, void *val, unsigned *index_ret); +void array_remove(struct array *, unsigned index); + +/* + * Inlining for base operations + */ + +ARRAYINLINE unsigned +array_num(const struct array *a) +{ + return a->num; +} + +ARRAYINLINE void * +array_get(const struct array *a, unsigned index) +{ + ARRAYASSERT(index < a->num); + return a->v[index]; +} + +ARRAYINLINE void +array_set(const struct array *a, unsigned index, void *val) +{ + ARRAYASSERT(index < a->num); + a->v[index] = val; +} + +ARRAYINLINE int +array_add(struct array *a, void *val, unsigned *index_ret) +{ + unsigned index; + int ret; + + index = a->num; + ret = array_setsize(a, index+1); + if (ret) { + return ret; + } + a->v[index] = val; + if (index_ret != NULL) { + *index_ret = index; + } + return 0; +} + +/* + * Bits for declaring and defining typed arrays. + * + * Usage: + * + * DECLARRAY_BYTYPE(foo, bar) declares "struct foo", which is + * an array of pointers to "bar", plus the operations on it. + * + * DECLARRAY(foo) is equivalent to DECLARRAY_BYTYPE(fooarray, struct foo). + * + * DEFARRAY_BYTYPE and DEFARRAY are the same as DECLARRAY except that + * they define the operations, and both take an extra argument INLINE. + * For C99 this should be INLINE in header files and empty in the + * master source file, the same as the usage of ARRAYINLINE above and + * in array.c. + * + * Example usage in e.g. item.h of some game: + * + * DECLARRAY_BYTYPE(stringarray, char); + * DECLARRAY(potion); + * DECLARRAY(sword); + * + * #ifndef ITEMINLINE + * #define ITEMINLINE INLINE + * #endif + * + * DEFARRAY_BYTYPE(stringarray, char, ITEMINLINE); + * DEFARRAY(potion, ITEMINLINE); + * DEFARRAY(sword, ITEMINLINE); + * + * Then item.c would do "#define ITEMINLINE" before including item.h. + * + * This creates types "struct stringarray", "struct potionarray", + * and "struct swordarray", with operations such as "swordarray_num". + * + * The operations on typed arrays are the same as the operations on + * the base array, except typed. + */ + +#define DECLARRAY_BYTYPE(ARRAY, T, INLINE) \ + struct ARRAY { \ + struct array arr; \ + }; \ + \ + INLINE struct ARRAY *ARRAY##_create(void); \ + INLINE void ARRAY##_destroy(struct ARRAY *a); \ + INLINE void ARRAY##_init(struct ARRAY *a); \ + INLINE void ARRAY##_cleanup(struct ARRAY *a); \ + INLINE unsigned ARRAY##_num(const struct ARRAY *a); \ + INLINE T *ARRAY##_get(const struct ARRAY *a, unsigned index); \ + INLINE void ARRAY##_set(struct ARRAY *a, unsigned index, T *val); \ + INLINE int ARRAY##_preallocate(struct ARRAY *a, unsigned num); \ + INLINE int ARRAY##_setsize(struct ARRAY *a, unsigned num); \ + INLINE int ARRAY##_add(struct ARRAY *a, T *val, unsigned *index_ret); \ + INLINE void ARRAY##_remove(struct ARRAY *a, unsigned index) + +#define DEFARRAY_BYTYPE(ARRAY, T, INLINE) \ + INLINE struct ARRAY * \ + ARRAY##_create(void) \ + { \ + struct ARRAY *a = kmalloc(sizeof(*a)); \ + if (a == NULL) { \ + return NULL; \ + } \ + array_init(&a->arr); \ + return a; \ + } \ + \ + INLINE void \ + ARRAY##_destroy(struct ARRAY *a) \ + { \ + array_cleanup(&a->arr); \ + kfree(a); \ + } \ + \ + INLINE void \ + ARRAY##_init(struct ARRAY *a) \ + { \ + array_init(&a->arr); \ + } \ + \ + INLINE void \ + ARRAY##_cleanup(struct ARRAY *a) \ + { \ + array_cleanup(&a->arr); \ + } \ + \ + INLINE unsigned \ + ARRAY##_num(const struct ARRAY *a) \ + { \ + return array_num(&a->arr); \ + } \ + \ + INLINE T * \ + ARRAY##_get(const struct ARRAY *a, unsigned index) \ + { \ + return (T *)array_get(&a->arr, index); \ + } \ + \ + INLINE void \ + ARRAY##_set(struct ARRAY *a, unsigned index, T *val) \ + { \ + array_set(&a->arr, index, (void *)val); \ + } \ + \ + INLINE int \ + ARRAY##_preallocate(struct ARRAY *a, unsigned num) \ + { \ + return array_preallocate(&a->arr, num); \ + } \ + \ + INLINE int \ + ARRAY##_setsize(struct ARRAY *a, unsigned num) \ + { \ + return array_setsize(&a->arr, num); \ + } \ + \ + INLINE int \ + ARRAY##_add(struct ARRAY *a, T *val, unsigned *index_ret) \ + { \ + return array_add(&a->arr, (void *)val, index_ret); \ + } \ + \ + INLINE void \ + ARRAY##_remove(struct ARRAY *a, unsigned index) \ + { \ + array_remove(&a->arr, index); \ + } + +#define DECLARRAY(T, INLINE) DECLARRAY_BYTYPE(T##array, struct T, INLINE) +#define DEFARRAY(T, INLINE) DEFARRAY_BYTYPE(T##array, struct T, INLINE) + +/* + * This is how you declare an array of strings; it works out as + * an array of pointers to char. + */ +DECLARRAY_BYTYPE(stringarray, char, ARRAYINLINE); +DEFARRAY_BYTYPE(stringarray, char, ARRAYINLINE); + + +#endif /* ARRAY_H */ diff --git a/kern/include/bitmap.h b/kern/include/bitmap.h new file mode 100644 index 0000000..d8df7ea --- /dev/null +++ b/kern/include/bitmap.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2000, 2001 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _BITMAP_H_ +#define _BITMAP_H_ + +/* + * Fixed-size array of bits. (Intended for storage management.) + * + * Functions: + * bitmap_create - allocate a new bitmap object. + * Returns NULL on error. + * bitmap_getdata - return pointer to raw bit data (for I/O). + * bitmap_alloc - locate a cleared bit, set it, and return its index. + * bitmap_mark - set a clear bit by its index. + * bitmap_unmark - clear a set bit by its index. + * bitmap_isset - return whether a particular bit is set or not. + * bitmap_destroy - destroy bitmap. + */ + + +struct bitmap; /* Opaque. */ + +struct bitmap *bitmap_create(unsigned nbits); +void *bitmap_getdata(struct bitmap *); +int bitmap_alloc(struct bitmap *, unsigned *index); +void bitmap_mark(struct bitmap *, unsigned index); +void bitmap_unmark(struct bitmap *, unsigned index); +int bitmap_isset(struct bitmap *, unsigned index); +void bitmap_destroy(struct bitmap *); + + +#endif /* _BITMAP_H_ */ diff --git a/kern/include/cdefs.h b/kern/include/cdefs.h new file mode 100644 index 0000000..194bd39 --- /dev/null +++ b/kern/include/cdefs.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2003, 2006, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _CDEFS_H_ +#define _CDEFS_H_ + +/* + * Some miscellaneous C language definitions and related matters. + */ + + +/* + * Build-time assertion. Doesn't generate any code. The error message + * on failure is less than ideal, but you can't have everything. + */ +#define COMPILE_ASSERT(x) ((void)sizeof(struct { unsigned : ((x)?1:-1); })) + + +/* + * Handy macro for the number of elements in a static array. + */ +#define ARRAYCOUNT(arr) (sizeof(arr) / sizeof((arr)[0])) + + +/* + * Tell GCC how to check printf formats. Also tell it about functions + * that don't return, as this is helpful for avoiding bogus warnings + * about uninitialized variables. + */ +#ifdef __GNUC__ +#define __PF(a,b) __attribute__((__format__(__printf__, a, b))) +#define __DEAD __attribute__((__noreturn__)) +#define __UNUSED __attribute__((__unused__)) +#else +#define __PF(a,b) +#define __DEAD +#define __UNUSED +#endif + + +/* + * Material for supporting inline functions. + * + * A function marked inline can be handled by the compiler in three + * ways: in addition to possibly inlining into the code for other + * functions, the compiler can (1) generate a file-static out-of-line + * copy of the function, (2) generate a global out-of-line copy of the + * function, or (3) generate no out-of-line copy of the function. + * + * None of these alone is thoroughly satisfactory. Since an inline + * function may or may not be inlined at the compiler's discretion, if + * no out-of-line copy exists the build may fail at link time with + * undefined symbols. Meanwhile, if the compiler is told to generate a + * global out-of-line copy, it will generate one such copy for every + * source file where the inline definition is visible; since inline + * functions tend to appear in header files, this leads to multiply + * defined symbols and build failure. The file-static option isn't + * really an improvement, either: one tends to get compiler warnings + * about inline functions that haven't been used, which for any + * particular source file tends to be at least some of the ones that + * have been defined. Furthermore, this method leads to one + * out-of-line copy of the inline function per source file that uses + * it, which not only wastes space but makes debugging painful. + * + * Therefore, we use the following scheme. + * + * In the header file containing the inline functions for the module + * "foo", we put + * + * #ifndef FOO_INLINE + * #define FOO_INLINE INLINE + * #endif + * + * where INLINE selects the compiler behavior that does *not* generate + * an out-of-line version. Then we define the inline functions + * themselves as FOO_INLINE. This allows the compiler to inline the + * functions anywhere it sees fit with a minimum of hassles. Then, + * when compiling foo.c, before including headers we put + * + * #define FOO_INLINE // empty + * + * which causes the inline functions to appear as ordinary function + * definitions, not inline at all, when foo.c is compiled. This + * ensures that an out-of-line definition appears, and furthermore + * ensures that the out-of-line definition is the same as the inline + * definition. + * + * The situation is complicated further because gcc is historically + * not compliant with the C standard. In C99, "inline" means "do not + * generate an out-of-line copy" and "extern inline" means "generate a + * global out-of-line copy". In gcc, going back far longer than C99, + * the meanings were reversed. This eventually changed, but varies + * with compiler version and options. The macro __GNUC_STDC_INLINE__ + * is defined if the behavior is C99-compliant. + * + * (Note that inline functions that appear only within a single source + * file can safely be declared "static inline"; to avoid whining from + * compiler in some contexts you may also want to add __UNUSED to + * that.) + */ +#if defined(__GNUC__) && !defined(__GNUC_STDC_INLINE__) +/* gcc's non-C99 inline semantics */ +#define INLINE extern inline + +#elif defined(__STDC__) && __STDC_VERSION__ >= 199901L +/* C99 */ +#define INLINE inline + +#else +/* something else; static inline is safest */ +#define INLINE static __UNUSED inline +#endif + + +#endif /* _CDEFS_H_ */ diff --git a/kern/include/clock.h b/kern/include/clock.h new file mode 100644 index 0000000..c80afd4 --- /dev/null +++ b/kern/include/clock.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _CLOCK_H_ +#define _CLOCK_H_ + +/* + * Time-related definitions. + */ + +#include + + +/* + * hardclock() is called on every CPU HZ times a second, possibly only + * when the CPU is not idle, for scheduling. + */ + +/* hardclocks per second */ +#define HZ 100 + +void hardclock_bootstrap(void); +void hardclock(void); + +/* + * timerclock() is called on one CPU once a second to allow simple + * timed operations. (This is a fairly simpleminded interface.) + */ +void timerclock(void); + +/* + * gettime() may be used to fetch the current time of day. + */ +void gettime(struct timespec *ret); + +/* + * arithmetic on times + * + * add: ret = t1 + t2 + * sub: ret = t1 - t2 + */ + +void timespec_add(const struct timespec *t1, + const struct timespec *t2, + struct timespec *ret); +void timespec_sub(const struct timespec *t1, + const struct timespec *t2, + struct timespec *ret); + +/* + * clocksleep() suspends execution for the requested number of seconds, + * like userlevel sleep(3). (Don't confuse it with wchan_sleep.) + */ +void clocksleep(int seconds); + + +#endif /* _CLOCK_H_ */ diff --git a/kern/include/copyinout.h b/kern/include/copyinout.h new file mode 100644 index 0000000..b6f312b --- /dev/null +++ b/kern/include/copyinout.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _COPYINOUT_H_ +#define _COPYINOUT_H_ + + +/* + * copyin/copyout/copyinstr/copyoutstr are standard BSD kernel functions. + * + * copyin copies LEN bytes from a user-space address USERSRC to a + * kernel-space address DEST. + * + * copyout copies LEN bytes from a kernel-space address SRC to a + * user-space address USERDEST. + * + * copyinstr copies a null-terminated string of at most LEN bytes from + * a user-space address USERSRC to a kernel-space address DEST, and + * returns the actual length of string found in GOT. DEST is always + * null-terminated on success. LEN and GOT include the null terminator. + * + * copyoutstr copies a null-terminated string of at most LEN bytes from + * a kernel-space address SRC to a user-space address USERDEST, and + * returns the actual length of string found in GOT. DEST is always + * null-terminated on success. LEN and GOT include the null terminator. + * + * All of these functions return 0 on success, EFAULT if a memory + * addressing error was encountered, or (for the string versions) + * ENAMETOOLONG if the space available was insufficient. + * + * NOTE that the order of the arguments is the same as bcopy() or + * cp/mv, that is, source on the left, NOT the same as strcpy(). + * The const qualifiers and types will help protect against mistakes + * in this regard but are obviously not foolproof. + * + * These functions are machine-dependent; however, a common version + * that can be used by a number of machine types is found in + * vm/copyinout.c. + */ + +int copyin(const_userptr_t usersrc, void *dest, size_t len); +int copyout(const void *src, userptr_t userdest, size_t len); +int copyinstr(const_userptr_t usersrc, char *dest, size_t len, size_t *got); +int copyoutstr(const char *src, userptr_t userdest, size_t len, size_t *got); + + +#endif /* _COPYINOUT_H_ */ diff --git a/kern/include/cpu.h b/kern/include/cpu.h new file mode 100644 index 0000000..687df77 --- /dev/null +++ b/kern/include/cpu.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _CPU_H_ +#define _CPU_H_ + + +#include +#include +#include /* for TLBSHOOTDOWN_MAX */ + + +/* + * Per-cpu structure + * + * Note: curcpu is defined by . + * + * cpu->c_self should always be used when *using* the address of curcpu + * (as opposed to merely dereferencing it) in case curcpu is defined as + * a pointer with a fixed address and a per-cpu mapping in the MMU. + */ + +struct cpu { + /* + * Fixed after allocation. + */ + struct cpu *c_self; /* Canonical address of this struct */ + unsigned c_number; /* This cpu's cpu number */ + unsigned c_hardware_number; /* Hardware-defined cpu number */ + + /* + * Accessed only by this cpu. + */ + struct thread *c_curthread; /* Current thread on cpu */ + struct threadlist c_zombies; /* List of exited threads */ + unsigned c_hardclocks; /* Counter of hardclock() calls */ + unsigned c_spinlocks; /* Counter of spinlocks held */ + + /* + * Accessed by other cpus. + * Protected by the runqueue lock. + */ + bool c_isidle; /* True if this cpu is idle */ + struct threadlist c_runqueue; /* Run queue for this cpu */ + struct spinlock c_runqueue_lock; + + /* + * Accessed by other cpus. + * Protected by the IPI lock. + * + * TLB shootdown requests made to this CPU are queued in + * c_shootdown[], with c_numshootdown holding the number of + * requests. TLBSHOOTDOWN_MAX is the maximum number that can + * be queued at once, which is machine-dependent. + * + * The contents of struct tlbshootdown are also machine- + * dependent and might reasonably be either an address space + * and vaddr pair, or a paddr, or something else. + */ + uint32_t c_ipi_pending; /* One bit for each IPI number */ + struct tlbshootdown c_shootdown[TLBSHOOTDOWN_MAX]; + unsigned c_numshootdown; + struct spinlock c_ipi_lock; + + /* + * Accessed by other cpus. Protected inside hangman.c. + */ + HANGMAN_ACTOR(c_hangman); +}; + +/* + * Initialization functions. + * + * cpu_create creates a cpu; it is suitable for calling from driver- + * or bus-specific code that looks for secondary CPUs. + * + * cpu_create calls cpu_machdep_init. + * + * cpu_start_secondary is the platform-dependent assembly language + * entry point for new CPUs; it can be found in start.S. It calls + * cpu_hatch after having claimed the startup stack and thread created + * for the cpu. + */ +struct cpu *cpu_create(unsigned hardware_number); +void cpu_machdep_init(struct cpu *); +/*ASMLINKAGE*/ void cpu_start_secondary(void); +void cpu_hatch(unsigned software_number); + +/* + * Produce a string describing the CPU type. + */ +void cpu_identify(char *buf, size_t max); + +/* + * Hardware-level interrupt on/off, for the current CPU. + * + * These should only be used by the spl code. + */ +void cpu_irqoff(void); +void cpu_irqon(void); + +/* + * Idle or shut down (respectively) the processor. + * + * cpu_idle() sits around (in a low-power state if possible) until it + * thinks something interesting may have happened, such as an + * interrupt. Then it returns. (It may be wrong, so it should always + * be called in a loop checking some other condition.) It must be + * called with interrupts off to avoid race conditions, although + * interrupts may be delivered before it returns. + * + * cpu_halt sits around (in a low-power state if possible) until the + * external reset is pushed. Interrupts should be disabled. It does + * not return. It should not allow interrupts to be delivered. + */ +void cpu_idle(void); +void cpu_halt(void); + +/* + * Interprocessor interrupts. + * + * From time to time it is necessary to poke another CPU. System + * boards of multiprocessor machines provide a way to do this. + * + * TLB shootdown is done by the VM system when more than one processor + * has (or may have) a page mapped in the MMU and it is being changed + * or otherwise needs to be invalidated across all CPUs. + * + * ipi_send sends an IPI to one CPU. + * ipi_broadcast sends an IPI to all CPUs except the current one. + * ipi_tlbshootdown is like ipi_send but carries TLB shootdown data. + * + * interprocessor_interrupt is called on the target CPU when an IPI is + * received. + */ + +/* IPI types */ +#define IPI_PANIC 0 /* System has called panic() */ +#define IPI_OFFLINE 1 /* CPU is requested to go offline */ +#define IPI_UNIDLE 2 /* Runnable threads are available */ +#define IPI_TLBSHOOTDOWN 3 /* MMU mapping(s) need invalidation */ + +void ipi_send(struct cpu *target, int code); +void ipi_broadcast(int code); +void ipi_tlbshootdown(struct cpu *target, const struct tlbshootdown *mapping); + +void interprocessor_interrupt(void); + + +#endif /* _CPU_H_ */ diff --git a/kern/include/current.h b/kern/include/current.h new file mode 100644 index 0000000..fa88971 --- /dev/null +++ b/kern/include/current.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _CURRENT_H_ +#define _CURRENT_H_ + +/* + * Definition of curcpu and curthread. + * + * The machine-dependent header should define either curcpu or curthread + * as a macro (but not both); then we use one to get the other, and include + * the header file needed to make that reference. (These includes are why + * this file isn't rolled into either cpu.h or thread.h.) + * + * This material is machine-dependent because on some platforms it is + * better/easier to keep track of curcpu and make curthread be + * curcpu->c_curthread, and on others to keep track of curthread and + * make curcpu be curthread->t_cpu. + * + * Either way we don't want retrieving curthread or curcpu to be + * expensive; digging around in system board registers and whatnot is + * not a very good idea. So we want to keep either curthread or curcpu + * on-chip somewhere in some fashion. + * + * There are various possible approaches; for example, one might use + * the MMU on each CPU to map that CPU's cpu structure to a fixed + * virtual address that's the same on all CPUs. Then curcpu can be a + * constant. (But one has to remember to use curcpu->c_self as the + * canonical form of the pointer anywhere that's visible to other + * CPUs.) On some CPUs the CPU number or cpu structure base address + * can be stored in a supervisor-mode register, where it can be set up + * during boot and then left alone. An alternative approach is to + * reserve a register to hold curthread, and update it during context + * switch. + * + * See each platform's machine/current.h for a discussion of what it + * does and why. + */ + +#include + +#if defined(__NEED_CURTHREAD) + +#include +#define curthread curcpu->c_curthread +#define CURCPU_EXISTS() (curcpu != NULL) + +#endif + +#if defined(__NEED_CURCPU) + +#include +#define curcpu curthread->t_cpu +#define CURCPU_EXISTS() (curthread != NULL) + +#endif + +/* + * Definition of curproc. + * + * curproc is always the current thread's process. + */ + +#define curproc (curthread->t_proc) + + +#endif /* _CURRENT_H_ */ diff --git a/kern/include/device.h b/kern/include/device.h new file mode 100644 index 0000000..b749351 --- /dev/null +++ b/kern/include/device.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _DEVICE_H_ +#define _DEVICE_H_ + +/* + * Devices. + */ + + +struct uio; /* in */ + +/* + * Filesystem-namespace-accessible device. + */ +struct device { + const struct device_ops *d_ops; + + blkcnt_t d_blocks; + blksize_t d_blocksize; + + dev_t d_devnumber; /* serial number for this device */ + + void *d_data; /* device-specific data */ +}; + +/* + * Device operations. + * devop_eachopen - called on each open call to allow denying the open + * devop_io - for both reads and writes (the uio indicates the direction) + * devop_ioctl - miscellaneous control operations + */ +struct device_ops { + int (*devop_eachopen)(struct device *, int flags_from_open); + int (*devop_io)(struct device *, struct uio *); + int (*devop_ioctl)(struct device *, int op, userptr_t data); +}; + +/* + * Macros to shorten the calling sequences. + */ +#define DEVOP_EACHOPEN(d, f) ((d)->d_ops->devop_eachopen(d, f)) +#define DEVOP_IO(d, u) ((d)->d_ops->devop_io(d, u)) +#define DEVOP_IOCTL(d, op, p) ((d)->d_ops->devop_ioctl(d, op, p)) + + +/* Create vnode for a vfs-level device. */ +struct vnode *dev_create_vnode(struct device *dev); + +/* Undo dev_create_vnode. */ +void dev_uncreate_vnode(struct vnode *vn); + +/* Initialization functions for builtin vfs-level devices. */ +void devnull_create(void); + +/* Function that kicks off device probe and attach. */ +void dev_bootstrap(void); + + +#endif /* _DEVICE_H_ */ diff --git a/kern/include/elf.h b/kern/include/elf.h new file mode 100644 index 0000000..7a5ae73 --- /dev/null +++ b/kern/include/elf.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ELF_H_ +#define _ELF_H_ + + +/* + * Simplified ELF definitions for OS/161 and System/161. + * + * Restrictions: + * 32-bit only + * No support for .o files or linker structures + * Does not define all the random symbols a standard elf header would. + */ + +/* Get MD bits */ +#include + + +/* + * ELF file header. This appears at the very beginning of an ELF file. + */ +#define ELF_NIDENT 16 +typedef struct { + unsigned char e_ident[ELF_NIDENT]; /* magic number et al. */ + uint16_t e_type; /* type of file this is */ + uint16_t e_machine; /* processor type file is for */ + uint32_t e_version; /* ELF version */ + uint32_t e_entry; /* address of program entry point */ + uint32_t e_phoff; /* location in file of phdrs */ + uint32_t e_shoff; /* ignore */ + uint32_t e_flags; /* ignore */ + uint16_t e_ehsize; /* actual size of file header */ + uint16_t e_phentsize; /* actual size of phdr */ + uint16_t e_phnum; /* number of phdrs */ + uint16_t e_shentsize; /* ignore */ + uint16_t e_shnum; /* ignore */ + uint16_t e_shstrndx; /* ignore */ +} Elf32_Ehdr; + +/* Offsets for the 1-byte fields within e_ident[] */ +#define EI_MAG0 0 /* '\177' */ +#define EI_MAG1 1 /* 'E' */ +#define EI_MAG2 2 /* 'L' */ +#define EI_MAG3 3 /* 'F' */ +#define EI_CLASS 4 /* File class - always ELFCLASS32 */ +#define EI_DATA 5 /* Data encoding - ELFDATA2LSB or ELFDATA2MSB*/ +#define EI_VERSION 6 /* ELF version - EV_CURRENT*/ +#define EI_OSABI 7 /* OS/syscall ABI identification */ +#define EI_ABIVERSION 8 /* syscall ABI version */ +#define EI_PAD 9 /* Start of padding bytes up to EI_NIDENT*/ + +/* Values for these fields */ + +/* For e_ident[EI_MAG0..3] */ +#define ELFMAG0 0x7f +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' + +/* For e_ident[EI_CLASS] */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ + +/* e_ident[EI_DATA] */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement values, LSB first */ +#define ELFDATA2MSB 2 /* 2's complement values, MSB first */ + +/* e_ident[EI_VERSION] */ +#define EV_NONE 0 /* Invalid version */ +#define EV_CURRENT 1 /* Current version */ + +/* e_ident[EI_OSABI] */ +#define ELFOSABI_SYSV 0 /* UNIX System V ABI */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + + +/* + * Values for e_type + */ +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 + +/* + * Values for e_machine + */ +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola 68000 */ +#define EM_88K 5 /* Motorola 88000 */ +#define EM_486 6 /* Intel 80486 */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS I Architecture */ +#define EM_S370 9 /* Amdahl UTS on System/370 */ +#define EM_MIPS_RS3_LE 10 /* MIPS RS3000 Little-endian */ +#define EM_RS6000 11 /* IBM RS/6000 XXX reserved */ +#define EM_PARISC 15 /* Hewlett-Packard PA-RISC */ +#define EM_NCUBE 16 /* NCube XXX reserved */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_V800 36 /* NEC V800 */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* Advanced RISC Machines ARM */ +#define EM_ALPHA 41 /* DIGITAL Alpha */ +#define EM_SH 42 /* Hitachi Super-H */ +#define EM_SPARCV9 43 /* SPARC Version 9 */ +#define EM_TRICORE 44 /* Siemens Tricore */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced Processor */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola MC68HC12 */ +#define EM_VAX 75 /* DIGITAL VAX */ +#define EM_ALPHA_EXP 36902 /* used by NetBSD/alpha; obsolete */ +#define EM_NUM 36903 + + +/* + * "Program Header" - runtime segment header. + * There are Ehdr.e_phnum of these located at one position within the file. + * + * Note: if p_memsz > p_filesz, the leftover space should be zero-filled. + */ +typedef struct { + uint32_t p_type; /* Type of segment */ + uint32_t p_offset; /* Location of data within file */ + uint32_t p_vaddr; /* Virtual address */ + uint32_t p_paddr; /* Ignore */ + uint32_t p_filesz; /* Size of data within file */ + uint32_t p_memsz; /* Size of data to be loaded into memory*/ + uint32_t p_flags; /* Flags */ + uint32_t p_align; /* Required alignment - can ignore */ +} Elf32_Phdr; + +/* values for p_type */ +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved, unspecified semantics */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_NUM 7 +#define PT_MIPS_REGINFO 0x70000000 + +/* values for p_flags */ +#define PF_R 0x4 /* Segment is readable */ +#define PF_W 0x2 /* Segment is writable */ +#define PF_X 0x1 /* Segment is executable */ + + +typedef Elf32_Ehdr Elf_Ehdr; +typedef Elf32_Phdr Elf_Phdr; + + +#endif /* _ELF_H_ */ diff --git a/kern/include/emufs.h b/kern/include/emufs.h new file mode 100644 index 0000000..1dbb7cb --- /dev/null +++ b/kern/include/emufs.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _EMUFS_H_ +#define _EMUFS_H_ + + +/* + * Get abstract structure definitions + */ +#include +#include + +/* + * Our structures + */ + +struct emufs_vnode { + struct vnode ev_v; /* abstract vnode structure */ + struct emu_softc *ev_emu; /* device */ + uint32_t ev_handle; /* file handle */ +}; + +struct emufs_fs { + struct fs ef_fs; /* abstract filesystem structure */ + struct emu_softc *ef_emu; /* device */ + struct emufs_vnode *ef_root; /* root vnode */ + struct vnodearray *ef_vnodes; /* table of loaded vnodes */ +}; + + +#endif /* _EMUFS_H_ */ diff --git a/kern/include/endian.h b/kern/include/endian.h new file mode 100644 index 0000000..43ef9da --- /dev/null +++ b/kern/include/endian.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ENDIAN_H_ +#define _ENDIAN_H_ + +#include + +/* + * Byte swap functions for the kernel. + */ + +uint16_t bswap16(uint16_t); +uint32_t bswap32(uint32_t); +uint64_t bswap64(uint64_t); + +uint16_t ntohs(uint16_t); +uint16_t htons(uint16_t); +uint32_t ntohl(uint32_t); +uint32_t htonl(uint32_t); +uint64_t ntohll(uint64_t); +uint64_t htonll(uint64_t); + +/* Utility functions for handling 64-bit values; see bswap.c for description */ +void join32to64(uint32_t x1, uint32_t x2, uint64_t *y2); +void split64to32(uint64_t x, uint32_t *y1, uint32_t *y2); + + +#endif /* _ENDIAN_H_ */ diff --git a/kern/include/fs.h b/kern/include/fs.h new file mode 100644 index 0000000..09e9880 --- /dev/null +++ b/kern/include/fs.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _FS_H_ +#define _FS_H_ + +struct vnode; /* in vnode.h */ + + +/* + * Abstract file system. (Or device accessible as a file.) + * + * fs_data is a pointer to filesystem-specific data. + */ + +struct fs { + void *fs_data; + const struct fs_ops *fs_ops; +}; + +/* + * Abstraction operations on a file system: + * + * fsop_sync - Flush all dirty buffers to disk. + * fsop_getvolname - Return volume name of filesystem. + * fsop_getroot - Return root vnode of filesystem. + * fsop_unmount - Attempt unmount of filesystem. + * + * fsop_getvolname may return NULL on filesystem types that don't + * support the concept of a volume name. The string returned is + * assumed to point into the filesystem's private storage and live + * until unmount time. + * + * If the volume name changes on the fly, there is no way at present + * to make sure such changes don't cause name conflicts. So it probably + * should be considered fixed. + * + * fsop_getroot should increment the refcount of the vnode returned. + * It should not ever return NULL. + * + * If fsop_unmount returns an error, the filesystem stays mounted, and + * consequently the struct fs instance should remain valid. On success, + * however, the filesystem object and all storage associated with the + * filesystem should have been discarded/released. + */ +struct fs_ops { + int (*fsop_sync)(struct fs *); + const char *(*fsop_getvolname)(struct fs *); + int (*fsop_getroot)(struct fs *, struct vnode **); + int (*fsop_unmount)(struct fs *); +}; + +/* + * Macros to shorten the calling sequences. + */ +#define FSOP_SYNC(fs) ((fs)->fs_ops->fsop_sync(fs)) +#define FSOP_GETVOLNAME(fs) ((fs)->fs_ops->fsop_getvolname(fs)) +#define FSOP_GETROOT(fs, ret) ((fs)->fs_ops->fsop_getroot(fs, ret)) +#define FSOP_UNMOUNT(fs) ((fs)->fs_ops->fsop_unmount(fs)) + +/* Initialization functions for builtin fake file systems. */ +void semfs_bootstrap(void); + + +#endif /* _FS_H_ */ diff --git a/kern/include/hangman.h b/kern/include/hangman.h new file mode 100644 index 0000000..91f3de2 --- /dev/null +++ b/kern/include/hangman.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HANGMAN_H +#define HANGMAN_H + +/* + * Simple deadlock detector. Enable with "options hangman" in the + * kernel config. + */ + +#include "opt-hangman.h" + +#if OPT_HANGMAN + +struct hangman_actor { + const char *a_name; + const struct hangman_lockable *a_waiting; +}; + +struct hangman_lockable { + const char *l_name; + const struct hangman_actor *l_holding; +}; + +void hangman_wait(struct hangman_actor *a, struct hangman_lockable *l); +void hangman_acquire(struct hangman_actor *a, struct hangman_lockable *l); +void hangman_release(struct hangman_actor *a, struct hangman_lockable *l); + +#define HANGMAN_ACTOR(sym) struct hangman_actor sym +#define HANGMAN_LOCKABLE(sym) struct hangman_lockable sym + +#define HANGMAN_ACTORINIT(a, n) ((a)->a_name = (n), (a)->a_waiting = NULL) +#define HANGMAN_LOCKABLEINIT(l, n) ((l)->l_name = (n), (l)->l_holding = NULL) + +#define HANGMAN_LOCKABLE_INITIALIZER { "spinlock", NULL } + +#define HANGMAN_WAIT(a, l) hangman_wait(a, l) +#define HANGMAN_ACQUIRE(a, l) hangman_acquire(a, l) +#define HANGMAN_RELEASE(a, l) hangman_release(a, l) + +#else + +#define HANGMAN_ACTOR(sym) +#define HANGMAN_LOCKABLE(sym) + +#define HANGMAN_ACTORINIT(a, name) +#define HANGMAN_LOCKABLEINIT(a, name) + +#define HANGMAN_LOCKABLE_INITIALIZER + +#define HANGMAN_WAIT(a, l) +#define HANGMAN_ACQUIRE(a, l) +#define HANGMAN_RELEASE(a, l) + +#endif + +#endif /* HANGMAN_H */ diff --git a/kern/include/kern/endian.h b/kern/include/kern/endian.h new file mode 100644 index 0000000..0d83e2b --- /dev/null +++ b/kern/include/kern/endian.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_ENDIAN_H_ +#define _KERN_ENDIAN_H_ + +/* + * Machine-independent and exported endianness definitions. + * + * Note: get these via in the kernel and in + * userland. + * + * This is the historic BSD way of defining endianness. + */ + +#define _LITTLE_ENDIAN 1234 +#define _BIG_ENDIAN 4321 +#define _PDP_ENDIAN 3412 + +/* This defines _BYTE_ORDER to one of the above. */ +#include + + +#endif /* _KERN_ENDIAN_H_ */ diff --git a/kern/include/kern/errmsg.h b/kern/include/kern/errmsg.h new file mode 100644 index 0000000..097b217 --- /dev/null +++ b/kern/include/kern/errmsg.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_ERRMSG_H_ +#define _KERN_ERRMSG_H_ + +/* + * Error strings. + * This table must agree with kern/errno.h. + * + * Note that since this actually defines sys_errlist and sys_nerrlist, it + * should only be included in one file. For the kernel, that file is + * lib/misc.c; for userland it's lib/libc/strerror.c. + */ +const char *const sys_errlist[] = { + "Operation succeeded", /* 0 */ + "Function not implemented", /* ENOSYS */ + "(undefined error 2)", /* unused */ + "Out of memory", /* ENOMEM */ + "Operation would block", /* EAGAIN (also EWOULDBLOCK) */ + "Interrupted system call", /* EINTR */ + "Bad memory reference", /* EFAULT */ + "String too long", /* ENAMETOOLONG */ + "Invalid argument", /* EINVAL */ + "Operation not permitted", /* EPERM */ + "Permission denied", /* EACCES */ + "Too many processes", /* EMPROC (EPROCLIM in Unix) */ + "Too many processes in system",/* ENPROC */ + "File is not executable", /* ENOEXEC */ + "Argument list too long", /* E2BIG */ + "No such process", /* ESRCH */ + "No child processes", /* ECHILD */ + "Not a directory", /* ENOTDIR */ + "Is a directory", /* EISDIR */ + "No such file or directory", /* ENOENT */ + "Too many levels of symbolic links",/* ELOOP */ + "Directory not empty", /* ENOTEMPTY */ + "File or object exists", /* EEXIST */ + "Too many hard links", /* EMLINK */ + "Cross-device link", /* EXDEV */ + "No such device", /* ENODEV */ + "Device not available", /* ENXIO */ + "Device or resource busy", /* EBUSY */ + "Too many open files", /* EMFILE */ + "Too many open files in system",/* ENFILE */ + "Bad file number", /* EBADF */ + "Invalid or inappropriate ioctl",/* EIOCTL (ENOTTY in Unix) */ + "Input/output error", /* EIO */ + "Illegal seek", /* ESPIPE */ + "Broken pipe", /* EPIPE */ + "Read-only file system", /* EROFS */ + "No space left on device", /* ENOSPC */ + "Disc quota exceeded", /* EDQUOT */ + "File too large", /* EFBIG */ + "Invalid file type or format",/* EFTYPE */ + "Argument out of range", /* EDOM */ + "Result out of range", /* ERANGE */ + "Invalid multibyte character sequence",/* EILSEQ */ + "Not a socket", /* ENOTSOCK */ + "Is a socket", /* EISSOCK (EOPNOTSUPP in Unix) */ + "Socket is already connected",/* EISCONN */ + "Socket is not connected", /* ENOTCONN */ + "Socket has been shut down", /* ESHUTDOWN */ + "Protocol family not supported",/* EPFNOSUPPORT */ + "Socket type not supported", /* ESOCKTNOSUPPORT */ + "Protocol not supported", /* EPROTONOSUPPORT */ + "Protocol wrong type for socket",/* EPROTOTYPE */ + "Address family not supported by protocol family",/* EAFNOSUPPORT */ + "Protocol option not available",/* ENOPROTOOPT */ + "Address already in use", /* EADDRINUSE */ + "Cannot assign requested address",/* EADDRNOTAVAIL */ + "Network is down", /* ENETDOWN */ + "Network is unreachable", /* ENETUNREACH */ + "Host is down", /* EHOSTDOWN */ + "Host is unreachable", /* EHOSTUNREACH */ + "Connection refused", /* ECONNREFUSED */ + "Connection timed out", /* ETIMEDOUT */ + "Connection reset by peer", /* ECONNRESET */ + "Message too large", /* EMSGSIZE */ + "Threads operation not supported",/* ENOTSUP */ +}; + +/* + * Number of entries in sys_errlist. + */ +const int sys_nerr = sizeof(sys_errlist)/sizeof(const char *); + +#endif /* _KERN_ERRMSG_H_ */ diff --git a/kern/include/kern/errno.h b/kern/include/kern/errno.h new file mode 100644 index 0000000..3c78d5e --- /dev/null +++ b/kern/include/kern/errno.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_ERRNO_H_ +#define _KERN_ERRNO_H_ + +/* + * If you change this, be sure to make appropriate corresponding changes + * to kern/errmsg.h as well. You might also want to change the man page + * for errno to document the new error. + * + * This has been changed relative to OS/161 1.x to make the grouping + * more logical. + * + * Also note that this file has to work from assembler, so it should + * contain only symbolic constants. + */ + +#define ENOSYS 1 /* Function not implemented */ +/* unused 2 */ +#define ENOMEM 3 /* Out of memory */ +#define EAGAIN 4 /* Operation would block */ +#define EINTR 5 /* Interrupted system call */ +#define EFAULT 6 /* Bad memory reference */ +#define ENAMETOOLONG 7 /* String too long */ +#define EINVAL 8 /* Invalid argument */ +#define EPERM 9 /* Operation not permitted */ +#define EACCES 10 /* Permission denied */ +#define EMPROC 11 /* Too many processes */ +#define ENPROC 12 /* Too many processes in system */ +#define ENOEXEC 13 /* File is not executable */ +#define E2BIG 14 /* Argument list too long */ +#define ESRCH 15 /* No such process */ +#define ECHILD 16 /* No child processes */ +#define ENOTDIR 17 /* Not a directory */ +#define EISDIR 18 /* Is a directory */ +#define ENOENT 19 /* No such file or directory */ +#define ELOOP 20 /* Too many levels of symbolic links */ +#define ENOTEMPTY 21 /* Directory not empty */ +#define EEXIST 22 /* File or object exists */ +#define EMLINK 23 /* Too many hard links */ +#define EXDEV 24 /* Cross-device link */ +#define ENODEV 25 /* No such device */ +#define ENXIO 26 /* Device not available */ +#define EBUSY 27 /* Device or resource busy */ +#define EMFILE 28 /* Too many open files */ +#define ENFILE 29 /* Too many open files in system */ +#define EBADF 30 /* Bad file number */ +#define EIOCTL 31 /* Invalid or inappropriate ioctl */ +#define EIO 32 /* Input/output error */ +#define ESPIPE 33 /* Illegal seek */ +#define EPIPE 34 /* Broken pipe */ +#define EROFS 35 /* Read-only file system */ +#define ENOSPC 36 /* No space left on device */ +#define EDQUOT 37 /* Disc quota exceeded */ +#define EFBIG 38 /* File too large */ +#define EFTYPE 39 /* Invalid file type or format */ +#define EDOM 40 /* Argument out of range */ +#define ERANGE 41 /* Result out of range */ +#define EILSEQ 42 /* Invalid multibyte character sequence */ +#define ENOTSOCK 43 /* Not a socket */ +#define EISSOCK 44 /* Is a socket */ +#define EISCONN 45 /* Socket is already connected */ +#define ENOTCONN 46 /* Socket is not connected */ +#define ESHUTDOWN 47 /* Socket has been shut down */ +#define EPFNOSUPPORT 48 /* Protocol family not supported */ +#define ESOCKTNOSUPPORT 49 /* Socket type not supported */ +#define EPROTONOSUPPORT 50 /* Protocol not supported */ +#define EPROTOTYPE 51 /* Protocol wrong type for socket */ +#define EAFNOSUPPORT 52 /* Address family not supported by protocol family */ +#define ENOPROTOOPT 53 /* Protocol option not available */ +#define EADDRINUSE 54 /* Address already in use */ +#define EADDRNOTAVAIL 55 /* Cannot assign requested address */ +#define ENETDOWN 56 /* Network is down */ +#define ENETUNREACH 57 /* Network is unreachable */ +#define EHOSTDOWN 58 /* Host is down */ +#define EHOSTUNREACH 59 /* Host is unreachable */ +#define ECONNREFUSED 60 /* Connection refused */ +#define ETIMEDOUT 61 /* Connection timed out */ +#define ECONNRESET 62 /* Connection reset by peer */ +#define EMSGSIZE 63 /* Message too large */ +#define ENOTSUP 64 /* Threads operation not supported */ + + +#endif /* _KERN_ERRNO_H_ */ diff --git a/kern/include/kern/fcntl.h b/kern/include/kern/fcntl.h new file mode 100644 index 0000000..4326806 --- /dev/null +++ b/kern/include/kern/fcntl.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_FCNTL_H_ +#define _KERN_FCNTL_H_ + +/* + * Constants for libc's . + */ + + +/* + * Important + */ + +/* Flags for open: choose one of these: */ +#define O_RDONLY 0 /* Open for read */ +#define O_WRONLY 1 /* Open for write */ +#define O_RDWR 2 /* Open for read and write */ +/* then or in any of these: */ +#define O_CREAT 4 /* Create file if it doesn't exist */ +#define O_EXCL 8 /* With O_CREAT, fail if file already exists */ +#define O_TRUNC 16 /* Truncate file upon open */ +#define O_APPEND 32 /* All writes happen at EOF (optional feature) */ +#define O_NOCTTY 64 /* Required by POSIX, != 0, but does nothing */ + +/* Additional related definition */ +#define O_ACCMODE 3 /* mask for O_RDONLY/O_WRONLY/O_RDWR */ + +/* + * Not so important + */ + +/* operation codes for flock() */ +#define LOCK_SH 1 /* shared lock */ +#define LOCK_EX 2 /* exclusive lock */ +#define LOCK_UN 3 /* release the lock */ +#define LOCK_NB 4 /* flag: don't block */ + +/* + * Mostly pretty useless + */ + +/* fcntl() operations */ +#define F_DUPFD 0 /* like dup() but not quite */ +#define F_GETFD 1 /* get per-handle flags */ +#define F_SETFD 2 /* set per-handle flags */ +#define F_GETFL 3 /* get per-file flags (O_* open flags) */ +#define F_SETFL 4 /* set per-file flags (O_* open flags) */ +#define F_GETOWN 5 /* get process/pgroup for SIGURG and SIGIO */ +#define F_SETOWN 6 /* set process/pgroup for SIGURG and SIGIO */ +#define F_GETLK 7 /* inspect record locks */ +#define F_SETLK 8 /* acquire record locks nonblocking */ +#define F_SETLKW 9 /* acquire record locks and wait */ + +/* flag for F_GETFD and F_SETFD */ +#define FD_CLOEXEC 1 /* close-on-exec */ + +/* modes for fcntl (F_GETLK/SETLK) locking */ +#define F_RDLCK 0 /* shared lock */ +#define F_WRLCK 1 /* exclusive lock */ +#define F_UNLCK 2 /* unlock */ + +/* struct for fcntl (F_GETLK/SETLK) locking */ +struct flock { + off_t l_start; /* place in file */ + int l_whence; /* SEEK_SET, SEEK_CUR, or SEEK_END */ + int l_type; /* F_RDLCK or F_WRLCK */ + off_t l_len; /* length of locked region */ + pid_t l_pid; /* process that holds the lock */ +}; + + +#endif /* _KERN_FCNTL_H_ */ diff --git a/kern/include/kern/ioctl.h b/kern/include/kern/ioctl.h new file mode 100644 index 0000000..f374e7e --- /dev/null +++ b/kern/include/kern/ioctl.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_IOCTL_H_ +#define _KERN_IOCTL_H_ + +/* + * ioctl operation codes + */ + +/* (none yet) */ + +#endif /* _KERN_IOCTL_H_*/ diff --git a/kern/include/kern/iovec.h b/kern/include/kern/iovec.h new file mode 100644 index 0000000..3436557 --- /dev/null +++ b/kern/include/kern/iovec.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_IOVEC_H_ +#define _KERN_IOVEC_H_ + +/* + * iovec structure, used in the readv/writev scatter/gather I/O calls, + * and within the kernel for keeping track of blocks of data for I/O. + */ + +struct iovec { + /* + * For maximum type safety, when in the kernel, distinguish + * user pointers from kernel pointers. + * + * (A pointer is a user pointer if it *came* from userspace, + * not necessarily if it *points* to userspace. If a system + * call passes 0xdeadbeef, it points to the kernel, but it's + * still a user pointer.) + * + * In userspace, there are only user pointers; also, the name + * iov_base is defined by POSIX. + * + * Note that to work properly (without extra unwanted fiddling + * around) this scheme requires that void* and userptr_t have + * the same machine representation. Machines where this isn't + * true are theoretically possible under the C standard, but + * do not exist in practice. + */ +#ifdef _KERNEL + union { + userptr_t iov_ubase; /* user-supplied pointer */ + void *iov_kbase; /* kernel-supplied pointer */ + }; +#else + void *iov_base; /* user-supplied pointer */ +#endif + size_t iov_len; /* Length of data */ +}; + +#endif /* _KERN_IOVEC_H_ */ diff --git a/kern/include/kern/limits.h b/kern/include/kern/limits.h new file mode 100644 index 0000000..8699b80 --- /dev/null +++ b/kern/include/kern/limits.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_LIMITS_H_ +#define _KERN_LIMITS_H_ + +/* + * Constants for libc's - system limits. + * + * The symbols are prefixed with __ here to avoid namespace pollution + * in libc. Use (in either userspace or the kernel) to get + * the proper names. + * + * These are Unix-style limits that Unix defines; you can change them + * around or add others as needed or as are appropriate to your system + * design. + * + * Likewise, the default values provided here are fairly reasonable, + * but you can change them around pretty freely and userspace code + * should adapt. Do change these as needed to match your + * implementation. + */ + + +/* + * Important, both as part of the system call API and for system behavior. + * + * 255 for NAME_MAX and 1024 for PATH_MAX are conventional. ARG_MAX + * should be at least 16K. In real systems it often runs to 256K or + * more. + */ + +/* Longest filename (without directory) not including null terminator */ +#define __NAME_MAX 255 + +/* Longest full path name */ +#define __PATH_MAX 1024 + +/* Max bytes for an exec function (should be at least 16K) */ +#define __ARG_MAX (64 * 1024) + + +/* + * Important for system behavior, but not a big part of the API. + * + * Most modern systems don't have OPEN_MAX at all, and instead go by + * whatever limit is set with setrlimit(). + */ + +/* Min value for a process ID (that can be assigned to a user process) */ +#define __PID_MIN 2 + +/* Max value for a process ID (change this to match your implementation) */ +#define __PID_MAX 32767 + +/* Max open files per process */ +#define __OPEN_MAX 128 + +/* Max bytes for atomic pipe I/O -- see description in the pipe() man page */ +#define __PIPE_BUF 512 + + +/* + * Not so important parts of the API. (Especially in OS/161 where we + * don't do credentials by default.) + */ + +/* Max number of supplemental group IDs in process credentials */ +#define __NGROUPS_MAX 32 + +/* Max login name size (for setlogin/getlogin), incl. null */ +#define __LOGIN_NAME_MAX 17 + + +/* + * Not very important at all. + */ + +/* Max number of iovec structures at once for readv/writev/preadv/pwritev */ +#define __IOV_MAX 1024 + + +#endif /* _KERN_LIMITS_H_ */ diff --git a/kern/include/kern/reboot.h b/kern/include/kern/reboot.h new file mode 100644 index 0000000..6130466 --- /dev/null +++ b/kern/include/kern/reboot.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_REBOOT_H_ +#define _KERN_REBOOT_H_ + +/* + * Constants for libc's and the reboot() system call. + * (Not all that important.) + */ + + +/* Codes for reboot */ +#define RB_REBOOT 0 /* Reboot system */ +#define RB_HALT 1 /* Halt system and do not reboot */ +#define RB_POWEROFF 2 /* Halt system and power off */ + + +#endif /* _KERN_REBOOT_H_ */ diff --git a/kern/include/kern/resource.h b/kern/include/kern/resource.h new file mode 100644 index 0000000..bec2c3b --- /dev/null +++ b/kern/include/kern/resource.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2004, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_RESOURCE_H_ +#define _KERN_RESOURCE_H_ + +/* + * Definitions for resource usage and limits. + * + * Not very important. + */ + + +/* priorities for setpriority() */ +#define PRIO_MIN (-20) +#define PRIO_MAX 20 + +/* "which" codes for setpriority() */ +#define PRIO_PROCESS 0 +#define PRIO_PGRP 1 +#define PRIO_USER 2 + +/* flags for getrusage() */ +#define RUSAGE_SELF 0 +#define RUSAGE_CHILDREN (-1) + +struct rusage { + struct timeval ru_utime; + struct timeval ru_stime; + __size_t ru_maxrss; /* maximum RSS during lifespan (kb) */ + __counter_t ru_ixrss; /* text memory usage (kb-ticks) */ + __counter_t ru_idrss; /* data memory usage (kb-ticks) */ + __counter_t ru_isrss; /* stack memory usage (kb-ticks) */ + __counter_t ru_minflt; /* minor VM faults (count) */ + __counter_t ru_majflt; /* major VM faults (count) */ + __counter_t ru_nswap; /* whole-process swaps (count) */ + __counter_t ru_inblock; /* file blocks read (count) */ + __counter_t ru_oublock; /* file blocks written (count) */ + __counter_t ru_msgrcv; /* socket/pipe packets rcv'd (count) */ + __counter_t ru_msgsnd; /* socket/pipe packets sent (count) */ + __counter_t ru_nsignals; /* signals delivered (count) */ + __counter_t ru_nvcsw; /* voluntary context switches (count)*/ + __counter_t ru_nivcsw; /* involuntary ditto (count) */ +}; + +/* limit codes for getrusage/setrusage */ + +#define RLIMIT_NPROC 0 /* max procs per user (count) */ +#define RLIMIT_NOFILE 1 /* max open files per proc (count) */ +#define RLIMIT_CPU 2 /* cpu usage (seconds) */ +#define RLIMIT_DATA 3 /* max .data/sbrk size (bytes) */ +#define RLIMIT_STACK 4 /* max stack size (bytes) */ +#define RLIMIT_MEMLOCK 5 /* max locked memory region (bytes) */ +#define RLIMIT_RSS 6 /* max RSS (bytes) */ +#define RLIMIT_CORE 7 /* core file size (bytes) */ +#define RLIMIT_FSIZE 8 /* max file size (bytes) */ +#define __RLIMIT_NUM 9 /* number of limits */ + +struct rlimit { + __rlim_t rlim_cur; /* soft limit */ + __rlim_t rlim_max; /* hard limit */ +}; + +#define RLIM_INFINITY (~(__rlim_t)0) + +#endif /* _KERN_RESOURCE_H_ */ diff --git a/kern/include/kern/seek.h b/kern/include/kern/seek.h new file mode 100644 index 0000000..cf1cfe6 --- /dev/null +++ b/kern/include/kern/seek.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_SEEK_H_ +#define _KERN_SEEK_H_ + +/* + * Codes for lseek(), which are shared in libc between and + * and thus get their own file. + * + * These are pretty important. Back in the day (like 20+ years ago) + * people would often just write the values 0, 1, and 2, but that's + * really not recommended. + */ + +#define SEEK_SET 0 /* Seek relative to beginning of file */ +#define SEEK_CUR 1 /* Seek relative to current position in file */ +#define SEEK_END 2 /* Seek relative to end of file */ + + +#endif /* _KERN_SEEK_H_ */ diff --git a/kern/include/kern/sfs.h b/kern/include/kern/sfs.h new file mode 100644 index 0000000..d151133 --- /dev/null +++ b/kern/include/kern/sfs.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_SFS_H_ +#define _KERN_SFS_H_ + + +/* + * SFS definitions visible to userspace. This covers the on-disk format + * and is used by tools that work on SFS volumes, such as mksfs. + */ + +#define SFS_MAGIC 0xabadf001 /* magic number identifying us */ +#define SFS_BLOCKSIZE 512 /* size of our blocks */ +#define SFS_VOLNAME_SIZE 32 /* max length of volume name */ +#define SFS_NDIRECT 15 /* # of direct blocks in inode */ +#define SFS_NINDIRECT 1 /* # of indirect blocks in inode */ +#define SFS_NDINDIRECT 0 /* # of 2x indirect blocks in inode */ +#define SFS_NTINDIRECT 0 /* # of 3x indirect blocks in inode */ +#define SFS_DBPERIDB 128 /* # direct blks per indirect blk */ +#define SFS_NAMELEN 60 /* max length of filename */ +#define SFS_SUPER_BLOCK 0 /* block the superblock lives in */ +#define SFS_FREEMAP_START 2 /* 1st block of the freemap */ +#define SFS_NOINO 0 /* inode # for free dir entry */ +#define SFS_ROOTDIR_INO 1 /* loc'n of the root dir inode */ + +/* Number of bits in a block */ +#define SFS_BITSPERBLOCK (SFS_BLOCKSIZE * CHAR_BIT) + +/* Utility macro */ +#define SFS_ROUNDUP(a,b) ((((a)+(b)-1)/(b))*b) + +/* Size of free block bitmap (in bits) */ +#define SFS_FREEMAPBITS(nblocks) SFS_ROUNDUP(nblocks, SFS_BITSPERBLOCK) + +/* Size of free block bitmap (in blocks) */ +#define SFS_FREEMAPBLOCKS(nblocks) (SFS_FREEMAPBITS(nblocks)/SFS_BITSPERBLOCK) + +/* File types for sfi_type */ +#define SFS_TYPE_INVAL 0 /* Should not appear on disk */ +#define SFS_TYPE_FILE 1 +#define SFS_TYPE_DIR 2 + +/* + * On-disk superblock + */ +struct sfs_superblock { + uint32_t sb_magic; /* Magic number; should be SFS_MAGIC */ + uint32_t sb_nblocks; /* Number of blocks in fs */ + char sb_volname[SFS_VOLNAME_SIZE]; /* Name of this volume */ + uint32_t reserved[118]; /* unused, set to 0 */ +}; + +/* + * On-disk inode + */ +struct sfs_dinode { + uint32_t sfi_size; /* Size of this file (bytes) */ + uint16_t sfi_type; /* One of SFS_TYPE_* above */ + uint16_t sfi_linkcount; /* # hard links to this file */ + uint32_t sfi_direct[SFS_NDIRECT]; /* Direct blocks */ + uint32_t sfi_indirect; /* Indirect block */ + uint32_t sfi_waste[128-3-SFS_NDIRECT]; /* unused space, set to 0 */ +}; + +/* + * On-disk directory entry + */ +struct sfs_direntry { + uint32_t sfd_ino; /* Inode number */ + char sfd_name[SFS_NAMELEN]; /* Filename */ +}; + + +#endif /* _KERN_SFS_H_ */ diff --git a/kern/include/kern/signal.h b/kern/include/kern/signal.h new file mode 100644 index 0000000..4036bb3 --- /dev/null +++ b/kern/include/kern/signal.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 1982, 1986, 1989, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)signal.h 8.4 (Berkeley) 5/4/95 + */ + +#ifndef _KERN_SIGNAL_H_ +#define _KERN_SIGNAL_H_ + +/* + * Machine-independent definitions for signals. + */ + + +/* + * The signals. + * + * The values of many of these are "well known", particularly 1, 9, + * 10, and 11. + * + * Note that Unix signals are a semantic cesspool; many have special + * properties or are supposed to interact with the system in special + * ways. It is gross. + */ + +#define SIGHUP 1 /* Hangup */ +#define SIGINT 2 /* Interrupt (^C) */ +#define SIGQUIT 3 /* Quit (typically ^\) */ +#define SIGILL 4 /* Illegal instruction */ +#define SIGTRAP 5 /* Breakpoint trap */ +#define SIGABRT 6 /* abort() call */ +#define SIGEMT 7 /* Emulator trap */ +#define SIGFPE 8 /* Floating point exception */ +#define SIGKILL 9 /* Hard kill (unblockable) */ +#define SIGBUS 10 /* Bus error, typically bad pointer alignment*/ +#define SIGSEGV 11 /* Segmentation fault */ +#define SIGSYS 12 /* Bad system call */ +#define SIGPIPE 13 /* Broken pipe */ +#define SIGALRM 14 /* alarm() expired */ +#define SIGTERM 15 /* Termination requested (default kill) */ +#define SIGURG 16 /* Urgent data on socket */ +#define SIGSTOP 17 /* Hard process stop (unblockable) */ +#define SIGTSTP 18 /* Terminal stop (^Z) */ +#define SIGCONT 19 /* Time to continue after stop */ +#define SIGCHLD 20 /* Child process exited */ +#define SIGTTIN 21 /* Stop on tty read while in background */ +#define SIGTTOU 22 /* Stop on tty write while in background */ +#define SIGIO 23 /* Nonblocking or async I/O is now ready */ +#define SIGXCPU 24 /* CPU time resource limit exceeded */ +#define SIGXFSZ 25 /* File size resource limit exceeded */ +#define SIGVTALRM 26 /* Like SIGALRM but in virtual time */ +#define SIGPROF 27 /* Profiling timer */ +#define SIGWINCH 28 /* Window size change on tty */ +#define SIGINFO 29 /* Information request (typically ^T) */ +#define SIGUSR1 20 /* Application-defined */ +#define SIGUSR2 31 /* Application-defined */ +#define SIGPWR 32 /* Power failure */ +#define _NSIG 32 + + +/* Type for a set of signals; used by e.g. sigprocmask(). */ +typedef __u32 sigset_t; + +/* flags for sigaction.sa_flags */ +#define SA_ONSTACK 1 /* Use sigaltstack() stack. */ +#define SA_RESTART 2 /* Restart syscall instead of interrupting. */ +#define SA_RESETHAND 4 /* Clear handler after one usage. */ + +/* codes for sigprocmask() */ +#define SIG_BLOCK 1 /* Block selected signals. */ +#define SIG_UNBLOCK 2 /* Unblock selected signals. */ +#define SIG_SETMASK 3 /* Set mask to the selected signals. */ + +/* Type for a signal handler function. */ +typedef void (*__sigfunc)(int); + +/* Magic values for signal handlers. */ +#define SIG_DFL ((__sigfunc) 0) /* Default behavior. */ +#define SIG_IGN ((__sigfunc) 1) /* Ignore the signal. */ + +/* + * Struct for sigaction(). + */ +struct sigaction { + __sigfunc sa_handler; + sigset_t sa_mask; + unsigned sa_flags; +}; + +/* + * Struct for sigaltstack(). + * (not very important) + */ +struct sigaltstack { + void *ss_sp; + size_t ss_size; + unsigned ss_flags; +}; + + +#endif /* _KERN_SIGNAL_H_ */ diff --git a/kern/include/kern/socket.h b/kern/include/kern/socket.h new file mode 100644 index 0000000..4796f9a --- /dev/null +++ b/kern/include/kern/socket.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2004, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_SOCKET_H_ +#define _KERN_SOCKET_H_ + +/* + * Socket-related definitions, for . + */ + + +/* + * Important + */ + +/* Socket types that we (might) support. */ +#define SOCK_STREAM 1 /* stream */ +#define SOCK_DGRAM 2 /* packet */ +#define SOCK_RAW 3 /* raw packet */ + +/* Address families that we (might) support. */ +#define AF_UNSPEC 0 +#define AF_UNIX 1 +#define AF_INET 2 +#define AF_INET6 3 + +/* Protocol families. Pointless layer of indirection in the standard API. */ +#define PF_UNSPEC AF_UNSPEC +#define PF_UNIX AF_UNIX +#define PF_INET AF_INET +#define PF_INET6 AF_INET6 + +/* + * Socket address structures. Socket addresses are polymorphic, and + * the polymorphism is handled by casting pointers. It's fairly gross, + * but way too deeply standardized to ever change. + * + * Each address family defines a sockaddr type (sockaddr_un, + * sockaddr_in, etc.) struct sockaddr is the common prefix of all + * these, and struct sockaddr_storage is defined to be large enough to + * hold any of them. + * + * The complex padding in sockaddr_storage forces it to be aligned, + * which wouldn't happen if it were just a char array. + */ + +struct sockaddr { + __u8 sa_len; + __u8 sa_family; +}; + +#define _SS_SIZE 128 +struct sockaddr_storage { + __u8 ss_len; + __u8 ss_family; + __u8 __ss_pad1; + __u8 __ss_pad2; + __u32 __ss_pad3; + __u64 __ss_pad4; + char __ss_pad5[_SS_SIZE - sizeof(__u64) - sizeof(__u32) - 4*sizeof(__u8)]; +}; + + +/* + * Not very important. + */ + +/* + * msghdr structures for sendmsg() and recvmsg(). + */ + +struct msghdr { + void *msg_name; /* really sockaddr; address, or null */ + socklen_t msg_namelen; /* size of msg_name object, or 0 */ + struct iovec *msg_iov; /* I/O buffers */ + int msg_iovlen; /* number of iovecs */ + void *msg_control; /* auxiliary data area, or null */ + socklen_t msg_controllen; /* size of msg_control area */ + int msg_flags; /* flags */ +}; + +struct cmsghdr { + socklen_t cmsg_len; /* length of control data, including header */ + int cmsg_level; /* protocol layer item originates from */ + int cmsg_type; /* protocol-specific message type */ + /* char cmsg_data[];*/ /* data follows the header */ +}; + + +#endif /* _KERN_SOCKET_H_ */ diff --git a/kern/include/kern/stat.h b/kern/include/kern/stat.h new file mode 100644 index 0000000..0f6cc54 --- /dev/null +++ b/kern/include/kern/stat.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_STAT_H_ +#define _KERN_STAT_H_ + +/* + * The stat structure, for returning file information via stat(), + * fstat(), and lstat(). + * + * Fields corresponding to things you aren't implementing should be + * set to zero. + * + * The file types are in kern/stattypes.h. + */ +struct stat { + /* Essential fields */ + off_t st_size; /* file size in bytes */ + mode_t st_mode; /* file type and protection mode */ + nlink_t st_nlink; /* number of hard links */ + blkcnt_t st_blocks; /* number of blocks file is using */ + + /* Identity */ + dev_t st_dev; /* device object lives on */ + ino_t st_ino; /* inode number (serial number) of object */ + dev_t st_rdev; /* device object is (if a device) */ + + /* Timestamps */ + time_t st_atime; /* last access time: seconds */ + time_t st_ctime; /* inode change time: seconds */ + time_t st_mtime; /* modification time: seconds */ + __u32 st_atimensec; /* last access time: nanoseconds */ + __u32 st_ctimensec; /* inode change time: nanoseconds */ + __u32 st_mtimensec; /* modification time: nanoseconds */ + + /* Permissions (also st_mode) */ + uid_t st_uid; /* owner */ + gid_t st_gid; /* group */ + + /* Other */ + __u32 st_gen; /* file generation number (root only) */ + blksize_t st_blksize; /* recommended I/O block size */ +}; + +#endif /* _KERN_STAT_H_ */ diff --git a/kern/include/kern/stattypes.h b/kern/include/kern/stattypes.h new file mode 100644 index 0000000..1192d71 --- /dev/null +++ b/kern/include/kern/stattypes.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_STATTYPES_H_ +#define _KERN_STATTYPES_H_ + +/* + * Further supporting material for stat(), fstat(), and lstat(). + * + * File types for st_mode. (The permissions are the low 12 bits.) + * + * These are also used, shifted right by those 12 bits, in struct + * dirent in libc, which is why they get their own file. + * + * Non-underscore versions of the names can be gotten from + * (kernel) or (userland). + */ + +#define _S_IFMT 070000 /* mask for type of file */ +#define _S_IFREG 010000 /* ordinary regular file */ +#define _S_IFDIR 020000 /* directory */ +#define _S_IFLNK 030000 /* symbolic link */ +#define _S_IFIFO 040000 /* pipe or named pipe */ +#define _S_IFSOCK 050000 /* socket */ +#define _S_IFCHR 060000 /* character device */ +#define _S_IFBLK 070000 /* block device */ + + +#endif /* _KERN_STATTYPES_H_ */ diff --git a/kern/include/kern/syscall.h b/kern/include/kern/syscall.h new file mode 100644 index 0000000..c9b8b2b --- /dev/null +++ b/kern/include/kern/syscall.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_SYSCALL_H_ +#define _KERN_SYSCALL_H_ + +/* + * System call numbers. + * + * To foster compatibility, this file contains a number for every + * more-or-less standard Unix system call that someone might + * conceivably implement on OS/161. The commented-out ones are ones + * we're pretty sure you won't be implementing. The others, you might + * or might not. Check your own course materials to find out what's + * specifically required of you. + * + * Caution: this file is parsed by a shell script to generate the assembly + * language system call stubs. Don't add weird stuff between the markers. + */ + +/*CALLBEGIN*/ + +// -- Process-related -- +#define SYS_fork 0 +#define SYS_vfork 1 +#define SYS_execv 2 +#define SYS__exit 3 +#define SYS_waitpid 4 +#define SYS_getpid 5 +#define SYS_getppid 6 +// (virtual memory) +#define SYS_sbrk 7 +#define SYS_mmap 8 +#define SYS_munmap 9 +#define SYS_mprotect 10 +//#define SYS_madvise 11 +//#define SYS_mincore 12 +//#define SYS_mlock 13 +//#define SYS_munlock 14 +//#define SYS_munlockall 15 +//#define SYS_minherit 16 +// (security/credentials) +#define SYS_umask 17 +#define SYS_issetugid 18 +#define SYS_getresuid 19 +#define SYS_setresuid 20 +#define SYS_getresgid 21 +#define SYS_setresgid 22 +#define SYS_getgroups 23 +#define SYS_setgroups 24 +#define SYS___getlogin 25 +#define SYS___setlogin 26 +// (signals) +#define SYS_kill 27 +#define SYS_sigaction 28 +#define SYS_sigpending 29 +#define SYS_sigprocmask 30 +#define SYS_sigsuspend 31 +#define SYS_sigreturn 32 +//#define SYS_sigaltstack 33 +// (resource tracking and usage) +//#define SYS_wait4 34 +//#define SYS_getrusage 35 +// (resource limits) +//#define SYS_getrlimit 36 +//#define SYS_setrlimit 37 +// (process priority control) +//#define SYS_getpriority 38 +//#define SYS_setpriority 39 +// (process groups, sessions, and job control) +//#define SYS_getpgid 40 +//#define SYS_setpgid 41 +//#define SYS_getsid 42 +//#define SYS_setsid 43 +// (userlevel debugging) +//#define SYS_ptrace 44 + +// -- File-handle-related -- +#define SYS_open 45 +#define SYS_pipe 46 +#define SYS_dup 47 +#define SYS_dup2 48 +#define SYS_close 49 +#define SYS_read 50 +#define SYS_pread 51 +//#define SYS_readv 52 +//#define SYS_preadv 53 +#define SYS_getdirentry 54 +#define SYS_write 55 +#define SYS_pwrite 56 +//#define SYS_writev 57 +//#define SYS_pwritev 58 +#define SYS_lseek 59 +#define SYS_flock 60 +#define SYS_ftruncate 61 +#define SYS_fsync 62 +#define SYS_fcntl 63 +#define SYS_ioctl 64 +#define SYS_select 65 +#define SYS_poll 66 + +// -- Pathname-related -- +#define SYS_link 67 +#define SYS_remove 68 +#define SYS_mkdir 69 +#define SYS_rmdir 70 +#define SYS_mkfifo 71 +#define SYS_rename 72 +#define SYS_access 73 +// (current directory) +#define SYS_chdir 74 +#define SYS_fchdir 75 +#define SYS___getcwd 76 +// (symbolic links) +#define SYS_symlink 77 +#define SYS_readlink 78 +// (mount) +#define SYS_mount 79 +#define SYS_unmount 80 + + +// -- Any-file-related -- +#define SYS_stat 81 +#define SYS_fstat 82 +#define SYS_lstat 83 +// (timestamps) +#define SYS_utimes 84 +#define SYS_futimes 85 +#define SYS_lutimes 86 +// (security/permissions) +#define SYS_chmod 87 +#define SYS_chown 88 +#define SYS_fchmod 89 +#define SYS_fchown 90 +#define SYS_lchmod 91 +#define SYS_lchown 92 +// (file system info) +//#define SYS_statfs 93 +//#define SYS_fstatfs 94 +//#define SYS_getfsstat 95 +// (POSIX dynamic system limits stuff) +//#define SYS_pathconf 96 +//#define SYS_fpathconf 97 + +// -- Sockets and networking -- +#define SYS_socket 98 +#define SYS_bind 99 +#define SYS_connect 100 +#define SYS_listen 101 +#define SYS_accept 102 +//#define SYS_socketpair 103 +#define SYS_shutdown 104 +#define SYS_getsockname 105 +#define SYS_getpeername 106 +#define SYS_getsockopt 107 +#define SYS_setsockopt 108 +//#define SYS_recvfrom 109 +//#define SYS_sendto 110 +//#define SYS_recvmsg 111 +//#define SYS_sendmsg 112 + +// -- Time-related -- +#define SYS___time 113 +#define SYS___settime 114 +#define SYS_nanosleep 115 +//#define SYS_getitimer 116 +//#define SYS_setitimer 117 + +// -- Other -- +#define SYS_sync 118 +#define SYS_reboot 119 +//#define SYS___sysctl 120 + +/*CALLEND*/ + + +#endif /* _KERN_SYSCALL_H_ */ diff --git a/kern/include/kern/time.h b/kern/include/kern/time.h new file mode 100644 index 0000000..d52076e --- /dev/null +++ b/kern/include/kern/time.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2004, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_TIME_H_ +#define _KERN_TIME_H_ + +/* + * Time-related definitions, for and others. + */ + + +/* + * Time with fractional seconds. Important. Unfortunately, to be + * compatible, we need both timeval and timespec. + */ + +struct timeval { + __time_t tv_sec; /* seconds */ + __i32 tv_usec; /* microseconds */ +}; + +struct timespec { + __time_t tv_sec; /* seconds */ + __i32 tv_nsec; /* nanoseconds */ +}; + + +/* + * Bits for interval timers. Obscure and not really that important. + */ + +/* codes for the various timers */ +#define ITIMER_REAL 0 /* Real (wall-clock) time. */ +#define ITIMER_VIRTUAL 1 /* Virtual (when process is executing) time. */ +#define ITIMER_PROF 2 /* For execution profiling. */ + +/* structure for setitimer/getitimer */ +struct itimerval { + struct timeval it_interval; /* Time to reload after expiry. */ + struct timeval it_value; /* Time to count. */ +}; + + +#endif /* _KERN_TIME_H_ */ diff --git a/kern/include/kern/types.h b/kern/include/kern/types.h new file mode 100644 index 0000000..002d3b7 --- /dev/null +++ b/kern/include/kern/types.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_TYPES_H_ +#define _KERN_TYPES_H_ + +/* Get machine-dependent types. */ +#include + +/* + * Machine-independent types visible to user level. + * + * Define everything with leading underscores to avoid polluting the C + * namespace for applications. + * + * The C standard (and additionally the POSIX standard) define rules + * for what families of symbol names are allowed to be used by + * application programmers, and what families of symbol names can be + * defined by various standard header files. The C library needs to + * conform to those rules, to the extent reasonably practical, to make + * sure that application code compiles and behaves as intended. + * + * Many of the C library's headers need to use one or more of these + * types in places where the "real" name of the type cannot be + * exposed, or expose the names of some of these types and not others. + * (For example, is supposed to define size_t, but is not + * supposed to also define e.g. pid_t.) + * + * For this reason we define everything with two underscores in front + * of it; in C such symbol names are reserved for the implementation, + * which we are, so this file can be included anywhere in any libc + * header without causing namespace problems. The "real" type names + * are defined with an additional layer of typedefs; this happens for + * the kernel in and for userland in (mostly) + * and also various other places as per relevant standards. + */ + +typedef __u32 __blkcnt_t; /* Count of blocks */ +typedef __u32 __blksize_t; /* Size of an I/O block */ +typedef __u64 __counter_t; /* Event counter */ +typedef __u32 __daddr_t; /* Disk block number */ +typedef __u32 __dev_t; /* Hardware device ID */ +typedef __u32 __fsid_t; /* Filesystem ID */ +typedef __i32 __gid_t; /* Group ID */ +typedef __u32 __in_addr_t; /* Internet address */ +typedef __u32 __in_port_t; /* Internet port number */ +typedef __u32 __ino_t; /* Inode number */ +typedef __u32 __mode_t; /* File access mode */ +typedef __u16 __nlink_t; /* Number of links (intentionally only 16 bits) */ +typedef __i64 __off_t; /* Offset within file */ +typedef __i32 __pid_t; /* Process ID */ +typedef __u64 __rlim_t; /* Resource limit quantity */ +typedef __u8 __sa_family_t;/* Socket address family */ +typedef __i64 __time_t; /* Time in seconds */ +typedef __i32 __uid_t; /* User ID */ + +typedef int __nfds_t; /* Number of file handles */ +typedef int __socklen_t; /* Socket-related length */ + +/* See note in */ +#ifdef __GNUC__ +typedef __builtin_va_list __va_list; +#endif + + +#endif /* _KERN_TYPES_H_ */ diff --git a/kern/include/kern/unistd.h b/kern/include/kern/unistd.h new file mode 100644 index 0000000..30f2678 --- /dev/null +++ b/kern/include/kern/unistd.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_UNISTD_H_ +#define _KERN_UNISTD_H_ + +/* Constants for read/write/etc: special file handles */ +#define STDIN_FILENO 0 /* Standard input */ +#define STDOUT_FILENO 1 /* Standard output */ +#define STDERR_FILENO 2 /* Standard error */ + + +#endif /* _KERN_UNISTD_H_ */ diff --git a/kern/include/kern/wait.h b/kern/include/kern/wait.h new file mode 100644 index 0000000..06ffab6 --- /dev/null +++ b/kern/include/kern/wait.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2003, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _KERN_WAIT_H_ +#define _KERN_WAIT_H_ + +/* + * Definitions for wait(). + */ + + +/* Flags for waitpid() and equivalent. */ +#define WNOHANG 1 /* Nonblocking. */ +#define WUNTRACED 2 /* Report stopping as well as exiting processes. */ + +/* Special "pids" to wait for. */ +#define WAIT_ANY (-1) /* Any child process. */ +#define WAIT_MYPGRP 0 /* Any process in the same process group. */ + +/* + * Result encoding. + * + * The lowest two bits say what happened; the rest encodes up to 30 + * bits of exit code. Note that the traditional Unix encoding, which + * is different, wastes most of the bits and can only transmit 8 bits + * of exit code... + */ +#define _WWHAT(x) ((x)&3) /* lower two bits say what happened */ +#define _WVAL(x) ((x)>>2) /* the rest is the value */ +#define _MKWVAL(x) ((x)<<2) /* encode a value */ + +/* Four things can happen... */ +#define __WEXITED 0 /* Process exited by calling _exit(). */ +#define __WSIGNALED 1 /* Process received a fatal signal. */ +#define __WCORED 2 /* Process dumped core on a fatal signal. */ +#define __WSTOPPED 3 /* Process stopped (and didn't exit). */ + +/* Test macros, used by applications. */ +#define WIFEXITED(x) (_WWHAT(x)==__WEXITED) +#define WIFSIGNALED(x) (_WWHAT(x)==__WSIGNALED || _WWHAT(x)==__WCORED) +#define WIFSTOPPED(x) (_WWHAT(x)==__WSTOPPED) +#define WEXITSTATUS(x) (_WVAL(x)) +#define WTERMSIG(x) (_WVAL(x)) +#define WSTOPSIG(x) (_WVAL(x)) +#define WCOREDUMP(x) (_WWHAT(x)==__WCORED) + +/* Encoding macros, used by the kernel to generate the wait result. */ +#define _MKWAIT_EXIT(x) (_MKWVAL(x)|__WEXITED) +#define _MKWAIT_SIG(x) (_MKWVAL(x)|__WSIGNALED) +#define _MKWAIT_CORE(x) (_MKWVAL(x)|__WCORED) +#define _MKWAIT_STOP(x) (_MKWVAL(x)|__WSTOPPED) + +#endif /* _KERN_WAIT_H_ */ diff --git a/kern/include/lib.h b/kern/include/lib.h new file mode 100644 index 0000000..66e5da3 --- /dev/null +++ b/kern/include/lib.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LIB_H_ +#define _LIB_H_ + +/* + * Miscellaneous standard C functions for the kernel, and other widely used + * kernel functions. + * + * Note: setjmp and longjmp are in . + */ + + +#include + +/* + * Assert macros. + * + * KASSERT and DEBUGASSERT are the same, except that they can be + * toggled independently. DEBUGASSERT is used in places where making + * checks is likely to be expensive and relatively unlikely to be + * helpful. + * + * Note that there's also a COMPILE_ASSERT for compile-time checks; + * it's in . + * + * Regular assertions (KASSERT) are disabled by the kernel config + * option "noasserts". DEBUGASSERT could be controlled by kernel + * config also, but since it's likely to be wanted only rarely during + * testing there doesn't seem much point; one can just edit this file + * temporarily instead. + */ +#include "opt-noasserts.h" + +#if OPT_NOASSERTS +#define KASSERT(expr) ((void)(expr)) +#else +#define KASSERT(expr) \ + ((expr) ? (void)0 : badassert(#expr, __FILE__, __LINE__, __func__)) +#endif + +#if 1 /* no debug asserts */ +#define DEBUGASSERT(expr) ((void)(expr)) +#else +#define DEBUGASSERT(expr) \ + ((expr) ? (void)0 : badassert(#expr, __FILE__, __LINE__, __func__)) +#endif + +/* + * Bit flags for DEBUG() + */ +#define DB_LOCORE 0x0001 +#define DB_SYSCALL 0x0002 +#define DB_INTERRUPT 0x0004 +#define DB_DEVICE 0x0008 +#define DB_THREADS 0x0010 +#define DB_VM 0x0020 +#define DB_EXEC 0x0040 +#define DB_VFS 0x0080 +#define DB_SEMFS 0x0100 +#define DB_SFS 0x0200 +#define DB_NET 0x0400 +#define DB_NETFS 0x0800 +#define DB_KMALLOC 0x1000 + +extern uint32_t dbflags; + +/* + * DEBUG() is for conditionally printing debug messages to the console. + * + * The idea is that you put lots of lines of the form + * + * DEBUG(DB_VM, "VM free pages: %u\n", free_pages); + * + * throughout the kernel; then you can toggle whether these messages + * are printed or not at runtime by setting the value of dbflags with + * the debugger. + * + * Unfortunately, as of this writing, there are only a very few such + * messages actually present in the system yet. Feel free to add more. + * + * DEBUG is a varargs macro. These were added to the language in C99. + */ +#define DEBUG(d, ...) ((dbflags & (d)) ? kprintf(__VA_ARGS__) : 0) + +/* + * Random number generator, using the random device. + * + * random() returns a number between 0 and randmax() inclusive. + */ +#define RANDOM_MAX (randmax()) +uint32_t randmax(void); +uint32_t random(void); + +/* + * Kernel heap memory allocation. Like malloc/free. + * If out of memory, kmalloc returns NULL. + * + * kheap_nextgeneration, dump, and dumpall do nothing unless heap + * labeling (for leak detection) in kmalloc.c (q.v.) is enabled. + */ +void *kmalloc(size_t size); +void kfree(void *ptr); +void kheap_printstats(void); +void kheap_nextgeneration(void); +void kheap_dump(void); +void kheap_dumpall(void); + +/* + * C string functions. + * + * kstrdup is like strdup, but calls kmalloc instead of malloc. + * If out of memory, it returns NULL. + */ +size_t strlen(const char *str); +int strcmp(const char *str1, const char *str2); +char *strcpy(char *dest, const char *src); +char *strcat(char *dest, const char *src); +char *kstrdup(const char *str); +char *strchr(const char *searched, int searchfor); +char *strrchr(const char *searched, int searchfor); +char *strtok_r(char *buf, const char *seps, char **context); + +void *memcpy(void *dest, const void *src, size_t len); +void *memmove(void *dest, const void *src, size_t len); +void *memset(void *block, int ch, size_t len); +void bzero(void *ptr, size_t len); +int atoi(const char *str); + +int snprintf(char *buf, size_t maxlen, const char *fmt, ...) __PF(3,4); + +const char *strerror(int errcode); + +/* + * Low-level console access. + */ +void putch(int ch); +int getch(void); +void beep(void); + +/* + * Higher-level console output. + * + * kprintf is like printf, only in the kernel. + * panic prepends the string "panic: " to the message printed, and then + * resets the system. + * badassert calls panic in a way suitable for an assertion failure. + * kgets is like gets, only with a buffer size argument. + * + * kprintf_bootstrap sets up a lock for kprintf and should be called + * during boot once malloc is available and before any additional + * threads are created. + */ +int kprintf(const char *format, ...) __PF(1,2); +__DEAD void panic(const char *format, ...) __PF(1,2); +__DEAD void badassert(const char *expr, const char *file, + int line, const char *func); + +void kgets(char *buf, size_t maxbuflen); + +void kprintf_bootstrap(void); + +/* + * Other miscellaneous stuff + */ + +#define DIVROUNDUP(a,b) (((a)+(b)-1)/(b)) +#define ROUNDUP(a,b) (DIVROUNDUP(a,b)*(b)) + + +#endif /* _LIB_H_ */ diff --git a/kern/include/limits.h b/kern/include/limits.h new file mode 100644 index 0000000..01684c4 --- /dev/null +++ b/kern/include/limits.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LIMITS_H_ +#define _LIMITS_H_ + +/* + * System limits. + */ + +/* Get the limit values, which are exported to userland with private names. */ +#include + +/* Provide the real names */ +#define NAME_MAX __NAME_MAX +#define PATH_MAX __PATH_MAX +#define ARG_MAX __ARG_MAX +#define PID_MIN __PID_MIN +#define PID_MAX __PID_MAX +#define PIPE_BUF __PIPE_BUF +#define NGROUPS_MAX __NGROUPS_MAX +#define LOGIN_NAME_MAX __LOGIN_NAME_MAX +#define OPEN_MAX __OPEN_MAX +#define IOV_MAX __IOV_MAX + +#endif /* _LIMITS_H_ */ diff --git a/kern/include/mainbus.h b/kern/include/mainbus.h new file mode 100644 index 0000000..4d7fff0 --- /dev/null +++ b/kern/include/mainbus.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MAINBUS_H_ +#define _MAINBUS_H_ + +/* + * Abstract system bus interface. + */ + + +struct cpu; /* from */ +struct trapframe; /* from */ + + +/* Initialize the system bus and probe and attach hardware devices. */ +void mainbus_bootstrap(void); + +/* Start up secondary CPUs, once their cpu structures are set up */ +void mainbus_start_cpus(void); + +/* Bus-level interrupt handler, called from cpu-level trap/interrupt code */ +void mainbus_interrupt(struct trapframe *); + +/* Find the size of main memory. */ +/* XXX this interface is not adequately MI */ +size_t mainbus_ramsize(void); + +/* Switch on an inter-processor interrupt. (Low-level.) */ +void mainbus_send_ipi(struct cpu *target); + +/* Request breaking into the debugger, where available. */ +void mainbus_debugger(void); + +/* + * The various ways to shut down the system. (These are very low-level + * and should generally not be called directly - md_poweroff, for + * instance, unceremoniously turns the power off without doing + * anything else.) + */ +void mainbus_halt(void); +void mainbus_poweroff(void); +void mainbus_reboot(void); +void mainbus_panic(void); + + +#endif /* _MAINBUS_H_ */ diff --git a/kern/include/membar.h b/kern/include/membar.h new file mode 100644 index 0000000..6152695 --- /dev/null +++ b/kern/include/membar.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _MEMBAR_H_ +#define _MEMBAR_H_ + +/* + * Memory barriers. These create ordering barriers in CPU memory + * accesses as actually issued by the CPU to the cache and memory + * system. Because superscalar CPUs can execute many instructions at + * once, they can potentially be retired in a different order from + * what's written in your code. Normally this doesn't matter, but + * sometimes it does (e.g. when writing to device registers) and in + * those cases you need to insert memory barrier instructions to + * create ordering guarantees. + * + * membar_load_load creates an ordering barrier between preceding + * loads (from memory to registers) and subsequent loads, but has + * (potentially) no effect on stores. This is what some people call a + * "load fence". + * + * membar_store_store creates an ordering barrier between preceding + * stores (from registers to memory) and subsequent stores, but has + * (potentially) no effect on loads. This is what some people call a + * "store" or "write fence". + * + * membar_store_any creates an ordering barrier between preceding + * stores and subsequent stores *and* loads. Preceding loads may be + * delayed past the barrier. This is the behavior needed for + * operations comparable to spinlock_acquire(). + * + * membar_any_store creates an ordering barrier between preceding + * loads and stores and subsequent stores. Following loads may be + * executed before the barrier. This is the behavior needed for + * operations comparable to spinlock_release(). + * + * membar_any_any creates a full ordering barrier, between preceding + * loads and stores and following loads and stores. + * + * In OS/161 we assume that the spinlock operations include any memory + * barrier instructions they require. (On many CPUs the synchronized/ + * locked instructions used to implement spinlocks are themselves + * implicit memory barriers.) You do not need to use membar_store_any + * and membar_any_store unless rolling your own lock-like objects, + * using atomic operations, implementing lock-free data structures, or + * talking to hardware devices. + * + * There is a lot of FUD about memory barriers circulating on the + * internet. Please ask your course staff if you have questions or + * concerns. + */ + +/* Inlining support - for making sure an out-of-line copy gets built */ +#ifndef MEMBAR_INLINE +#define MEMBAR_INLINE INLINE +#endif + +MEMBAR_INLINE void membar_load_load(void); +MEMBAR_INLINE void membar_store_store(void); +MEMBAR_INLINE void membar_store_any(void); +MEMBAR_INLINE void membar_any_store(void); +MEMBAR_INLINE void membar_any_any(void); + +/* Get the implementation. */ +#include + +#endif /* _MEMBAR_H_ */ diff --git a/kern/include/proc.h b/kern/include/proc.h new file mode 100644 index 0000000..f63c48c --- /dev/null +++ b/kern/include/proc.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _PROC_H_ +#define _PROC_H_ + +/* + * Definition of a process. + * + * Note: curproc is defined by . + */ + +#include + +struct addrspace; +struct thread; +struct vnode; + +/* + * Process structure. + * + * Note that we only count the number of threads in each process. + * (And, unless you implement multithreaded user processes, this + * number will not exceed 1 except in kproc.) If you want to know + * exactly which threads are in the process, e.g. for debugging, add + * an array and a sleeplock to protect it. (You can't use a spinlock + * to protect an array because arrays need to be able to call + * kmalloc.) + * + * You will most likely be adding stuff to this structure, so you may + * find you need a sleeplock in here for other reasons as well. + * However, note that p_addrspace must be protected by a spinlock: + * thread_switch needs to be able to fetch the current address space + * without sleeping. + */ +struct proc { + char *p_name; /* Name of this process */ + struct spinlock p_lock; /* Lock for this structure */ + unsigned p_numthreads; /* Number of threads in this process */ + + /* VM */ + struct addrspace *p_addrspace; /* virtual address space */ + + /* VFS */ + struct vnode *p_cwd; /* current working directory */ + + /* add more material here as needed */ +}; + +/* This is the process structure for the kernel and for kernel-only threads. */ +extern struct proc *kproc; + +/* Call once during system startup to allocate data structures. */ +void proc_bootstrap(void); + +/* Create a fresh process for use by runprogram(). */ +struct proc *proc_create_runprogram(const char *name); + +/* Destroy a process. */ +void proc_destroy(struct proc *proc); + +/* Attach a thread to a process. Must not already have a process. */ +int proc_addthread(struct proc *proc, struct thread *t); + +/* Detach a thread from its process. */ +void proc_remthread(struct thread *t); + +/* Fetch the address space of the current process. */ +struct addrspace *proc_getas(void); + +/* Change the address space of the current process, and return the old one. */ +struct addrspace *proc_setas(struct addrspace *); + + +#endif /* _PROC_H_ */ diff --git a/kern/include/setjmp.h b/kern/include/setjmp.h new file mode 100644 index 0000000..67fae47 --- /dev/null +++ b/kern/include/setjmp.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SETJMP_H_ +#define _SETJMP_H_ + +/* + * Kernel-level setjmp/longjmp. + */ + +/* Get (machine-dependent) definition of jmp_buf. */ +#include + +int setjmp(jmp_buf jb); +void longjmp(jmp_buf jb, int retval); + + +#endif /* _SETJMP_H_ */ diff --git a/kern/include/sfs.h b/kern/include/sfs.h new file mode 100644 index 0000000..3c94d74 --- /dev/null +++ b/kern/include/sfs.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SFS_H_ +#define _SFS_H_ + + +/* + * Header for SFS, the Simple File System. + */ + + +/* + * Get abstract structure definitions + */ +#include +#include + +/* + * Get on-disk structures and constants that are made available to + * userland for the benefit of mksfs, dumpsfs, etc. + */ +#include + +/* + * In-memory inode + */ +struct sfs_vnode { + struct vnode sv_absvn; /* abstract vnode structure */ + struct sfs_dinode sv_i; /* copy of on-disk inode */ + uint32_t sv_ino; /* inode number */ + bool sv_dirty; /* true if sv_i modified */ +}; + +/* + * In-memory info for a whole fs volume + */ +struct sfs_fs { + struct fs sfs_absfs; /* abstract filesystem structure */ + struct sfs_superblock sfs_sb; /* copy of on-disk superblock */ + bool sfs_superdirty; /* true if superblock modified */ + struct device *sfs_device; /* device mounted on */ + struct vnodearray *sfs_vnodes; /* vnodes loaded into memory */ + struct bitmap *sfs_freemap; /* blocks in use are marked 1 */ + bool sfs_freemapdirty; /* true if freemap modified */ +}; + +/* + * Function for mounting a sfs (calls vfs_mount) + */ +int sfs_mount(const char *device); + + +#endif /* _SFS_H_ */ diff --git a/kern/include/signal.h b/kern/include/signal.h new file mode 100644 index 0000000..215fa51 --- /dev/null +++ b/kern/include/signal.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2004, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SIGNAL_H_ +#define _SIGNAL_H_ + +/* In-kernel signal definitions. Get both the MD and MI parts. */ + +#include +#include + + +#endif /* _SIGNAL_H_ */ diff --git a/kern/include/spinlock.h b/kern/include/spinlock.h new file mode 100644 index 0000000..e28ec90 --- /dev/null +++ b/kern/include/spinlock.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SPINLOCK_H_ +#define _SPINLOCK_H_ + +/* + * Spinlocks. While the guts are machine-dependent, the structure and the + * basic functions are supposed to be the same across all machines. + */ + +#include +#include + +/* Inlining support - for making sure an out-of-line copy gets built */ +#ifndef SPINLOCK_INLINE +#define SPINLOCK_INLINE INLINE +#endif + +/* Get the machine-dependent bits. */ +#include + +/* + * Basic spinlock. + * + * Note that spinlocks are held by CPUs, not by threads. + * + * This structure is made public so spinlocks do not have to be + * malloc'd; however, code that uses spinlocks should not look inside + * the structure directly but always use the spinlock API functions. + */ +struct spinlock { + volatile spinlock_data_t splk_lock; /* Memory word where we spin. */ + struct cpu *splk_holder; /* CPU holding this lock. */ + HANGMAN_LOCKABLE(splk_hangman); /* Deadlock detector hook. */ +}; + +/* + * Initializer for cases where a spinlock needs to be static or global. + */ +#ifdef OPT_HANGMAN +#define SPINLOCK_INITIALIZER { SPINLOCK_DATA_INITIALIZER, NULL, \ + HANGMAN_LOCKABLE_INITIALIZER } +#else +#define SPINLOCK_INITIALIZER { SPINLOCK_DATA_INITIALIZER, NULL } +#endif + +/* + * Spinlock functions. + * + * init Initialize the contents of a spinlock. + * cleanup Opposite of init. Lock must be unlocked. + * + * acquire Get the lock, spinning as necessary. Also disables interrupts. + * release Release the lock. May re-enable interrupts. + * + * do_i_hold Check if the current CPU holds the lock. + */ + +void spinlock_init(struct spinlock *lk); +void spinlock_cleanup(struct spinlock *lk); + +void spinlock_acquire(struct spinlock *lk); +void spinlock_release(struct spinlock *lk); + +bool spinlock_do_i_hold(struct spinlock *lk); + + +#endif /* _SPINLOCK_H_ */ diff --git a/kern/include/spl.h b/kern/include/spl.h new file mode 100644 index 0000000..2a8d0e3 --- /dev/null +++ b/kern/include/spl.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SPL_H_ +#define _SPL_H_ + +#include + +/* Inlining support - for making sure an out-of-line copy gets built */ +#ifndef SPL_INLINE +#define SPL_INLINE INLINE +#endif + +/* + * Machine-independent interface to interrupt enable/disable. + * + * "spl" stands for "set priority level", and was originally the name of + * a VAX assembler instruction. + * + * The idea is that one can block less important interrupts while + * processing them, but still allow more urgent interrupts to interrupt + * that processing. + * + * Ordinarily there would be a whole bunch of defined interrupt + * priority levels and functions for setting them - spltty(), + * splbio(), etc., etc. But we don't support interrupt priorities in + * OS/161, so there are only three: + * + * spl0() sets IPL to 0, enabling all interrupts. + * splhigh() sets IPL to the highest value, disabling all interrupts. + * splx(s) sets IPL to S, enabling whatever state S represents. + * + * All three return the old interrupt state. Thus, these are commonly used + * as follows: + * + * int s = splhigh(); + * [ code ] + * splx(s); + * + * Note that these functions only affect interrupts on the current + * processor. + */ + +SPL_INLINE int spl0(void); +SPL_INLINE int splhigh(void); +int splx(int); + +/* + * Integer interrupt priority levels. + */ +#define IPL_NONE 0 +#define IPL_HIGH 1 + +/* + * Lower-level functions for explicitly raising and lowering + * particular interrupt levels. These are used by splx() and by the + * spinlock code. + * + * A previous setting of OLDIPL is cancelled and replaced with NEWIPL. + * + * For splraise, NEWIPL > OLDIPL, and for spllower, NEWIPL < OLDIPL. + */ +void splraise(int oldipl, int newipl); +void spllower(int oldipl, int newipl); + +//////////////////////////////////////////////////////////// + +SPL_INLINE +int +spl0(void) +{ + return splx(IPL_NONE); +} + +SPL_INLINE +int +splhigh(void) +{ + return splx(IPL_HIGH); +} + + +#endif /* _SPL_H_ */ diff --git a/kern/include/stat.h b/kern/include/stat.h new file mode 100644 index 0000000..c387576 --- /dev/null +++ b/kern/include/stat.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _STAT_H_ +#define _STAT_H_ + +/* Get the stat structure. */ +#include + +/* Get the object type macros, which are shared in libc with . */ +#include + +/* Provide non-underscore names. */ +#define S_IFMT _S_IFMT +#define S_IFREG _S_IFREG +#define S_IFDIR _S_IFDIR +#define S_IFLNK _S_IFLNK +#define S_IFIFO _S_IFIFO +#define S_IFSOCK _S_IFSOCK +#define S_IFCHR _S_IFCHR +#define S_IFBLK _S_IFBLK + + +#endif /* _STAT_H */ diff --git a/kern/include/stdarg.h b/kern/include/stdarg.h new file mode 100644 index 0000000..b4db313 --- /dev/null +++ b/kern/include/stdarg.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _STDARG_H_ +#define _STDARG_H_ + + +/* Get __PF() for declaring printf-like functions. */ +#include + +/* + * As of gcc 3.0, the stdarg declarations can be made machine- + * independent because gcc abstracts the implementations away for + * us. However, they went and changed __builtin_stdarg_start to + * __builtin_va_start sometime between gcc 4.1 and 4.8 (not sure + * when) so we need to check that. + */ + +#ifdef __GNUC__ +typedef __va_list va_list; + +#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8) +#define va_start(ap, fmt) __builtin_stdarg_start(ap, fmt) +#else +#define va_start(ap, fmt) __builtin_va_start(ap, fmt) +#endif +#define va_arg(ap,t) __builtin_va_arg(ap, t) +#define va_copy(ap1, ap2) __builtin_va_copy(ap1, ap2) +#define va_end(ap) __builtin_va_end(ap) +#endif + +/* + * The v... versions of printf functions in . This is not + * really the best place for them... but if we put them in + * we'd need to either include this file there, put these defs there, + * or split the definition of va_list into another header file, none + * of which seems entirely desirable. + */ +void vkprintf(const char *fmt, va_list ap) __PF(1,0); +int vsnprintf(char *buf, size_t maxlen, const char *fmt, va_list ap) __PF(3,0); + +/* + * The printf driver function (shared with libc). + * Does v...printf, passing the output data piecemeal to the function + * supplied. The "clientdata" argument is passed through to the function. + * The strings passed to the function might not be null-terminated; the + * supplied length should be used explicitly. + */ +int __vprintf(void (*func)(void *clientdata, const char *str, size_t len), + void *clientdata, const char *format, va_list ap) __PF(3,0); + + +#endif /* _STDARG_H_ */ diff --git a/kern/include/synch.h b/kern/include/synch.h new file mode 100644 index 0000000..0431cd3 --- /dev/null +++ b/kern/include/synch.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SYNCH_H_ +#define _SYNCH_H_ + +/* + * Header file for synchronization primitives. + */ + + +#include + +/* + * Dijkstra-style semaphore. + * + * The name field is for easier debugging. A copy of the name is made + * internally. + */ +struct semaphore { + char *sem_name; + struct wchan *sem_wchan; + struct spinlock sem_lock; + volatile unsigned sem_count; +}; + +struct semaphore *sem_create(const char *name, unsigned initial_count); +void sem_destroy(struct semaphore *); + +/* + * Operations (both atomic): + * P (proberen): decrement count. If the count is 0, block until + * the count is 1 again before decrementing. + * V (verhogen): increment count. + */ +void P(struct semaphore *); +void V(struct semaphore *); + + +/* + * Simple lock for mutual exclusion. + * + * When the lock is created, no thread should be holding it. Likewise, + * when the lock is destroyed, no thread should be holding it. + * + * The name field is for easier debugging. A copy of the name is + * (should be) made internally. + */ +struct lock { + char *lk_name; + HANGMAN_LOCKABLE(lk_hangman); /* Deadlock detector hook. */ + // add what you need here + // (don't forget to mark things volatile as needed) +}; + +struct lock *lock_create(const char *name); +void lock_destroy(struct lock *); + +/* + * Operations: + * lock_acquire - Get the lock. Only one thread can hold the lock at the + * same time. + * lock_release - Free the lock. Only the thread holding the lock may do + * this. + * lock_do_i_hold - Return true if the current thread holds the lock; + * false otherwise. + * + * These operations must be atomic. You get to write them. + */ +void lock_acquire(struct lock *); +void lock_release(struct lock *); +bool lock_do_i_hold(struct lock *); + + +/* + * Condition variable. + * + * Note that the "variable" is a bit of a misnomer: a CV is normally used + * to wait until a variable meets a particular condition, but there's no + * actual variable, as such, in the CV. + * + * These CVs are expected to support Mesa semantics, that is, no + * guarantees are made about scheduling. + * + * The name field is for easier debugging. A copy of the name is + * (should be) made internally. + */ + +struct cv { + char *cv_name; + // add what you need here + // (don't forget to mark things volatile as needed) +}; + +struct cv *cv_create(const char *name); +void cv_destroy(struct cv *); + +/* + * Operations: + * cv_wait - Release the supplied lock, go to sleep, and, after + * waking up again, re-acquire the lock. + * cv_signal - Wake up one thread that's sleeping on this CV. + * cv_broadcast - Wake up all threads sleeping on this CV. + * + * For all three operations, the current thread must hold the lock passed + * in. Note that under normal circumstances the same lock should be used + * on all operations with any particular CV. + * + * These operations must be atomic. You get to write them. + */ +void cv_wait(struct cv *cv, struct lock *lock); +void cv_signal(struct cv *cv, struct lock *lock); +void cv_broadcast(struct cv *cv, struct lock *lock); + + +#endif /* _SYNCH_H_ */ diff --git a/kern/include/syscall.h b/kern/include/syscall.h new file mode 100644 index 0000000..ad59b0f --- /dev/null +++ b/kern/include/syscall.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SYSCALL_H_ +#define _SYSCALL_H_ + + +#include /* for __DEAD */ +struct trapframe; /* from */ + +/* + * The system call dispatcher. + */ + +void syscall(struct trapframe *tf); + +/* + * Support functions. + */ + +/* Helper for fork(). You write this. */ +void enter_forked_process(struct trapframe *tf); + +/* Enter user mode. Does not return. */ +__DEAD void enter_new_process(int argc, userptr_t argv, userptr_t env, + vaddr_t stackptr, vaddr_t entrypoint); + + +/* + * Prototypes for IN-KERNEL entry points for system call implementations. + */ + +int sys_reboot(int code); +int sys___time(userptr_t user_seconds, userptr_t user_nanoseconds); + +#endif /* _SYSCALL_H_ */ diff --git a/kern/include/test.h b/kern/include/test.h new file mode 100644 index 0000000..7b02114 --- /dev/null +++ b/kern/include/test.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _TEST_H_ +#define _TEST_H_ + +/* + * Declarations for test code and other miscellaneous high-level + * functions. + */ + + +/* + * Test code. + */ + +/* data structure tests */ +int arraytest(int, char **); +int arraytest2(int, char **); +int bitmaptest(int, char **); +int threadlisttest(int, char **); + +/* thread tests */ +int threadtest(int, char **); +int threadtest2(int, char **); +int threadtest3(int, char **); +int semtest(int, char **); +int locktest(int, char **); +int cvtest(int, char **); +int cvtest2(int, char **); + +/* semaphore unit tests */ +int semu1(int, char **); +int semu2(int, char **); +int semu3(int, char **); +int semu4(int, char **); +int semu5(int, char **); +int semu6(int, char **); +int semu7(int, char **); +int semu8(int, char **); +int semu9(int, char **); +int semu10(int, char **); +int semu11(int, char **); +int semu12(int, char **); +int semu13(int, char **); +int semu14(int, char **); +int semu15(int, char **); +int semu16(int, char **); +int semu17(int, char **); +int semu18(int, char **); +int semu19(int, char **); +int semu20(int, char **); +int semu21(int, char **); +int semu22(int, char **); + +/* filesystem tests */ +int fstest(int, char **); +int readstress(int, char **); +int writestress(int, char **); +int writestress2(int, char **); +int longstress(int, char **); +int createstress(int, char **); +int printfile(int, char **); + +/* other tests */ +int kmalloctest(int, char **); +int kmallocstress(int, char **); +int kmalloctest3(int, char **); +int kmalloctest4(int, char **); +int nettest(int, char **); + +/* Routine for running a user-level program. */ +int runprogram(char *progname); + +/* Kernel menu system. */ +void menu(char *argstr); + +/* The main function, called from start.S. */ +void kmain(char *bootstring); + + +#endif /* _TEST_H_ */ diff --git a/kern/include/thread.h b/kern/include/thread.h new file mode 100644 index 0000000..8017994 --- /dev/null +++ b/kern/include/thread.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _THREAD_H_ +#define _THREAD_H_ + +/* + * Definition of a thread. + * + * Note: curthread is defined by . + */ + +#include +#include +#include + +struct cpu; + +/* get machine-dependent defs */ +#include + + +/* Size of kernel stacks; must be power of 2 */ +#define STACK_SIZE 4096 + +/* Mask for extracting the stack base address of a kernel stack pointer */ +#define STACK_MASK (~(vaddr_t)(STACK_SIZE-1)) + +/* Macro to test if two addresses are on the same kernel stack */ +#define SAME_STACK(p1, p2) (((p1) & STACK_MASK) == ((p2) & STACK_MASK)) + + +/* States a thread can be in. */ +typedef enum { + S_RUN, /* running */ + S_READY, /* ready to run */ + S_SLEEP, /* sleeping */ + S_ZOMBIE, /* zombie; exited but not yet deleted */ +} threadstate_t; + +/* Thread structure. */ +struct thread { + /* + * These go up front so they're easy to get to even if the + * debugger is messed up. + */ + char *t_name; /* Name of this thread */ + const char *t_wchan_name; /* Name of wait channel, if sleeping */ + threadstate_t t_state; /* State this thread is in */ + + /* + * Thread subsystem internal fields. + */ + struct thread_machdep t_machdep; /* Any machine-dependent goo */ + struct threadlistnode t_listnode; /* Link for run/sleep/zombie lists */ + void *t_stack; /* Kernel-level stack */ + struct switchframe *t_context; /* Saved register context (on stack) */ + struct cpu *t_cpu; /* CPU thread runs on */ + struct proc *t_proc; /* Process thread belongs to */ + HANGMAN_ACTOR(t_hangman); /* Deadlock detector hook */ + + /* + * Interrupt state fields. + * + * t_in_interrupt is true if current execution is in an + * interrupt handler, which means the thread's normal context + * of execution is stopped somewhere in the middle of doing + * something else. This makes assorted operations unsafe. + * + * See notes in spinlock.c regarding t_curspl and t_iplhigh_count. + * + * Exercise for the student: why is this material per-thread + * rather than per-cpu or global? + */ + bool t_in_interrupt; /* Are we in an interrupt? */ + int t_curspl; /* Current spl*() state */ + int t_iplhigh_count; /* # of times IPL has been raised */ + + /* + * Public fields + */ + + /* add more here as needed */ +}; + +/* + * Array of threads. + */ +#ifndef THREADINLINE +#define THREADINLINE INLINE +#endif + +DECLARRAY(thread, THREADINLINE); +DEFARRAY(thread, THREADINLINE); + +/* Call once during system startup to allocate data structures. */ +void thread_bootstrap(void); + +/* Call late in system startup to get secondary CPUs running. */ +void thread_start_cpus(void); + +/* Call during panic to stop other threads in their tracks */ +void thread_panic(void); + +/* Call during system shutdown to offline other CPUs. */ +void thread_shutdown(void); + +/* + * Make a new thread, which will start executing at "func". The thread + * will belong to the process "proc", or to the current thread's + * process if "proc" is null. The "data" arguments (one pointer, one + * number) are passed to the function. The current thread is used as a + * prototype for creating the new one. Returns an error code. The + * thread structure for the new thread is not returned; it is not in + * general safe to refer to it as the new thread may exit and + * disappear at any time without notice. + */ +int thread_fork(const char *name, struct proc *proc, + void (*func)(void *, unsigned long), + void *data1, unsigned long data2); + +/* + * Cause the current thread to exit. + * Interrupts need not be disabled. + */ +__DEAD void thread_exit(void); + +/* + * Cause the current thread to yield to the next runnable thread, but + * itself stay runnable. + * Interrupts need not be disabled. + */ +void thread_yield(void); + +/* + * Reshuffle the run queue. Called from the timer interrupt. + */ +void schedule(void); + +/* + * Potentially migrate ready threads to other CPUs. Called from the + * timer interrupt. + */ +void thread_consider_migration(void); + + +#endif /* _THREAD_H_ */ diff --git a/kern/include/threadlist.h b/kern/include/threadlist.h new file mode 100644 index 0000000..c48f2ce --- /dev/null +++ b/kern/include/threadlist.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _THREADLIST_H_ +#define _THREADLIST_H_ + + +struct thread; /* from */ + +/* + * AmigaOS-style linked list of threads. + * + * The two threadlistnodes in the threadlist structure are always on + * the list, as bookends; this removes all the special cases in the + * list handling code. However, this means that iterating starts with + * the "second" element in the list (tl_head.tln_next, or + * tl_tail.tln_prev) and it ends at the last element that's actually a + * thread. + * + * Note that this means that assigning or memcpying threadlist + * structures will break them. Don't do that... + * + * ->tln_self always points to the thread that contains the + * threadlistnode. We could avoid this if we wanted to instead use + * + * (struct thread *)((char *)node - offsetof(struct thread, t_listnode)) + * + * to get the thread pointer. But that's gross. + */ + +struct threadlistnode { + struct threadlistnode *tln_prev; + struct threadlistnode *tln_next; + struct thread *tln_self; +}; + +struct threadlist { + struct threadlistnode tl_head; + struct threadlistnode tl_tail; + unsigned tl_count; +}; + +/* Initialize and clean up a thread list node. */ +void threadlistnode_init(struct threadlistnode *tln, struct thread *self); +void threadlistnode_cleanup(struct threadlistnode *tln); + +/* Initialize and clean up a thread list. Must be empty at cleanup. */ +void threadlist_init(struct threadlist *tl); +void threadlist_cleanup(struct threadlist *tl); + +/* Check if it's empty */ +bool threadlist_isempty(struct threadlist *tl); + +/* Add and remove: at ends */ +void threadlist_addhead(struct threadlist *tl, struct thread *t); +void threadlist_addtail(struct threadlist *tl, struct thread *t); +struct thread *threadlist_remhead(struct threadlist *tl); +struct thread *threadlist_remtail(struct threadlist *tl); + +/* Add and remove: in middle. (TL is needed to maintain ->tl_count.) */ +void threadlist_insertafter(struct threadlist *tl, + struct thread *onlist, struct thread *addee); +void threadlist_insertbefore(struct threadlist *tl, + struct thread *addee, struct thread *onlist); +void threadlist_remove(struct threadlist *tl, struct thread *t); + +/* Iteration; itervar should previously be declared as (struct thread *) */ +#define THREADLIST_FORALL(itervar, tl) \ + for ((itervar) = (tl).tl_head.tln_next->tln_self; \ + (itervar) != NULL; \ + (itervar) = (itervar)->t_listnode.tln_next->tln_self) + +#define THREADLIST_FORALL_REV(itervar, tl) \ + for ((itervar) = (tl).tl_tail.tln_prev->tln_self; \ + (itervar) != NULL; \ + (itervar) = (itervar)->t_listnode.tln_prev->tln_self) + + +#endif /* _THREADLIST_H_ */ diff --git a/kern/include/threadprivate.h b/kern/include/threadprivate.h new file mode 100644 index 0000000..d07dd07 --- /dev/null +++ b/kern/include/threadprivate.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _THREADPRIVATE_H_ +#define _THREADPRIVATE_H_ + +struct thread; /* from */ +struct thread_machdep; /* from */ +struct switchframe; /* from */ + + +/* + * Subsystem-private thread defs. + * + * This file is to be used only by the thread subsystem. However, it + * has to be placed in the public include directory (rather than the + * threads directory) so the machine-dependent thread code can include + * it. This is one of the drawbacks of putting all machine-dependent + * material in a single directory: it exposes what ought to be private + * interfaces. + */ + + +/* + * Private thread functions. + */ + +/* Entry point for new threads. */ +void thread_startup(void (*entrypoint)(void *data1, unsigned long data2), + void *data1, unsigned long data2); + +/* Initialize or clean up the machine-dependent portion of struct thread */ +void thread_machdep_init(struct thread_machdep *tm); +void thread_machdep_cleanup(struct thread_machdep *tm); + +/* + * Machine-dependent functions for working on switchframes. + * + * Note that while the functions themselves are machine-dependent, their + * declarations are not. + */ + +/* Assembler-level context switch. */ +void switchframe_switch(struct switchframe **prev, struct switchframe **next); + +/* Thread initialization */ +void switchframe_init(struct thread *, + void (*entrypoint)(void *data1, unsigned long data2), + void *data1, unsigned long data2); + + +#endif /* _THREADPRIVATE_H_ */ diff --git a/kern/include/types.h b/kern/include/types.h new file mode 100644 index 0000000..ef310e0 --- /dev/null +++ b/kern/include/types.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _TYPES_H_ +#define _TYPES_H_ + +/* + * Master kernel header file. + * + * The model for the include files in the kernel is as follows: + * + * - Every source file includes this file, , first. + * + * - Every other header file may assume this file has been + * included, but should explicitly include any other headers it + * uses to compile. + * + * - Some exceptions to the previous rules exist among the headers + * exported to userland; those files should be included in the + * kernel only indirectly via other, non-exported, headers, as + * described in comments therein. + * + * - Every source or header file should include each file it + * directly uses, even if that header is included via some other + * header. This helps to prevent build failures when unrelated + * dependencies are changed around. + * + * - As a matter of convention, the ordering of include files in + * the base system is in order of subsystem dependence. That is, + * lower-level code like should come before + * higher-level code like or . This + * convention helps one to keep keep track of (and learn) the + * organization of the system. + * + * The general ordering is as follows: + * 1. + * 2. Kernel ABI definitions, e.g. . + * 3. Support code: , arrays, queues, etc. + * 4. Low-level code: locks, trapframes, etc. + * 5. Kernel subsystems: threads, VM, VFS, etc. + * 6. System call layer, e.g. , . + * + * Subsystem-private headers (the only extant example is + * switchframe.h) and then kernel option headers generated by + * config come last. + * + * There is no one perfect ordering, because the kernel is not + * composed of perfectly nested layers. But for the most part + * this principle produces a workable result. + */ + + +/* Get types visible to userland, both MI and MD. */ +#include + +/* Get machine-dependent types not visible to userland. */ +#include + +/* + * Define userptr_t as a pointer to a one-byte struct, so it won't mix + * with other pointers. + */ + +struct __userptr { char _dummy; }; +typedef struct __userptr *userptr_t; +typedef const struct __userptr *const_userptr_t; + +/* + * Proper (non-underscore) names for the types that are exposed to + * userland. + */ + +/* machine-dependent from ... */ +typedef __i8 int8_t; +typedef __i16 int16_t; +typedef __i32 int32_t; +typedef __i64 int64_t; +typedef __u8 uint8_t; +typedef __u16 uint16_t; +typedef __u32 uint32_t; +typedef __u64 uint64_t; +typedef __size_t size_t; +typedef __ssize_t ssize_t; +typedef __intptr_t intptr_t; +typedef __uintptr_t uintptr_t; +typedef __ptrdiff_t ptrdiff_t; + +/* ...and machine-independent from . */ +typedef __blkcnt_t blkcnt_t; +typedef __blksize_t blksize_t; +typedef __daddr_t daddr_t; +typedef __dev_t dev_t; +typedef __fsid_t fsid_t; +typedef __gid_t gid_t; +typedef __in_addr_t in_addr_t; +typedef __in_port_t in_port_t; +typedef __ino_t ino_t; +typedef __mode_t mode_t; +typedef __nlink_t nlink_t; +typedef __off_t off_t; +typedef __pid_t pid_t; +typedef __rlim_t rlim_t; +typedef __sa_family_t sa_family_t; +typedef __time_t time_t; +typedef __uid_t uid_t; + +typedef __nfds_t nfds_t; +typedef __socklen_t socklen_t; + +/* + * Number of bits per byte. + */ + +#define CHAR_BIT __CHAR_BIT + +/* + * Null pointer. + */ + +#define NULL ((void *)0) + +/* + * Boolean. + */ +typedef _Bool bool; +#define true 1 +#define false 0 + +#endif /* _TYPES_H_ */ diff --git a/kern/include/uio.h b/kern/include/uio.h new file mode 100644 index 0000000..4c879aa --- /dev/null +++ b/kern/include/uio.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _UIO_H_ +#define _UIO_H_ + +/* + * A uio is an abstraction encapsulating a memory block, some metadata + * about it, and also a cursor position associated with working + * through it. The uio structure is used to manage blocks of data + * moved around by the kernel. + * + * Note: struct iovec is in . + * + * The structure here is essentially the same as BSD uio. The + * position is maintained by incrementing the block pointer, + * decrementing the block size, decrementing the residue count, and + * also incrementing the seek offset in uio_offset. The last is + * intended to provide management for seek pointers. + * + * Callers of file system operations that take uios should honor the + * uio_offset values returned by these operations, as for directories + * they may not necessarily be byte counts and attempting to compute + * seek positions based on byte counts can produce wrong behavior. + * + * File system operations calling uiomove for directory data and not + * intending to use byte counts should update uio_offset to the + * desired value explicitly after calling uiomove, as uiomove always + * increments uio_offset by the number of bytes transferred. + */ + +#include + +/* Direction. */ +enum uio_rw { + UIO_READ, /* From kernel to uio_seg */ + UIO_WRITE, /* From uio_seg to kernel */ +}; + +/* Source/destination. */ +enum uio_seg { + UIO_USERISPACE, /* User process code. */ + UIO_USERSPACE, /* User process data. */ + UIO_SYSSPACE, /* Kernel. */ +}; + +struct uio { + struct iovec *uio_iov; /* Data blocks */ + unsigned uio_iovcnt; /* Number of iovecs */ + off_t uio_offset; /* Desired offset into object */ + size_t uio_resid; /* Remaining amt of data to xfer */ + enum uio_seg uio_segflg; /* What kind of pointer we have */ + enum uio_rw uio_rw; /* Whether op is a read or write */ + struct addrspace *uio_space; /* Address space for user pointer */ +}; + + +/* + * Copy data from a kernel buffer to a data region defined by a uio struct, + * updating the uio struct's offset and resid fields. May alter the iovec + * fields as well. + * + * Before calling this, you should + * (1) set up uio_iov to point to the buffer(s) you want to transfer + * to, and set uio_iovcnt to the number of such buffers; + * (2) initialize uio_offset as desired; + * (3) initialize uio_resid to the total amount of data that can be + * transferred through this uio; + * (4) set up uio_seg and uio_rw correctly; + * (5) if uio_seg is UIO_SYSSPACE, set uio_space to NULL; otherwise, + * initialize uio_space to the address space in which the buffer + * should be found. + * + * After calling, + * (1) the contents of uio_iov and uio_iovcnt may be altered and + * should not be interpreted; + * (2) uio_offset will have been incremented by the amount transferred; + * (3) uio_resid will have been decremented by the amount transferred; + * (4) uio_segflg, uio_rw, and uio_space will be unchanged. + * + * uiomove() may be called repeatedly on the same uio to transfer + * additional data until the available buffer space the uio refers to + * is exhausted. + * + * Note that the actual value of uio_offset is not interpreted. It is + * provided (and updated by uiomove) to allow for easier file seek + * pointer management. + * + * When uiomove is called, the address space presently in context must + * be the same as the one recorded in uio_space. This is an important + * sanity check if I/O has been queued. + */ +int uiomove(void *kbuffer, size_t len, struct uio *uio); + +/* + * Like uiomove, but sends zeros. + */ +int uiomovezeros(size_t len, struct uio *uio); + +/* + * Initialize a uio suitable for I/O from a kernel buffer. + * + * Usage example; + * char buf[128]; + * struct iovec iov; + * struct uio myuio; + * + * uio_kinit(&iov, &myuio, buf, sizeof(buf), 0, UIO_READ); + * result = VOP_READ(vn, &myuio); + * ... + */ +void uio_kinit(struct iovec *, struct uio *, + void *kbuf, size_t len, off_t pos, enum uio_rw rw); + + +#endif /* _UIO_H_ */ diff --git a/kern/include/version.h b/kern/include/version.h new file mode 100644 index 0000000..4d9fa1c --- /dev/null +++ b/kern/include/version.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _VERSION_H_ +#define _VERSION_H_ + +/* + * Leave this alone, so we can tell what version of the OS/161 base + * code we gave you. + */ +#define BASE_VERSION "2.0.3" + +/* + * Change this as you see fit in the course of hacking the system. + */ +#define GROUP_VERSION "0" + + +#endif /* _VERSION_H_ */ diff --git a/kern/include/vfs.h b/kern/include/vfs.h new file mode 100644 index 0000000..b4a6cc3 --- /dev/null +++ b/kern/include/vfs.h @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _VFS_H_ +#define _VFS_H_ + + +#include + + +/* + * Virtual File System layer functions. + * + * The VFS layer translates operations on abstract on-disk files or + * pathnames to operations on specific files on specific filesystems. + */ + +struct uio; /* kernel or userspace I/O buffer (uio.h) */ +struct device; /* abstract structure for a device (dev.h) */ +struct fs; /* abstract structure for a filesystem (fs.h) */ +struct vnode; /* abstract structure for an on-disk file (vnode.h) */ + +/* + * VFS layer low-level operations. + * See vnode.h for direct operations on vnodes. + * See fs.h for direct operations on filesystems/devices. + * + * vfs_setcurdir - change current directory of current thread by vnode + * vfs_clearcurdir - change current directory of current thread to "none" + * vfs_getcurdir - retrieve vnode of current directory of current thread + * vfs_sync - force all dirty buffers to disk + * vfs_getroot - get root vnode for the filesystem named DEVNAME + * vfs_getdevname - get mounted device name for the filesystem passed in + */ + +int vfs_setcurdir(struct vnode *dir); +int vfs_clearcurdir(void); +int vfs_getcurdir(struct vnode **retdir); +int vfs_sync(void); +int vfs_getroot(const char *devname, struct vnode **result); +const char *vfs_getdevname(struct fs *fs); + +/* + * VFS layer mid-level operations. + * + * vfs_lookup - Like VOP_LOOKUP, but takes a full device:path name, + * or a name relative to the current directory, and + * goes to the correct filesystem. + * vfs_lookparent - Likewise, for VOP_LOOKPARENT. + * + * Both of these may destroy the path passed in. + */ + +int vfs_lookup(char *path, struct vnode **result); +int vfs_lookparent(char *path, struct vnode **result, + char *buf, size_t buflen); + +/* + * VFS layer high-level operations on pathnames + * Because lookup may destroy pathnames, these all may too. + * + * vfs_open - Open or create a file. FLAGS/MODE per the syscall. + * vfs_readlink - Read contents of a symlink into a uio. + * vfs_symlink - Create a symlink PATH containing contents CONTENTS. + * vfs_mkdir - Create a directory. MODE per the syscall. + * vfs_link - Create a hard link to a file. + * vfs_remove - Delete a file. + * vfs_rmdir - Delete a directory. + * vfs_rename - rename a file. + * + * vfs_chdir - Change current directory of current thread by name. + * vfs_getcwd - Retrieve name of current directory of current thread. + * + * vfs_close - Close a vnode opened with vfs_open. Does not fail. + * (See vfspath.c for a discussion of why.) + */ + +int vfs_open(char *path, int openflags, mode_t mode, struct vnode **ret); +void vfs_close(struct vnode *vn); +int vfs_readlink(char *path, struct uio *data); +int vfs_symlink(const char *contents, char *path); +int vfs_mkdir(char *path, mode_t mode); +int vfs_link(char *oldpath, char *newpath); +int vfs_remove(char *path); +int vfs_rmdir(char *path); +int vfs_rename(char *oldpath, char *newpath); + +int vfs_chdir(char *path); +int vfs_getcwd(struct uio *buf); + +/* + * Misc + * + * vfs_bootstrap - Call during system initialization to allocate + * structures. + * + * vfs_setbootfs - Set the filesystem that paths beginning with a + * slash are sent to. If not set, these paths fail + * with ENOENT. The argument should be the device + * name or volume name for the filesystem (such as + * "lhd0:") but need not have the trailing colon. + * + * vfs_clearbootfs - Clear the bootfs filesystem. This should be + * done during shutdown so that the filesystem in + * question can be unmounted. + * + * vfs_adddev - Add a device to the VFS named device list. If + * MOUNTABLE is zero, the device will be accessible + * as "DEVNAME:". If the mountable flag is set, the + * device will be accessible as "DEVNAMEraw:" and + * mountable under the name "DEVNAME". Thus, the + * console, added with MOUNTABLE not set, would be + * accessed by pathname as "con:", and lhd0, added + * with mountable set, would be accessed by + * pathname as "lhd0raw:" and mounted by passing + * "lhd0" to vfs_mount. + * + * vfs_addfs - Add a hardwired filesystem to the VFS named device + * list. It will be accessible as "devname:". This is + * intended for filesystem-devices like emufs, and + * gizmos like Linux procfs or BSD kernfs, not for + * mounting filesystems on disk devices. + * + * vfs_mount - Attempt to mount a filesystem on a device. The + * device named by DEVNAME will be looked up and + * passed, along with DATA, to the supplied function + * MOUNTFUNC, which should create a struct fs and + * return it in RESULT. + * + * vfs_unmount - Unmount the filesystem presently mounted on the + * specified device. + * + * vfs_swapon - Look up DEVNAME and mark it as a swap device, + * returning a vnode. Similar to vfs_mount. + * + * vfs_swapoff - Unmark DEVNAME as a swap device. The vnode + * previously returned by vfs_swapon should be + * decref'd first. Similar to vfs_unmount. + * + * vfs_unmountall - Unmount all mounted filesystems. + */ + +void vfs_bootstrap(void); + +int vfs_setbootfs(const char *fsname); +void vfs_clearbootfs(void); + +int vfs_adddev(const char *devname, struct device *dev, int mountable); +int vfs_addfs(const char *devname, struct fs *fs); + +int vfs_mount(const char *devname, void *data, + int (*mountfunc)(void *data, + struct device *dev, + struct fs **result)); +int vfs_unmount(const char *devname); +int vfs_swapon(const char *devname, struct vnode **result); +int vfs_swapoff(const char *devname); +int vfs_unmountall(void); + +/* + * Array of vnodes. + */ +#ifndef VFSINLINE +#define VFSINLINE INLINE +#endif + +DECLARRAY(vnode, VFSINLINE); +DEFARRAY(vnode, VFSINLINE); + +/* + * Global one-big-lock for all filesystem operations. + * You must remove this for the filesystem assignment. + */ +void vfs_biglock_acquire(void); +void vfs_biglock_release(void); +bool vfs_biglock_do_i_hold(void); + + +#endif /* _VFS_H_ */ diff --git a/kern/include/vm.h b/kern/include/vm.h new file mode 100644 index 0000000..abc0cfe --- /dev/null +++ b/kern/include/vm.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _VM_H_ +#define _VM_H_ + +/* + * VM system-related definitions. + * + * You'll probably want to add stuff here. + */ + + +#include + +/* Fault-type arguments to vm_fault() */ +#define VM_FAULT_READ 0 /* A read was attempted */ +#define VM_FAULT_WRITE 1 /* A write was attempted */ +#define VM_FAULT_READONLY 2 /* A write to a readonly page was attempted*/ + + +/* Initialization function */ +void vm_bootstrap(void); + +/* Fault handling function called by trap code */ +int vm_fault(int faulttype, vaddr_t faultaddress); + +/* Allocate/free kernel heap pages (called by kmalloc/kfree) */ +vaddr_t alloc_kpages(unsigned npages); +void free_kpages(vaddr_t addr); + +/* TLB shootdown handling called from interprocessor_interrupt */ +void vm_tlbshootdown(const struct tlbshootdown *); + + +#endif /* _VM_H_ */ diff --git a/kern/include/vnode.h b/kern/include/vnode.h new file mode 100644 index 0000000..a29ae9a --- /dev/null +++ b/kern/include/vnode.h @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _VNODE_H_ +#define _VNODE_H_ + +#include +struct uio; +struct stat; + + +/* + * A struct vnode is an abstract representation of a file. + * + * It is an interface in the Java sense that allows the kernel's + * filesystem-independent code to interact usefully with multiple sets + * of filesystem code. + */ + +/* + * Abstract low-level file. + * + * Note: vn_fs may be null if the vnode refers to a device. + */ +struct vnode { + int vn_refcount; /* Reference count */ + struct spinlock vn_countlock; /* Lock for vn_refcount */ + + struct fs *vn_fs; /* Filesystem vnode belongs to */ + + void *vn_data; /* Filesystem-specific data */ + + const struct vnode_ops *vn_ops; /* Functions on this vnode */ +}; + +/* + * Abstract operations on a vnode. + * + * These are used in the form VOP_FOO(vnode, args), which are macros + * that expands to vnode->vn_ops->vop_foo(vnode, args). The operations + * "foo" are: + * + * vop_eachopen - Called on *each* open() of a file. Can be used to + * reject illegal or undesired open modes. Note that + * various operations can be performed without the + * file actually being opened. + * The vnode need not look at O_CREAT, O_EXCL, or + * O_TRUNC, as these are handled in the VFS layer. + * + * VOP_EACHOPEN should not be called directly from + * above the VFS layer - use vfs_open() to open vnodes. + * + * vop_reclaim - Called when vnode is no longer in use. + * + ***************************************** + * + * vop_read - Read data from file to uio, at offset specified + * in the uio, updating uio_resid to reflect the + * amount read, and updating uio_offset to match. + * Not allowed on directories or symlinks. + * + * vop_readlink - Read the contents of a symlink into a uio. + * Not allowed on other types of object. + * + * vop_getdirentry - Read a single filename from a directory into a + * uio, choosing what name based on the offset + * field in the uio, and updating that field. + * Unlike with I/O on regular files, the value of + * the offset field is not interpreted outside + * the filesystem and thus need not be a byte + * count. However, the uio_resid field should be + * handled in the normal fashion. + * On non-directory objects, return ENOTDIR. + * + * vop_write - Write data from uio to file at offset specified + * in the uio, updating uio_resid to reflect the + * amount written, and updating uio_offset to match. + * Not allowed on directories or symlinks. + * + * vop_ioctl - Perform ioctl operation OP on file using data + * DATA. The interpretation of the data is specific + * to each ioctl. + * + * vop_stat - Return info about a file. The pointer is a + * pointer to struct stat; see kern/stat.h. + * + * vop_gettype - Return type of file. The values for file types + * are in kern/stattypes.h. + * + * vop_isseekable - Check if this file is seekable. All regular files + * and directories are seekable, but some devices are + * not. + * + * vop_fsync - Force any dirty buffers associated with this file + * to stable storage. + * + * vop_mmap - Map file into memory. If you implement this + * feature, you're responsible for choosing the + * arguments for this operation. + * + * vop_truncate - Forcibly set size of file to the length passed + * in, discarding any excess blocks. + * + * vop_namefile - Compute pathname relative to filesystem root + * of the file and copy to the specified + * uio. Need not work on objects that are not + * directories. + * + ***************************************** + * + * vop_creat - Create a regular file named NAME in the passed + * directory DIR. If boolean EXCL is true, fail if + * the file already exists; otherwise, use the + * existing file if there is one. Hand back the + * vnode for the file as per vop_lookup. + * + * vop_symlink - Create symlink named NAME in the passed directory, + * with contents CONTENTS. + * + * vop_mkdir - Make directory NAME in the passed directory PARENTDIR. + * + * vop_link - Create hard link, with name NAME, to file FILE + * in the passed directory DIR. + * + * vop_remove - Delete non-directory object NAME from passed + * directory. If NAME refers to a directory, + * return EISDIR. If passed vnode is not a + * directory, return ENOTDIR. + * + * vop_rmdir - Delete directory object NAME from passed + * directory. + * + * vop_rename - Rename file NAME1 in directory VN1 to be + * file NAME2 in directory VN2. + * + ***************************************** + * + * vop_lookup - Parse PATHNAME relative to the passed directory + * DIR, and hand back the vnode for the file it + * refers to. May destroy PATHNAME. Should increment + * refcount on vnode handed back. + * + * vop_lookparent - Parse PATHNAME relative to the passed directory + * DIR, and hand back (1) the vnode for the + * parent directory of the file it refers to, and + * (2) the last component of the filename, copied + * into kernel buffer BUF with max length LEN. May + * destroy PATHNAME. Should increment refcount on + * vnode handed back. + */ + +#define VOP_MAGIC 0xa2b3c4d5 + +struct vnode_ops { + unsigned long vop_magic; /* should always be VOP_MAGIC */ + + int (*vop_eachopen)(struct vnode *object, int flags_from_open); + int (*vop_reclaim)(struct vnode *vnode); + + + int (*vop_read)(struct vnode *file, struct uio *uio); + int (*vop_readlink)(struct vnode *link, struct uio *uio); + int (*vop_getdirentry)(struct vnode *dir, struct uio *uio); + int (*vop_write)(struct vnode *file, struct uio *uio); + int (*vop_ioctl)(struct vnode *object, int op, userptr_t data); + int (*vop_stat)(struct vnode *object, struct stat *statbuf); + int (*vop_gettype)(struct vnode *object, mode_t *result); + bool (*vop_isseekable)(struct vnode *object); + int (*vop_fsync)(struct vnode *object); + int (*vop_mmap)(struct vnode *file /* add stuff */); + int (*vop_truncate)(struct vnode *file, off_t len); + int (*vop_namefile)(struct vnode *file, struct uio *uio); + + + int (*vop_creat)(struct vnode *dir, + const char *name, bool excl, mode_t mode, + struct vnode **result); + int (*vop_symlink)(struct vnode *dir, + const char *contents, const char *name); + int (*vop_mkdir)(struct vnode *parentdir, + const char *name, mode_t mode); + int (*vop_link)(struct vnode *dir, + const char *name, struct vnode *file); + int (*vop_remove)(struct vnode *dir, + const char *name); + int (*vop_rmdir)(struct vnode *dir, + const char *name); + + int (*vop_rename)(struct vnode *vn1, const char *name1, + struct vnode *vn2, const char *name2); + + + int (*vop_lookup)(struct vnode *dir, + char *pathname, struct vnode **result); + int (*vop_lookparent)(struct vnode *dir, + char *pathname, struct vnode **result, + char *buf, size_t len); +}; + +#define __VOP(vn, sym) (vnode_check(vn, #sym), (vn)->vn_ops->vop_##sym) + +#define VOP_EACHOPEN(vn, flags) (__VOP(vn, eachopen)(vn, flags)) +#define VOP_RECLAIM(vn) (__VOP(vn, reclaim)(vn)) + +#define VOP_READ(vn, uio) (__VOP(vn, read)(vn, uio)) +#define VOP_READLINK(vn, uio) (__VOP(vn, readlink)(vn, uio)) +#define VOP_GETDIRENTRY(vn, uio) (__VOP(vn,getdirentry)(vn, uio)) +#define VOP_WRITE(vn, uio) (__VOP(vn, write)(vn, uio)) +#define VOP_IOCTL(vn, code, buf) (__VOP(vn, ioctl)(vn,code,buf)) +#define VOP_STAT(vn, ptr) (__VOP(vn, stat)(vn, ptr)) +#define VOP_GETTYPE(vn, result) (__VOP(vn, gettype)(vn, result)) +#define VOP_ISSEEKABLE(vn) (__VOP(vn, isseekable)(vn)) +#define VOP_FSYNC(vn) (__VOP(vn, fsync)(vn)) +#define VOP_MMAP(vn /*add stuff */) (__VOP(vn, mmap)(vn /*add stuff */)) +#define VOP_TRUNCATE(vn, pos) (__VOP(vn, truncate)(vn, pos)) +#define VOP_NAMEFILE(vn, uio) (__VOP(vn, namefile)(vn, uio)) + +#define VOP_CREAT(vn,nm,excl,mode,res) (__VOP(vn, creat)(vn,nm,excl,mode,res)) +#define VOP_SYMLINK(vn, name, content) (__VOP(vn, symlink)(vn, name, content)) +#define VOP_MKDIR(vn, name, mode) (__VOP(vn, mkdir)(vn, name, mode)) +#define VOP_LINK(vn, name, vn2) (__VOP(vn, link)(vn, name, vn2)) +#define VOP_REMOVE(vn, name) (__VOP(vn, remove)(vn, name)) +#define VOP_RMDIR(vn, name) (__VOP(vn, rmdir)(vn, name)) +#define VOP_RENAME(vn1,name1,vn2,name2)(__VOP(vn1,rename)(vn1,name1,vn2,name2)) + +#define VOP_LOOKUP(vn, name, res) (__VOP(vn, lookup)(vn, name, res)) +#define VOP_LOOKPARENT(vn,nm,res,bf,ln) (__VOP(vn,lookparent)(vn,nm,res,bf,ln)) + +/* + * Consistency check + */ +void vnode_check(struct vnode *, const char *op); + +/* + * Reference count manipulation (handled above filesystem level) + */ +void vnode_incref(struct vnode *); +void vnode_decref(struct vnode *); + +#define VOP_INCREF(vn) vnode_incref(vn) +#define VOP_DECREF(vn) vnode_decref(vn) + +/* + * Vnode initialization (intended for use by filesystem code) + * The reference count is initialized to 1. + */ +int vnode_init(struct vnode *, const struct vnode_ops *ops, + struct fs *fs, void *fsdata); + +/* + * Vnode final cleanup (intended for use by filesystem code) + * The reference count is asserted to be 1. + */ +void vnode_cleanup(struct vnode *); + +/* + * Common stubs for vnode functions that just fail, in various ways. + */ +int vopfail_uio_notdir(struct vnode *vn, struct uio *uio); +int vopfail_uio_isdir(struct vnode *vn, struct uio *uio); +int vopfail_uio_inval(struct vnode *vn, struct uio *uio); +int vopfail_uio_nosys(struct vnode *vn, struct uio *uio); +int vopfail_mmap_isdir(struct vnode *vn /* add stuff */); +int vopfail_mmap_perm(struct vnode *vn /* add stuff */); +int vopfail_mmap_nosys(struct vnode *vn /* add stuff */); +int vopfail_truncate_isdir(struct vnode *vn, off_t pos); +int vopfail_creat_notdir(struct vnode *vn, const char *name, bool excl, + mode_t mode, struct vnode **result); +int vopfail_symlink_notdir(struct vnode *vn, const char *contents, + const char *name); +int vopfail_symlink_nosys(struct vnode *vn, const char *contents, + const char *name); +int vopfail_mkdir_notdir(struct vnode *vn, const char *name, mode_t mode); +int vopfail_mkdir_nosys(struct vnode *vn, const char *name, mode_t mode); +int vopfail_link_notdir(struct vnode *dir, const char *name, + struct vnode *file); +int vopfail_link_nosys(struct vnode *dir, const char *name, + struct vnode *file); +int vopfail_string_notdir(struct vnode *vn, const char *name); +int vopfail_string_nosys(struct vnode *vn, const char *name); +int vopfail_rename_notdir(struct vnode *fromdir, const char *fromname, + struct vnode *todir, const char *toname); +int vopfail_rename_nosys(struct vnode *fromdir, const char *fromname, + struct vnode *todir, const char *toname); +int vopfail_lookup_notdir(struct vnode *vn, char *path, struct vnode **result); +int vopfail_lookparent_notdir(struct vnode *vn, char *path, + struct vnode **result, char *buf, size_t len); + + +#endif /* _VNODE_H_ */ diff --git a/kern/include/wchan.h b/kern/include/wchan.h new file mode 100644 index 0000000..8009598 --- /dev/null +++ b/kern/include/wchan.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _WCHAN_H_ +#define _WCHAN_H_ + +/* + * Wait channel. + */ + + +struct spinlock; /* in spinlock.h */ +struct wchan; /* Opaque */ + +/* + * Create a wait channel. Use NAME as a symbolic name for the channel. + * NAME should be a string constant; if not, the caller is responsible + * for freeing it after the wchan is destroyed. + */ +struct wchan *wchan_create(const char *name); + +/* + * Destroy a wait channel. Must be empty and unlocked. + */ +void wchan_destroy(struct wchan *wc); + +/* + * Return nonzero if there are no threads sleeping on the channel. + * This is meant to be used only for diagnostic purposes. + */ +bool wchan_isempty(struct wchan *wc, struct spinlock *lk); + +/* + * Go to sleep on a wait channel. The current thread is suspended + * until awakened by someone else, at which point this function + * returns. + * + * The associated lock must be locked. It will be unlocked while + * sleeping, and relocked upon return. + */ +void wchan_sleep(struct wchan *wc, struct spinlock *lk); + +/* + * Wake up one thread, or all threads, sleeping on a wait channel. + * The associated spinlock should be locked. + * + * The current implementation is FIFO but this is not promised by the + * interface. + */ +void wchan_wakeone(struct wchan *wc, struct spinlock *lk); +void wchan_wakeall(struct wchan *wc, struct spinlock *lk); + + +#endif /* _WCHAN_H_ */ diff --git a/kern/lib/array.c b/kern/lib/array.c new file mode 100644 index 0000000..0efb362 --- /dev/null +++ b/kern/lib/array.c @@ -0,0 +1,135 @@ +/*- + * Copyright (c) 2009 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define ARRAYINLINE + +#include +#include +#include +#include + +struct array * +array_create(void) +{ + struct array *a; + + a = kmalloc(sizeof(*a)); + if (a != NULL) { + array_init(a); + } + return a; +} + +void +array_destroy(struct array *a) +{ + array_cleanup(a); + kfree(a); +} + +void +array_init(struct array *a) +{ + a->num = a->max = 0; + a->v = NULL; +} + +void +array_cleanup(struct array *a) +{ + /* + * Require array to be empty - helps avoid memory leaks since + * we don't/can't free anything any contents may be pointing + * to. + */ + ARRAYASSERT(a->num == 0); + kfree(a->v); +#ifdef ARRAYS_CHECKED + a->v = NULL; +#endif +} + +int +array_preallocate(struct array *a, unsigned num) +{ + void **newptr; + unsigned newmax; + + if (num > a->max) { + /* Don't touch A until the allocation succeeds. */ + newmax = a->max; + while (num > newmax) { + newmax = newmax ? newmax*2 : 4; + } + + /* + * We don't have krealloc, and it wouldn't be + * worthwhile to implement just for this. So just + * allocate a new block and copy. (Exercise: what + * about this and/or kmalloc makes it not worthwhile?) + */ + + newptr = kmalloc(newmax*sizeof(*a->v)); + if (newptr == NULL) { + return ENOMEM; + } + memcpy(newptr, a->v, a->num*sizeof(*a->v)); + kfree(a->v); + a->v = newptr; + a->max = newmax; + } + return 0; +} + +int +array_setsize(struct array *a, unsigned num) +{ + int result; + + result = array_preallocate(a, num); + if (result) { + return result; + } + a->num = num; + + return 0; +} + +void +array_remove(struct array *a, unsigned index) +{ + unsigned num_to_move; + + ARRAYASSERT(a->num <= a->max); + ARRAYASSERT(index < a->num); + + num_to_move = a->num - (index + 1); + memmove(a->v + index, a->v + index+1, num_to_move*sizeof(void *)); + a->num--; +} diff --git a/kern/lib/bitmap.c b/kern/lib/bitmap.c new file mode 100644 index 0000000..1e6ce01 --- /dev/null +++ b/kern/lib/bitmap.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2000, 2001, 2002 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Fixed-size array of bits. (Intended for storage management.) + */ + +#include +#include +#include +#include + +/* + * It would be a lot more efficient on most platforms to use uint32_t + * or unsigned long as the base type for holding bits. But we don't, + * because if one uses any data type more than a single byte wide, + * bitmap data saved on disk becomes endian-dependent, which is a + * severe nuisance. + */ +#define BITS_PER_WORD (CHAR_BIT) +#define WORD_TYPE unsigned char +#define WORD_ALLBITS (0xff) + +struct bitmap { + unsigned nbits; + WORD_TYPE *v; +}; + + +struct bitmap * +bitmap_create(unsigned nbits) +{ + struct bitmap *b; + unsigned words; + + words = DIVROUNDUP(nbits, BITS_PER_WORD); + b = kmalloc(sizeof(struct bitmap)); + if (b == NULL) { + return NULL; + } + b->v = kmalloc(words*sizeof(WORD_TYPE)); + if (b->v == NULL) { + kfree(b); + return NULL; + } + + bzero(b->v, words*sizeof(WORD_TYPE)); + b->nbits = nbits; + + /* Mark any leftover bits at the end in use */ + if (words > nbits / BITS_PER_WORD) { + unsigned j, ix = words-1; + unsigned overbits = nbits - ix*BITS_PER_WORD; + + KASSERT(nbits / BITS_PER_WORD == words-1); + KASSERT(overbits > 0 && overbits < BITS_PER_WORD); + + for (j=overbits; jv[ix] |= ((WORD_TYPE)1 << j); + } + } + + return b; +} + +void * +bitmap_getdata(struct bitmap *b) +{ + return b->v; +} + +int +bitmap_alloc(struct bitmap *b, unsigned *index) +{ + unsigned ix; + unsigned maxix = DIVROUNDUP(b->nbits, BITS_PER_WORD); + unsigned offset; + + for (ix=0; ixv[ix]!=WORD_ALLBITS) { + for (offset = 0; offset < BITS_PER_WORD; offset++) { + WORD_TYPE mask = ((WORD_TYPE)1) << offset; + + if ((b->v[ix] & mask)==0) { + b->v[ix] |= mask; + *index = (ix*BITS_PER_WORD)+offset; + KASSERT(*index < b->nbits); + return 0; + } + } + KASSERT(0); + } + } + return ENOSPC; +} + +static +inline +void +bitmap_translate(unsigned bitno, unsigned *ix, WORD_TYPE *mask) +{ + unsigned offset; + *ix = bitno / BITS_PER_WORD; + offset = bitno % BITS_PER_WORD; + *mask = ((WORD_TYPE)1) << offset; +} + +void +bitmap_mark(struct bitmap *b, unsigned index) +{ + unsigned ix; + WORD_TYPE mask; + + KASSERT(index < b->nbits); + bitmap_translate(index, &ix, &mask); + + KASSERT((b->v[ix] & mask)==0); + b->v[ix] |= mask; +} + +void +bitmap_unmark(struct bitmap *b, unsigned index) +{ + unsigned ix; + WORD_TYPE mask; + + KASSERT(index < b->nbits); + bitmap_translate(index, &ix, &mask); + + KASSERT((b->v[ix] & mask)!=0); + b->v[ix] &= ~mask; +} + + +int +bitmap_isset(struct bitmap *b, unsigned index) +{ + unsigned ix; + WORD_TYPE mask; + + bitmap_translate(index, &ix, &mask); + return (b->v[ix] & mask); +} + +void +bitmap_destroy(struct bitmap *b) +{ + kfree(b->v); + kfree(b); +} diff --git a/kern/lib/bswap.c b/kern/lib/bswap.c new file mode 100644 index 0000000..fb8adf2 --- /dev/null +++ b/kern/lib/bswap.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * Unconditional byte-swap functions. + * + * bswap16, 32, and 64 unconditionally swap byte order of integers of + * the respective bitsize. + * + * The advantage of writing them out like this is that the bit + * patterns are easily validated by inspection. Also, this form is + * more likely to be picked up by the compiler and converted into + * byte-swap machine instructions (if those exist) than something + * loop-based. + */ + +uint16_t +bswap16(uint16_t val) +{ + return ((val & 0x00ff) << 8) + | ((val & 0xff00) >> 8); +} + +uint32_t +bswap32(uint32_t val) +{ + return ((val & 0x000000ff) << 24) + | ((val & 0x0000ff00) << 8) + | ((val & 0x00ff0000) >> 8) + | ((val & 0xff000000) >> 24); +} + +uint64_t +bswap64(uint64_t val) +{ + return ((val & 0x00000000000000ff) << 56) + | ((val & 0x000000000000ff00) << 40) + | ((val & 0x0000000000ff0000) << 24) + | ((val & 0x00000000ff000000) << 8) + | ((val & 0x000000ff00000000) << 8) + | ((val & 0x0000ff0000000000) << 24) + | ((val & 0x00ff000000000000) >> 40) + | ((val & 0xff00000000000000) >> 56); +} + +/* + * Network byte order byte-swap functions. + * + * For ntoh* and hton*: + * *s are for "short" (16-bit) + * *l are for "long" (32-bit) + * *ll are for "long long" (64-bit) + * + * hton* convert from host byte order to network byte order. + * ntoh* convert from network byte order to host byte order. + * + * Network byte order is big-endian. + * + * Note that right now the only platforms OS/161 runs on are + * big-endian, so these functions are actually all empty. + * + * These should maybe be made inline. + */ + +#if _BYTE_ORDER == _LITTLE_ENDIAN +#define TO(tag, bits, type) \ + type ntoh##tag(type val) { return bswap##bits(val); } \ + type hton##tag(type val) { return bswap##bits(val); } +#endif + +/* + * Use a separate #if, so if the header file defining the symbols gets + * omitted or messed up the build will fail instead of silently choosing + * the wrong option. + */ +#if _BYTE_ORDER == _BIG_ENDIAN +#define TO(tag, bits, type) \ + type ntoh##tag(type val) { return val; } \ + type hton##tag(type val) { return val; } +#endif + +#if _BYTE_ORDER == _PDP_ENDIAN +#error "You lose." +#endif + +#ifndef TO +#error "_BYTE_ORDER not set" +#endif + +TO(s, 16, uint16_t) +TO(l, 32, uint32_t) +TO(ll, 64, uint64_t) + + +/* + * Some utility functions for handling 64-bit values. + * + * join32to64 pastes two adjoining 32-bit values together in the right + * way to treat them as a 64-bit value, depending on endianness. + * split64to32 is the inverse operation. + * + * The 32-bit arguments should be passed in the order they appear in + * memory, not as high word and low word; the whole point of these + * functions is to know which is the high word and which is the low + * word. + */ + +void +join32to64(uint32_t x1, uint32_t x2, uint64_t *y2) +{ +#if _BYTE_ORDER == _BIG_ENDIAN + *y2 = ((uint64_t)x1 << 32) | (uint64_t)x2; +#elif _BYTE_ORDER == _LITTLE_ENDIAN + *y2 = (uint64_t)x1 | ((uint64_t)x2 << 32); +#else +#error "Eh?" +#endif +} + +void +split64to32(uint64_t x, uint32_t *y1, uint32_t *y2) +{ +#if _BYTE_ORDER == _BIG_ENDIAN + *y1 = x >> 32; + *y2 = x & 0xffffffff; +#elif _BYTE_ORDER == _LITTLE_ENDIAN + *y1 = x & 0xffffffff; + *y2 = x >> 32; +#else +#error "Eh?" +#endif +} diff --git a/kern/lib/kgets.c b/kern/lib/kgets.c new file mode 100644 index 0000000..18deafb --- /dev/null +++ b/kern/lib/kgets.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2001 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include +#include + +/* + * Do a backspace in typed input. + * We overwrite the current character with a space in case we're on + * a terminal where backspace is nondestructive. + */ +static +void +backsp(void) +{ + putch('\b'); + putch(' '); + putch('\b'); +} + +/* + * Read a string off the console. Support a few of the more useful + * common control characters. Do not include the terminating newline + * in the buffer passed back. + */ +void +kgets(char *buf, size_t maxlen) +{ + size_t pos = 0; + int ch; + + while (1) { + ch = getch(); + if (ch=='\n' || ch=='\r') { + putch('\n'); + break; + } + + /* Only allow the normal 7-bit ascii */ + if (ch>=32 && ch<127 && pos < maxlen-1) { + putch(ch); + buf[pos++] = ch; + } + else if ((ch=='\b' || ch==127) && pos>0) { + /* backspace */ + backsp(); + pos--; + } + else if (ch==3) { + /* ^C - return empty string */ + putch('^'); + putch('C'); + putch('\n'); + pos = 0; + break; + } + else if (ch==18) { + /* ^R - reprint input */ + buf[pos] = 0; + kprintf("^R\n%s", buf); + } + else if (ch==21) { + /* ^U - erase line */ + while (pos > 0) { + backsp(); + pos--; + } + } + else if (ch==23) { + /* ^W - erase word */ + while (pos > 0 && buf[pos-1]==' ') { + backsp(); + pos--; + } + while (pos > 0 && buf[pos-1]!=' ') { + backsp(); + pos--; + } + } + else { + beep(); + } + } + + buf[pos] = 0; +} diff --git a/kern/lib/kprintf.c b/kern/lib/kprintf.c new file mode 100644 index 0000000..3adc7a3 --- /dev/null +++ b/kern/lib/kprintf.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for vfs_sync() +#include // for ltrace_stop() + + +/* Flags word for DEBUG() macro. */ +uint32_t dbflags = 0; + +/* Lock for non-polled kprintfs */ +static struct lock *kprintf_lock; + +/* Lock for polled kprintfs */ +static struct spinlock kprintf_spinlock; + + +/* + * Warning: all this has to work from interrupt handlers and when + * interrupts are disabled. + */ + + +/* + * Create the kprintf lock. Must be called before creating a second + * thread or enabling a second CPU. + */ +void +kprintf_bootstrap(void) +{ + KASSERT(kprintf_lock == NULL); + + kprintf_lock = lock_create("kprintf_lock"); + if (kprintf_lock == NULL) { + panic("Could not create kprintf_lock\n"); + } + spinlock_init(&kprintf_spinlock); +} + +/* + * Send characters to the console. Backend for __printf. + */ +static +void +console_send(void *junk, const char *data, size_t len) +{ + size_t i; + + (void)junk; + + for (i=0; it_in_interrupt == false + && curthread->t_curspl == 0 + && curcpu->c_spinlocks == 0; + + if (dolock) { + lock_acquire(kprintf_lock); + } + else { + spinlock_acquire(&kprintf_spinlock); + } + + va_start(ap, fmt); + chars = __vprintf(console_send, NULL, fmt, ap); + va_end(ap); + + if (dolock) { + lock_release(kprintf_lock); + } + else { + spinlock_release(&kprintf_spinlock); + } + + return chars; +} + +/* + * panic() is for fatal errors. It prints the printf arguments it's + * passed and then halts the system. + */ + +void +panic(const char *fmt, ...) +{ + va_list ap; + + /* + * When we reach panic, the system is usually fairly screwed up. + * It's not entirely uncommon for anything else we try to do + * here to trigger more panics. + * + * This variable makes sure that if we try to do something here, + * and it causes another panic, *that* panic doesn't try again; + * trying again almost inevitably causes infinite recursion. + * + * This is not excessively paranoid - these things DO happen! + */ + static volatile int evil; + + if (evil == 0) { + evil = 1; + + /* + * Not only do we not want to be interrupted while + * panicking, but we also want the console to be + * printing in polling mode so as not to do context + * switches. So turn interrupts off on this CPU. + */ + splhigh(); + } + + if (evil == 1) { + evil = 2; + + /* Kill off other threads and halt other CPUs. */ + thread_panic(); + } + + if (evil == 2) { + evil = 3; + + /* Print the message. */ + kprintf("panic: "); + va_start(ap, fmt); + __vprintf(console_send, NULL, fmt, ap); + va_end(ap); + } + + if (evil == 3) { + evil = 4; + + /* Drop to the debugger. */ + ltrace_stop(0); + } + + if (evil == 4) { + evil = 5; + + /* Try to sync the disks. */ + vfs_sync(); + } + + if (evil == 5) { + evil = 6; + + /* Shut down or reboot the system. */ + mainbus_panic(); + } + + /* + * Last resort, just in case. + */ + + for (;;); +} + +/* + * Assertion failures go through this. + */ +void +badassert(const char *expr, const char *file, int line, const char *func) +{ + panic("Assertion failed: %s, at %s:%d (%s)\n", + expr, file, line, func); +} diff --git a/kern/lib/misc.c b/kern/lib/misc.c new file mode 100644 index 0000000..2388e1d --- /dev/null +++ b/kern/lib/misc.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +/* + * Like strdup, but calls kmalloc. + */ +char * +kstrdup(const char *s) +{ + char *z; + + z = kmalloc(strlen(s)+1); + if (z == NULL) { + return NULL; + } + strcpy(z, s); + return z; +} + +/* + * Standard C function to return a string for a given errno. + * Kernel version; panics if it hits an unknown error. + */ +const char * +strerror(int errcode) +{ + if (errcode>=0 && errcode < sys_nerr) { + return sys_errlist[errcode]; + } + panic("Invalid error code %d\n", errcode); + return NULL; +} diff --git a/kern/lib/time.c b/kern/lib/time.c new file mode 100644 index 0000000..077e6da --- /dev/null +++ b/kern/lib/time.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * ts1 + ts2 + */ +void +timespec_add(const struct timespec *ts1, + const struct timespec *ts2, + struct timespec *ret) +{ + ret->tv_nsec = ts1->tv_nsec + ts2->tv_nsec; + ret->tv_sec = ts1->tv_sec + ts2->tv_sec; + if (ret->tv_nsec >= 1000000000) { + ret->tv_nsec -= 1000000000; + ret->tv_sec += 1; + } +} + +/* + * ts1 - ts2 + */ +void +timespec_sub(const struct timespec *ts1, + const struct timespec *ts2, + struct timespec *ret) +{ + /* in case ret and ts1 or ts2 are the same */ + struct timespec r; + + r = *ts1; + if (r.tv_nsec < ts2->tv_nsec) { + r.tv_nsec += 1000000000; + r.tv_sec--; + } + + r.tv_nsec -= ts2->tv_nsec; + r.tv_sec -= ts2->tv_sec; + *ret = r; +} diff --git a/kern/lib/uio.c b/kern/lib/uio.c new file mode 100644 index 0000000..69f9a85 --- /dev/null +++ b/kern/lib/uio.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +/* + * See uio.h for a description. + */ + +int +uiomove(void *ptr, size_t n, struct uio *uio) +{ + struct iovec *iov; + size_t size; + int result; + + if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE) { + panic("uiomove: Invalid uio_rw %d\n", (int) uio->uio_rw); + } + if (uio->uio_segflg==UIO_SYSSPACE) { + KASSERT(uio->uio_space == NULL); + } + else { + KASSERT(uio->uio_space == proc_getas()); + } + + while (n > 0 && uio->uio_resid > 0) { + /* get the first iovec */ + iov = uio->uio_iov; + size = iov->iov_len; + + if (size > n) { + size = n; + } + + if (size == 0) { + /* move to the next iovec and try again */ + uio->uio_iov++; + uio->uio_iovcnt--; + if (uio->uio_iovcnt == 0) { + /* + * This should only happen if you set + * uio_resid incorrectly (to more than + * the total length of buffers the uio + * points to). + */ + panic("uiomove: ran out of buffers\n"); + } + continue; + } + + switch (uio->uio_segflg) { + case UIO_SYSSPACE: + if (uio->uio_rw == UIO_READ) { + memmove(iov->iov_kbase, ptr, size); + } + else { + memmove(ptr, iov->iov_kbase, size); + } + iov->iov_kbase = ((char *)iov->iov_kbase+size); + break; + case UIO_USERSPACE: + case UIO_USERISPACE: + if (uio->uio_rw == UIO_READ) { + result = copyout(ptr, iov->iov_ubase,size); + } + else { + result = copyin(iov->iov_ubase, ptr, size); + } + if (result) { + return result; + } + iov->iov_ubase += size; + break; + default: + panic("uiomove: Invalid uio_segflg %d\n", + (int)uio->uio_segflg); + } + + iov->iov_len -= size; + uio->uio_resid -= size; + uio->uio_offset += size; + ptr = ((char *)ptr + size); + n -= size; + } + + return 0; +} + +int +uiomovezeros(size_t n, struct uio *uio) +{ + /* static, so initialized as zero */ + static char zeros[16]; + size_t amt; + int result; + + /* This only makes sense when reading */ + KASSERT(uio->uio_rw == UIO_READ); + + while (n > 0) { + amt = sizeof(zeros); + if (amt > n) { + amt = n; + } + result = uiomove(zeros, amt, uio); + if (result) { + return result; + } + n -= amt; + } + + return 0; +} + +/* + * Convenience function to initialize an iovec and uio for kernel I/O. + */ + +void +uio_kinit(struct iovec *iov, struct uio *u, + void *kbuf, size_t len, off_t pos, enum uio_rw rw) +{ + iov->iov_kbase = kbuf; + iov->iov_len = len; + u->uio_iov = iov; + u->uio_iovcnt = 1; + u->uio_offset = pos; + u->uio_resid = len; + u->uio_segflg = UIO_SYSSPACE; + u->uio_rw = rw; + u->uio_space = NULL; +} diff --git a/kern/main/main.c b/kern/main/main.c new file mode 100644 index 0000000..d095480 --- /dev/null +++ b/kern/main/main.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Main. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "autoconf.h" // for pseudoconfig + + +/* + * These two pieces of data are maintained by the makefiles and build system. + * buildconfig is the name of the config file the kernel was configured with. + * buildversion starts at 1 and is incremented every time you link a kernel. + * + * The purpose is not to show off how many kernels you've linked, but + * to make it easy to make sure that the kernel you just booted is the + * same one you just built. + */ +extern const int buildversion; +extern const char buildconfig[]; + +/* + * Copyright message for the OS/161 base code. + */ +static const char harvard_copyright[] = + "Copyright (c) 2000, 2001-2005, 2008-2011, 2013, 2014\n" + " President and Fellows of Harvard College. All rights reserved.\n"; + + +/* + * Initial boot sequence. + */ +static +void +boot(void) +{ + /* + * The order of these is important! + * Don't go changing it without thinking about the consequences. + * + * Among other things, be aware that console output gets + * buffered up at first and does not actually appear until + * mainbus_bootstrap() attaches the console device. This can + * be remarkably confusing if a bug occurs at this point. So + * don't put new code before mainbus_bootstrap if you don't + * absolutely have to. + * + * Also note that the buffer for this is only 1k. If you + * overflow it, the system will crash without printing + * anything at all. You can make it larger though (it's in + * dev/generic/console.c). + */ + + kprintf("\n"); + kprintf("OS/161 base system version %s\n", BASE_VERSION); + kprintf("%s", harvard_copyright); + kprintf("\n"); + + kprintf("Put-your-group-name-here's system version %s (%s #%d)\n", + GROUP_VERSION, buildconfig, buildversion); + kprintf("\n"); + + /* Early initialization. */ + ram_bootstrap(); + proc_bootstrap(); + thread_bootstrap(); + hardclock_bootstrap(); + vfs_bootstrap(); + kheap_nextgeneration(); + + /* Probe and initialize devices. Interrupts should come on. */ + kprintf("Device probe...\n"); + KASSERT(curthread->t_curspl > 0); + mainbus_bootstrap(); + KASSERT(curthread->t_curspl == 0); + /* Now do pseudo-devices. */ + pseudoconfig(); + kprintf("\n"); + kheap_nextgeneration(); + + /* Late phase of initialization. */ + vm_bootstrap(); + kprintf_bootstrap(); + thread_start_cpus(); + + /* Default bootfs - but ignore failure, in case emu0 doesn't exist */ + vfs_setbootfs("emu0"); + + kheap_nextgeneration(); + + /* + * Make sure various things aren't screwed up. + */ + COMPILE_ASSERT(sizeof(userptr_t) == sizeof(char *)); + COMPILE_ASSERT(sizeof(*(userptr_t)0) == sizeof(char)); +} + +/* + * Shutdown sequence. Opposite to boot(). + */ +static +void +shutdown(void) +{ + + kprintf("Shutting down.\n"); + + vfs_clearbootfs(); + vfs_clearcurdir(); + vfs_unmountall(); + + thread_shutdown(); + + splhigh(); +} + +/*****************************************/ + +/* + * reboot() system call. + * + * Note: this is here because it's directly related to the code above, + * not because this is where system call code should go. Other syscall + * code should probably live in the "syscall" directory. + */ +int +sys_reboot(int code) +{ + switch (code) { + case RB_REBOOT: + case RB_HALT: + case RB_POWEROFF: + break; + default: + return EINVAL; + } + + shutdown(); + + switch (code) { + case RB_HALT: + kprintf("The system is halted.\n"); + mainbus_halt(); + break; + case RB_REBOOT: + kprintf("Rebooting...\n"); + mainbus_reboot(); + break; + case RB_POWEROFF: + kprintf("The system is halted.\n"); + mainbus_poweroff(); + break; + } + + panic("reboot operation failed\n"); + return 0; +} + +/* + * Kernel main. Boot up, then fork the menu thread; wait for a reboot + * request, and then shut down. + */ +void +kmain(char *arguments) +{ + boot(); + + menu(arguments); + + /* Should not get here */ +} diff --git a/kern/main/menu.c b/kern/main/menu.c new file mode 100644 index 0000000..1f5723a --- /dev/null +++ b/kern/main/menu.c @@ -0,0 +1,827 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "opt-sfs.h" +#include "opt-net.h" + +/* + * In-kernel menu and command dispatcher. + */ + +#define _PATH_SHELL "/bin/sh" + +#define MAXMENUARGS 16 + +//////////////////////////////////////////////////////////// +// +// Command menu functions + +/* + * Function for a thread that runs an arbitrary userlevel program by + * name. + * + * Note: this cannot pass arguments to the program. You may wish to + * change it so it can, because that will make testing much easier + * in the future. + * + * It copies the program name because runprogram destroys the copy + * it gets by passing it to vfs_open(). + */ +static +void +cmd_progthread(void *ptr, unsigned long nargs) +{ + char **args = ptr; + char progname[128]; + int result; + + KASSERT(nargs >= 1); + + if (nargs > 2) { + kprintf("Warning: argument passing from menu not supported\n"); + } + + /* Hope we fit. */ + KASSERT(strlen(args[0]) < sizeof(progname)); + + strcpy(progname, args[0]); + + result = runprogram(progname); + if (result) { + kprintf("Running program %s failed: %s\n", args[0], + strerror(result)); + return; + } + + /* NOTREACHED: runprogram only returns on error. */ +} + +/* + * Common code for cmd_prog and cmd_shell. + * + * Note that this does not wait for the subprogram to finish, but + * returns immediately to the menu. This is usually not what you want, + * so you should have it call your system-calls-assignment waitpid + * code after forking. + * + * Also note that because the subprogram's thread uses the "args" + * array and strings, until you do this a race condition exists + * between that code and the menu input code. + */ +static +int +common_prog(int nargs, char **args) +{ + struct proc *proc; + int result; + + /* Create a process for the new program to run in. */ + proc = proc_create_runprogram(args[0] /* name */); + if (proc == NULL) { + return ENOMEM; + } + + result = thread_fork(args[0] /* thread name */, + proc /* new process */, + cmd_progthread /* thread function */, + args /* thread arg */, nargs /* thread arg */); + if (result) { + kprintf("thread_fork failed: %s\n", strerror(result)); + proc_destroy(proc); + return result; + } + + /* + * The new process will be destroyed when the program exits... + * once you write the code for handling that. + */ + + return 0; +} + +/* + * Command for running an arbitrary userlevel program. + */ +static +int +cmd_prog(int nargs, char **args) +{ + if (nargs < 2) { + kprintf("Usage: p program [arguments]\n"); + return EINVAL; + } + + /* drop the leading "p" */ + args++; + nargs--; + + return common_prog(nargs, args); +} + +/* + * Command for starting the system shell. + */ +static +int +cmd_shell(int nargs, char **args) +{ + (void)args; + if (nargs != 1) { + kprintf("Usage: s\n"); + return EINVAL; + } + + args[0] = (char *)_PATH_SHELL; + + return common_prog(nargs, args); +} + +/* + * Command for changing directory. + */ +static +int +cmd_chdir(int nargs, char **args) +{ + if (nargs != 2) { + kprintf("Usage: cd directory\n"); + return EINVAL; + } + + return vfs_chdir(args[1]); +} + +/* + * Command for printing the current directory. + */ +static +int +cmd_pwd(int nargs, char **args) +{ + char buf[PATH_MAX+1]; + int result; + struct iovec iov; + struct uio ku; + + (void)nargs; + (void)args; + + uio_kinit(&iov, &ku, buf, sizeof(buf)-1, 0, UIO_READ); + result = vfs_getcwd(&ku); + if (result) { + kprintf("vfs_getcwd failed (%s)\n", strerror(result)); + return result; + } + + /* null terminate */ + buf[sizeof(buf)-1-ku.uio_resid] = 0; + + /* print it */ + kprintf("%s\n", buf); + + return 0; +} + +/* + * Command for running sync. + */ +static +int +cmd_sync(int nargs, char **args) +{ + (void)nargs; + (void)args; + + vfs_sync(); + + return 0; +} + +/* + * Command for dropping to the debugger. + */ +static +int +cmd_debug(int nargs, char **args) +{ + (void)nargs; + (void)args; + + mainbus_debugger(); + + return 0; +} + +/* + * Command for doing an intentional panic. + */ +static +int +cmd_panic(int nargs, char **args) +{ + (void)nargs; + (void)args; + + panic("User requested panic\n"); + return 0; +} + +/* + * Subthread for intentially deadlocking. + */ +struct deadlock { + struct lock *lock1; + struct lock *lock2; +}; + +static +void +cmd_deadlockthread(void *ptr, unsigned long num) +{ + struct deadlock *dl = ptr; + + (void)num; + + /* If it doesn't wedge right away, keep trying... */ + while (1) { + lock_acquire(dl->lock2); + lock_acquire(dl->lock1); + kprintf("+"); + lock_release(dl->lock1); + lock_release(dl->lock2); + } +} + +/* + * Command for doing an intentional deadlock. + */ +static +int +cmd_deadlock(int nargs, char **args) +{ + struct deadlock dl; + int result; + + (void)nargs; + (void)args; + + dl.lock1 = lock_create("deadlock1"); + if (dl.lock1 == NULL) { + kprintf("lock_create failed\n"); + return ENOMEM; + } + dl.lock2 = lock_create("deadlock2"); + if (dl.lock2 == NULL) { + lock_destroy(dl.lock1); + kprintf("lock_create failed\n"); + return ENOMEM; + } + + result = thread_fork(args[0] /* thread name */, + NULL /* kernel thread */, + cmd_deadlockthread /* thread function */, + &dl /* thread arg */, 0 /* thread arg */); + if (result) { + kprintf("thread_fork failed: %s\n", strerror(result)); + lock_release(dl.lock1); + lock_destroy(dl.lock2); + lock_destroy(dl.lock1); + return result; + } + + /* If it doesn't wedge right away, keep trying... */ + while (1) { + lock_acquire(dl.lock1); + lock_acquire(dl.lock2); + kprintf("."); + lock_release(dl.lock2); + lock_release(dl.lock1); + } + /* NOTREACHED */ + return 0; +} + +/* + * Command for shutting down. + */ +static +int +cmd_quit(int nargs, char **args) +{ + (void)nargs; + (void)args; + + vfs_sync(); + sys_reboot(RB_POWEROFF); + thread_exit(); + return 0; +} + +/* + * Command for mounting a filesystem. + */ + +/* Table of mountable filesystem types. */ +static const struct { + const char *name; + int (*func)(const char *device); +} mounttable[] = { +#if OPT_SFS + { "sfs", sfs_mount }, +#endif +}; + +static +int +cmd_mount(int nargs, char **args) +{ + char *fstype; + char *device; + unsigned i; + + if (nargs != 3) { + kprintf("Usage: mount fstype device:\n"); + return EINVAL; + } + + fstype = args[1]; + device = args[2]; + + /* Allow (but do not require) colon after device name */ + if (device[strlen(device)-1]==':') { + device[strlen(device)-1] = 0; + } + + for (i=0; i= MAXMENUARGS) { + kprintf("Command line has too many words\n"); + return E2BIG; + } + args[nargs++] = word; + } + + if (nargs==0) { + return 0; + } + + for (i=0; cmdtable[i].name; i++) { + if (*cmdtable[i].name && !strcmp(args[0], cmdtable[i].name)) { + KASSERT(cmdtable[i].func!=NULL); + + gettime(&before); + + result = cmdtable[i].func(nargs, args); + + gettime(&after); + timespec_sub(&after, &before, &duration); + + kprintf("Operation took %llu.%09lu seconds\n", + (unsigned long long) duration.tv_sec, + (unsigned long) duration.tv_nsec); + + return result; + } + } + + kprintf("%s: Command not found\n", args[0]); + return EINVAL; +} + +/* + * Evaluate a command line that may contain multiple semicolon-delimited + * commands. + * + * If "isargs" is set, we're doing command-line processing; print the + * comamnds as we execute them and panic if the command is invalid or fails. + */ +static +void +menu_execute(char *line, int isargs) +{ + char *command; + char *context; + int result; + + for (command = strtok_r(line, ";", &context); + command != NULL; + command = strtok_r(NULL, ";", &context)) { + + if (isargs) { + kprintf("OS/161 kernel: %s\n", command); + } + + result = cmd_dispatch(command); + if (result) { + kprintf("Menu command failed: %s\n", strerror(result)); + if (isargs) { + panic("Failure processing kernel arguments\n"); + } + } + } +} + +/* + * Command menu main loop. + * + * First, handle arguments passed on the kernel's command line from + * the bootloader. Then loop prompting for commands. + * + * The line passed in from the bootloader is treated as if it had been + * typed at the prompt. Semicolons separate commands; spaces and tabs + * separate words (command names and arguments). + * + * So, for instance, to mount an SFS on lhd0 and make it the boot + * filesystem, and then boot directly into the shell, one would use + * the kernel command line + * + * "mount sfs lhd0; bootfs lhd0; s" + */ + +void +menu(char *args) +{ + char buf[64]; + + menu_execute(args, 1); + + while (1) { + kprintf("OS/161 kernel [? for menu]: "); + kgets(buf, sizeof(buf)); + menu_execute(buf, 0); + } +} diff --git a/kern/proc/proc.c b/kern/proc/proc.c new file mode 100644 index 0000000..2db8ea2 --- /dev/null +++ b/kern/proc/proc.c @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Process support. + * + * There is (intentionally) not much here; you will need to add stuff + * and maybe change around what's already present. + * + * p_lock is intended to be held when manipulating the pointers in the + * proc structure, not while doing any significant work with the + * things they point to. Rearrange this (and/or change it to be a + * regular lock) as needed. + * + * Unless you're implementing multithreaded user processes, the only + * process that will have more than one thread is the kernel process. + */ + +#include +#include +#include +#include +#include +#include + +/* + * The process for the kernel; this holds all the kernel-only threads. + */ +struct proc *kproc; + +/* + * Create a proc structure. + */ +static +struct proc * +proc_create(const char *name) +{ + struct proc *proc; + + proc = kmalloc(sizeof(*proc)); + if (proc == NULL) { + return NULL; + } + proc->p_name = kstrdup(name); + if (proc->p_name == NULL) { + kfree(proc); + return NULL; + } + + proc->p_numthreads = 0; + spinlock_init(&proc->p_lock); + + /* VM fields */ + proc->p_addrspace = NULL; + + /* VFS fields */ + proc->p_cwd = NULL; + + return proc; +} + +/* + * Destroy a proc structure. + * + * Note: nothing currently calls this. Your wait/exit code will + * probably want to do so. + */ +void +proc_destroy(struct proc *proc) +{ + /* + * You probably want to destroy and null out much of the + * process (particularly the address space) at exit time if + * your wait/exit design calls for the process structure to + * hang around beyond process exit. Some wait/exit designs + * do, some don't. + */ + + KASSERT(proc != NULL); + KASSERT(proc != kproc); + + /* + * We don't take p_lock in here because we must have the only + * reference to this structure. (Otherwise it would be + * incorrect to destroy it.) + */ + + /* VFS fields */ + if (proc->p_cwd) { + VOP_DECREF(proc->p_cwd); + proc->p_cwd = NULL; + } + + /* VM fields */ + if (proc->p_addrspace) { + /* + * If p is the current process, remove it safely from + * p_addrspace before destroying it. This makes sure + * we don't try to activate the address space while + * it's being destroyed. + * + * Also explicitly deactivate, because setting the + * address space to NULL won't necessarily do that. + * + * (When the address space is NULL, it means the + * process is kernel-only; in that case it is normally + * ok if the MMU and MMU- related data structures + * still refer to the address space of the last + * process that had one. Then you save work if that + * process is the next one to run, which isn't + * uncommon. However, here we're going to destroy the + * address space, so we need to make sure that nothing + * in the VM system still refers to it.) + * + * The call to as_deactivate() must come after we + * clear the address space, or a timer interrupt might + * reactivate the old address space again behind our + * back. + * + * If p is not the current process, still remove it + * from p_addrspace before destroying it as a + * precaution. Note that if p is not the current + * process, in order to be here p must either have + * never run (e.g. cleaning up after fork failed) or + * have finished running and exited. It is quite + * incorrect to destroy the proc structure of some + * random other process while it's still running... + */ + struct addrspace *as; + + if (proc == curproc) { + as = proc_setas(NULL); + as_deactivate(); + } + else { + as = proc->p_addrspace; + proc->p_addrspace = NULL; + } + as_destroy(as); + } + + KASSERT(proc->p_numthreads == 0); + spinlock_cleanup(&proc->p_lock); + + kfree(proc->p_name); + kfree(proc); +} + +/* + * Create the process structure for the kernel. + */ +void +proc_bootstrap(void) +{ + kproc = proc_create("[kernel]"); + if (kproc == NULL) { + panic("proc_create for kproc failed\n"); + } +} + +/* + * Create a fresh proc for use by runprogram. + * + * It will have no address space and will inherit the current + * process's (that is, the kernel menu's) current directory. + */ +struct proc * +proc_create_runprogram(const char *name) +{ + struct proc *newproc; + + newproc = proc_create(name); + if (newproc == NULL) { + return NULL; + } + + /* VM fields */ + + newproc->p_addrspace = NULL; + + /* VFS fields */ + + /* + * Lock the current process to copy its current directory. + * (We don't need to lock the new process, though, as we have + * the only reference to it.) + */ + spinlock_acquire(&curproc->p_lock); + if (curproc->p_cwd != NULL) { + VOP_INCREF(curproc->p_cwd); + newproc->p_cwd = curproc->p_cwd; + } + spinlock_release(&curproc->p_lock); + + return newproc; +} + +/* + * Add a thread to a process. Either the thread or the process might + * or might not be current. + * + * Turn off interrupts on the local cpu while changing t_proc, in + * case it's current, to protect against the as_activate call in + * the timer interrupt context switch, and any other implicit uses + * of "curproc". + */ +int +proc_addthread(struct proc *proc, struct thread *t) +{ + int spl; + + KASSERT(t->t_proc == NULL); + + spinlock_acquire(&proc->p_lock); + proc->p_numthreads++; + spinlock_release(&proc->p_lock); + + spl = splhigh(); + t->t_proc = proc; + splx(spl); + + return 0; +} + +/* + * Remove a thread from its process. Either the thread or the process + * might or might not be current. + * + * Turn off interrupts on the local cpu while changing t_proc, in + * case it's current, to protect against the as_activate call in + * the timer interrupt context switch, and any other implicit uses + * of "curproc". + */ +void +proc_remthread(struct thread *t) +{ + struct proc *proc; + int spl; + + proc = t->t_proc; + KASSERT(proc != NULL); + + spinlock_acquire(&proc->p_lock); + KASSERT(proc->p_numthreads > 0); + proc->p_numthreads--; + spinlock_release(&proc->p_lock); + + spl = splhigh(); + t->t_proc = NULL; + splx(spl); +} + +/* + * Fetch the address space of (the current) process. + * + * Caution: address spaces aren't refcounted. If you implement + * multithreaded processes, make sure to set up a refcount scheme or + * some other method to make this safe. Otherwise the returned address + * space might disappear under you. + */ +struct addrspace * +proc_getas(void) +{ + struct addrspace *as; + struct proc *proc = curproc; + + if (proc == NULL) { + return NULL; + } + + spinlock_acquire(&proc->p_lock); + as = proc->p_addrspace; + spinlock_release(&proc->p_lock); + return as; +} + +/* + * Change the address space of (the current) process. Return the old + * one for later restoration or disposal. + */ +struct addrspace * +proc_setas(struct addrspace *newas) +{ + struct addrspace *oldas; + struct proc *proc = curproc; + + KASSERT(proc != NULL); + + spinlock_acquire(&proc->p_lock); + oldas = proc->p_addrspace; + proc->p_addrspace = newas; + spinlock_release(&proc->p_lock); + return oldas; +} diff --git a/kern/syscall/loadelf.c b/kern/syscall/loadelf.c new file mode 100644 index 0000000..ccfc5f9 --- /dev/null +++ b/kern/syscall/loadelf.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +/* + * Code to load an ELF-format executable into the current address space. + * + * It makes the following address space calls: + * - first, as_define_region once for each segment of the program; + * - then, as_prepare_load; + * - then it loads each chunk of the program; + * - finally, as_complete_load. + * + * This gives the VM code enough flexibility to deal with even grossly + * mis-linked executables if that proves desirable. Under normal + * circumstances, as_prepare_load and as_complete_load probably don't + * need to do anything. + * + * If you wanted to support memory-mapped executables you would need + * to rearrange this to map each segment. + * + * To support dynamically linked executables with shared libraries + * you'd need to change this to load the "ELF interpreter" (dynamic + * linker). And you'd have to write a dynamic linker... + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Load a segment at virtual address VADDR. The segment in memory + * extends from VADDR up to (but not including) VADDR+MEMSIZE. The + * segment on disk is located at file offset OFFSET and has length + * FILESIZE. + * + * FILESIZE may be less than MEMSIZE; if so the remaining portion of + * the in-memory segment should be zero-filled. + * + * Note that uiomove will catch it if someone tries to load an + * executable whose load address is in kernel space. If you should + * change this code to not use uiomove, be sure to check for this case + * explicitly. + */ +static +int +load_segment(struct addrspace *as, struct vnode *v, + off_t offset, vaddr_t vaddr, + size_t memsize, size_t filesize, + int is_executable) +{ + struct iovec iov; + struct uio u; + int result; + + if (filesize > memsize) { + kprintf("ELF: warning: segment filesize > segment memsize\n"); + filesize = memsize; + } + + DEBUG(DB_EXEC, "ELF: Loading %lu bytes to 0x%lx\n", + (unsigned long) filesize, (unsigned long) vaddr); + + iov.iov_ubase = (userptr_t)vaddr; + iov.iov_len = memsize; // length of the memory space + u.uio_iov = &iov; + u.uio_iovcnt = 1; + u.uio_resid = filesize; // amount to read from the file + u.uio_offset = offset; + u.uio_segflg = is_executable ? UIO_USERISPACE : UIO_USERSPACE; + u.uio_rw = UIO_READ; + u.uio_space = as; + + result = VOP_READ(v, &u); + if (result) { + return result; + } + + if (u.uio_resid != 0) { + /* short read; problem with executable? */ + kprintf("ELF: short read on segment - file truncated?\n"); + return ENOEXEC; + } + + /* + * If memsize > filesize, the remaining space should be + * zero-filled. There is no need to do this explicitly, + * because the VM system should provide pages that do not + * contain other processes' data, i.e., are already zeroed. + * + * During development of your VM system, it may have bugs that + * cause it to (maybe only sometimes) not provide zero-filled + * pages, which can cause user programs to fail in strange + * ways. Explicitly zeroing program BSS may help identify such + * bugs, so the following disabled code is provided as a + * diagnostic tool. Note that it must be disabled again before + * you submit your code for grading. + */ +#if 0 + { + size_t fillamt; + + fillamt = memsize - filesize; + if (fillamt > 0) { + DEBUG(DB_EXEC, "ELF: Zero-filling %lu more bytes\n", + (unsigned long) fillamt); + u.uio_resid += fillamt; + result = uiomovezeros(fillamt, &u); + } + } +#endif + + return result; +} + +/* + * Load an ELF executable user program into the current address space. + * + * Returns the entry point (initial PC) for the program in ENTRYPOINT. + */ +int +load_elf(struct vnode *v, vaddr_t *entrypoint) +{ + Elf_Ehdr eh; /* Executable header */ + Elf_Phdr ph; /* "Program header" = segment header */ + int result, i; + struct iovec iov; + struct uio ku; + struct addrspace *as; + + as = proc_getas(); + + /* + * Read the executable header from offset 0 in the file. + */ + + uio_kinit(&iov, &ku, &eh, sizeof(eh), 0, UIO_READ); + result = VOP_READ(v, &ku); + if (result) { + return result; + } + + if (ku.uio_resid != 0) { + /* short read; problem with executable? */ + kprintf("ELF: short read on header - file truncated?\n"); + return ENOEXEC; + } + + /* + * Check to make sure it's a 32-bit ELF-version-1 executable + * for our processor type. If it's not, we can't run it. + * + * Ignore EI_OSABI and EI_ABIVERSION - properly, we should + * define our own, but that would require tinkering with the + * linker to have it emit our magic numbers instead of the + * default ones. (If the linker even supports these fields, + * which were not in the original elf spec.) + */ + + if (eh.e_ident[EI_MAG0] != ELFMAG0 || + eh.e_ident[EI_MAG1] != ELFMAG1 || + eh.e_ident[EI_MAG2] != ELFMAG2 || + eh.e_ident[EI_MAG3] != ELFMAG3 || + eh.e_ident[EI_CLASS] != ELFCLASS32 || + eh.e_ident[EI_DATA] != ELFDATA2MSB || + eh.e_ident[EI_VERSION] != EV_CURRENT || + eh.e_version != EV_CURRENT || + eh.e_type!=ET_EXEC || + eh.e_machine!=EM_MACHINE) { + return ENOEXEC; + } + + /* + * Go through the list of segments and set up the address space. + * + * Ordinarily there will be one code segment, one read-only + * data segment, and one data/bss segment, but there might + * conceivably be more. You don't need to support such files + * if it's unduly awkward to do so. + * + * Note that the expression eh.e_phoff + i*eh.e_phentsize is + * mandated by the ELF standard - we use sizeof(ph) to load, + * because that's the structure we know, but the file on disk + * might have a larger structure, so we must use e_phentsize + * to find where the phdr starts. + */ + + for (i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Load program "progname" and start running it in usermode. + * Does not return except on error. + * + * Calls vfs_open on progname and thus may destroy it. + */ +int +runprogram(char *progname) +{ + struct addrspace *as; + struct vnode *v; + vaddr_t entrypoint, stackptr; + int result; + + /* Open the file. */ + result = vfs_open(progname, O_RDONLY, 0, &v); + if (result) { + return result; + } + + /* We should be a new process. */ + KASSERT(proc_getas() == NULL); + + /* Create a new address space. */ + as = as_create(); + if (as == NULL) { + vfs_close(v); + return ENOMEM; + } + + /* Switch to it and activate it. */ + proc_setas(as); + as_activate(); + + /* Load the executable. */ + result = load_elf(v, &entrypoint); + if (result) { + /* p_addrspace will go away when curproc is destroyed */ + vfs_close(v); + return result; + } + + /* Done with the file now. */ + vfs_close(v); + + /* Define the user stack in the address space */ + result = as_define_stack(as, &stackptr); + if (result) { + /* p_addrspace will go away when curproc is destroyed */ + return result; + } + + /* Warp to user mode. */ + enter_new_process(0 /*argc*/, NULL /*userspace addr of argv*/, + NULL /*userspace addr of environment*/, + stackptr, entrypoint); + + /* enter_new_process does not return. */ + panic("enter_new_process returned\n"); + return EINVAL; +} + diff --git a/kern/syscall/time_syscalls.c b/kern/syscall/time_syscalls.c new file mode 100644 index 0000000..87a8bf1 --- /dev/null +++ b/kern/syscall/time_syscalls.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +/* + * Example system call: get the time of day. + */ +int +sys___time(userptr_t user_seconds_ptr, userptr_t user_nanoseconds_ptr) +{ + struct timespec ts; + int result; + + gettime(&ts); + + result = copyout(&ts.tv_sec, user_seconds_ptr, sizeof(ts.tv_sec)); + if (result) { + return result; + } + + result = copyout(&ts.tv_nsec, user_nanoseconds_ptr, + sizeof(ts.tv_nsec)); + if (result) { + return result; + } + + return 0; +} diff --git a/kern/test/arraytest.c b/kern/test/arraytest.c new file mode 100644 index 0000000..b55d3a7 --- /dev/null +++ b/kern/test/arraytest.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#define TESTSIZE 73 +#define BIGTESTSIZE 3000 /* more than one page of pointers */ +#define NTH(i) ((void *)(0xb007 + 3*(i))) + +static +void +testa(struct array *a) +{ + int testarray[TESTSIZE]; + int i, j, n, r, *p; + + for (i=0; i +#include +#include +#include + +#define TESTSIZE 533 + +int +bitmaptest(int nargs, char **args) +{ + struct bitmap *b; + char data[TESTSIZE]; + uint32_t x; + int i; + + (void)nargs; + (void)args; + + kprintf("Starting bitmap test...\n"); + + for (i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SLOGAN "HODIE MIHI - CRAS TIBI\n" +#define FILENAME "fstest.tmp" +#define NCHUNKS 720 +#define NTHREADS 12 +#define NLONG 32 +#define NCREATE 24 + +static struct semaphore *threadsem = NULL; + +static +void +init_threadsem(void) +{ + if (threadsem==NULL) { + threadsem = sem_create("fstestsem", 0); + if (threadsem == NULL) { + panic("fstest: sem_create failed\n"); + } + } +} + +/* + * Vary each line of the test file in a way that's predictable but + * unlikely to mask bugs in the filesystem. + */ +static +void +rotate(char *str, int amt) +{ + int i, ch; + + amt = (amt+2600)%26; + KASSERT(amt>=0); + + for (i=0; str[i]; i++) { + ch = str[i]; + if (ch>='A' && ch<='Z') { + ch = ch - 'A'; + ch += amt; + ch %= 26; + ch = ch + 'A'; + KASSERT(ch>='A' && ch<='Z'); + } + str[i] = ch; + } +} + +//////////////////////////////////////////////////////////// + +static +void +fstest_makename(char *buf, size_t buflen, + const char *fs, const char *namesuffix) +{ + snprintf(buf, buflen, "%s:%s%s", fs, FILENAME, namesuffix); + KASSERT(strlen(buf) < buflen); +} + +#define MAKENAME() fstest_makename(name, sizeof(name), fs, namesuffix) + +static +int +fstest_remove(const char *fs, const char *namesuffix) +{ + char name[32]; + char buf[32]; + int err; + + MAKENAME(); + + strcpy(buf, name); + err = vfs_remove(buf); + if (err) { + kprintf("Could not remove %s: %s\n", name, strerror(err)); + return -1; + } + + return 0; +} + +static +int +fstest_write(const char *fs, const char *namesuffix, + int stridesize, int stridepos) +{ + struct vnode *vn; + int err; + int i; + size_t shouldbytes=0; + size_t bytes=0; + off_t pos=0; + char name[32]; + char buf[32]; + struct iovec iov; + struct uio ku; + int flags; + + KASSERT(sizeof(buf) > strlen(SLOGAN)); + + MAKENAME(); + + flags = O_WRONLY|O_CREAT; + if (stridesize == 1) { + flags |= O_TRUNC; + } + + /* vfs_open destroys the string it's passed */ + strcpy(buf, name); + err = vfs_open(buf, flags, 0664, &vn); + if (err) { + kprintf("Could not open %s for write: %s\n", + name, strerror(err)); + return -1; + } + + for (i=0; i 0) { + kprintf("%s: Short write: %lu bytes left over\n", + name, (unsigned long) ku.uio_resid); + vfs_close(vn); + vfs_remove(name); + return -1; + } + + bytes += (ku.uio_offset - pos); + shouldbytes += strlen(SLOGAN); + pos = ku.uio_offset; + } + + vfs_close(vn); + + if (bytes != shouldbytes) { + kprintf("%s: %lu bytes written, should have been %lu!\n", + name, (unsigned long) bytes, + (unsigned long) (NCHUNKS*strlen(SLOGAN))); + vfs_remove(name); + return -1; + } + kprintf("%s: %lu bytes written\n", name, (unsigned long) bytes); + + return 0; +} + +static +int +fstest_read(const char *fs, const char *namesuffix) +{ + struct vnode *vn; + int err; + int i; + size_t bytes=0; + char name[32]; + char buf[32]; + struct iovec iov; + struct uio ku; + + MAKENAME(); + + /* vfs_open destroys the string it's passed */ + strcpy(buf, name); + err = vfs_open(buf, O_RDONLY, 0664, &vn); + if (err) { + kprintf("Could not open test file for read: %s\n", + strerror(err)); + return -1; + } + + for (i=0; i 0) { + kprintf("%s: Short read: %lu bytes left over\n", name, + (unsigned long) ku.uio_resid); + vfs_close(vn); + return -1; + } + buf[strlen(SLOGAN)] = 0; + rotate(buf, -i); + if (strcmp(buf, SLOGAN)) { + kprintf("%s: Test failed: line %d mismatched: %s\n", + name, i+1, buf); + vfs_close(vn); + return -1; + } + + bytes = ku.uio_offset; + } + + vfs_close(vn); + + if (bytes != NCHUNKS*strlen(SLOGAN)) { + kprintf("%s: %lu bytes read, should have been %lu!\n", + name, (unsigned long) bytes, + (unsigned long) (NCHUNKS*strlen(SLOGAN))); + return -1; + } + kprintf("%s: %lu bytes read\n", name, (unsigned long) bytes); + return 0; +} + +//////////////////////////////////////////////////////////// + +static +void +dofstest(const char *filesys) +{ + kprintf("*** Starting filesystem test on %s:\n", filesys); + + if (fstest_write(filesys, "", 1, 0)) { + kprintf("*** Test failed\n"); + return; + } + + if (fstest_read(filesys, "")) { + kprintf("*** Test failed\n"); + return; + } + + if (fstest_remove(filesys, "")) { + kprintf("*** Test failed\n"); + return; + } + + kprintf("*** Filesystem test done\n"); +} + +//////////////////////////////////////////////////////////// + +static +void +readstress_thread(void *fs, unsigned long num) +{ + const char *filesys = fs; + if (fstest_read(filesys, "")) { + kprintf("*** Thread %lu: failed\n", num); + } + V(threadsem); +} + +static +void +doreadstress(const char *filesys) +{ + int i, err; + + init_threadsem(); + + kprintf("*** Starting fs read stress test on %s:\n", filesys); + + if (fstest_write(filesys, "", 1, 0)) { + kprintf("*** Test failed\n"); + return; + } + + for (i=0; i 0) { + kprintf("%s: Short write: %lu bytes left over\n", + name, (unsigned long) ku.uio_resid); + continue; + } + + bytes = ku.uio_offset; + if (bytes != strlen(SLOGAN)) { + kprintf("%s: %lu bytes written, expected %lu!\n", + name, (unsigned long) bytes, + (unsigned long) strlen(SLOGAN)); + continue; + } + numwritten++; + } + kprintf("Thread %lu: %u files written\n", num, numwritten); + + for (i=0; i 0) { + kprintf("%s: Short read: %lu bytes left over\n", + name, (unsigned long) ku.uio_resid); + continue; + } + + buf[strlen(SLOGAN)] = 0; + rotate(buf, -i); + + if (strcmp(buf, SLOGAN)) { + kprintf("%s: Test failed: file mismatched: %s\n", + name, buf); + continue; + } + + bytes = ku.uio_offset; + if (bytes != strlen(SLOGAN)) { + kprintf("%s: %lu bytes read, expected %lu!\n", + name, (unsigned long) bytes, + (unsigned long) strlen(SLOGAN)); + continue; + } + + numread++; + } + kprintf("Thread %lu: %u files read\n", num, numread); + + for (i=0; i 0) { + done = 1; + } + + uio_kinit(&iov, &ku, buf, sizeof(buf)-ku.uio_resid, wpos, + UIO_WRITE); + result = VOP_WRITE(wv, &ku); + if (result) { + kprintf("Write error: %s\n", strerror(result)); + break; + } + wpos = ku.uio_offset; + + if (ku.uio_resid > 0) { + kprintf("Warning: short write\n"); + } + } + + vfs_close(wv); + vfs_close(rv); + + return 0; +} diff --git a/kern/test/kmalloctest.c b/kern/test/kmalloctest.c new file mode 100644 index 0000000..6abb39c --- /dev/null +++ b/kern/test/kmalloctest.c @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Test code for kmalloc. + */ +#include +#include +#include +#include +#include +#include /* for PAGE_SIZE */ +#include + +#include "opt-dumbvm.h" + +//////////////////////////////////////////////////////////// +// km1/km2 + +/* + * Test kmalloc; allocate ITEMSIZE bytes NTRIES times, freeing + * somewhat later. + * + * The total of ITEMSIZE * NTRIES is intended to exceed the size of + * available memory. + * + * kmallocstress does the same thing, but from NTHREADS different + * threads at once. + */ + +#define NTRIES 1200 +#define ITEMSIZE 997 +#define NTHREADS 8 + +static +void +kmallocthread(void *sm, unsigned long num) +{ + struct semaphore *sem = sm; + void *ptr; + void *oldptr=NULL; + void *oldptr2=NULL; + int i; + + for (i=0; i= blocksize / sizeof(void *)) { + curblock++; + curpos = 0; + } + /* Update the running total, and rotate the size. */ + totalsize += cursize; + cursizeindex = (cursizeindex + 1) % NUM_KM3_SIZES; + } + + kprintf("kmalloctest3: %zu bytes allocated\n", totalsize); + + /* Free the objects. */ + curblock = 0; + curpos = 0; + cursizeindex = 0; + for (i=0; i= blocksize / sizeof(void *)) { + curblock++; + curpos = 0; + } + KASSERT(totalsize > 0); + totalsize -= cursize; + cursizeindex = (cursizeindex + 1) % NUM_KM3_SIZES; + } + KASSERT(totalsize == 0); + + /* Free the lower tier. */ + for (i=0; i +#include +#include + +int +nettest(int nargs, char **args) +{ + (void)nargs; + (void)args; + kprintf("No network support available\n"); + return 1; +} diff --git a/kern/test/semunit.c b/kern/test/semunit.c new file mode 100644 index 0000000..bbe6a68 --- /dev/null +++ b/kern/test/semunit.c @@ -0,0 +1,820 @@ +/* + * Copyright (c) 2015 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Unit tests for semaphores. + * + * We test 21 correctness criteria, each stated in a comment at the + * top of each test. + * + * Note that these tests go inside the semaphore abstraction to + * validate the internal state. + * + * All tests (apart from those that crash) attempt to clean up after + * running, to avoid leaking memory and leaving extra threads lying + * around. Tests with a cleanup phase call ok() before going to it in + * case the cleanup crashes -- this should not happen of course but if + * it does it should be distinguished from the main part of the test + * itself dying. + */ + +#define NAMESTRING "some-silly-name" + +//////////////////////////////////////////////////////////// +// support code + +static unsigned waiters_running = 0; +static struct spinlock waiters_lock = SPINLOCK_INITIALIZER; + +static +void +ok(void) +{ + kprintf("Test passed; now cleaning up.\n"); +} + +/* + * Wrapper for sem_create when we aren't explicitly tweaking it. + */ +static +struct semaphore * +makesem(unsigned count) +{ + struct semaphore *sem; + + sem = sem_create(NAMESTRING, count); + if (sem == NULL) { + panic("semunit: whoops: sem_create failed\n"); + } + return sem; +} + +/* + * A thread that just waits on a semaphore. + */ +static +void +waiter(void *vsem, unsigned long junk) +{ + struct semaphore *sem = vsem; + (void)junk; + + P(sem); + + spinlock_acquire(&waiters_lock); + KASSERT(waiters_running > 0); + waiters_running--; + spinlock_release(&waiters_lock); +} + +/* + * Set up a waiter. + */ +static +void +makewaiter(struct semaphore *sem) +{ + int result; + + spinlock_acquire(&waiters_lock); + waiters_running++; + spinlock_release(&waiters_lock); + + result = thread_fork("semunit waiter", NULL, waiter, sem, 0); + if (result) { + panic("semunit: thread_fork failed\n"); + } + kprintf("Sleeping for waiter to run\n"); + clocksleep(1); +} + +/* + * Spinlocks don't natively provide this, because it only makes sense + * under controlled conditions. + * + * Note that we should really read the holder atomically; but because + * we're using this under controlled conditions, it doesn't actually + * matter -- nobody is supposed to be able to touch the holder while + * we're checking it, or the check wouldn't be reliable; and, provided + * clocksleep works, nobody can. + */ +static +bool +spinlock_not_held(struct spinlock *splk) +{ + return splk->splk_holder == NULL; +} + +//////////////////////////////////////////////////////////// +// tests + +/* + * 1. After a successful sem_create: + * - sem_name compares equal to the passed-in name + * - sem_name is not the same pointer as the passed-in name + * - sem_wchan is not null + * - sem_lock is not held and has no owner + * - sem_count is the passed-in count + */ +int +semu1(int nargs, char **args) +{ + struct semaphore *sem; + const char *name = NAMESTRING; + + (void)nargs; (void)args; + + sem = sem_create(name, 56); + if (sem == NULL) { + panic("semu1: whoops: sem_create failed\n"); + } + KASSERT(!strcmp(sem->sem_name, name)); + KASSERT(sem->sem_name != name); + KASSERT(sem->sem_wchan != NULL); + KASSERT(spinlock_not_held(&sem->sem_lock)); + KASSERT(sem->sem_count == 56); + + ok(); + /* clean up */ + sem_destroy(sem); + return 0; +} + +/* + * 2. Passing a null name to sem_create asserts or crashes. + */ +int +semu2(int nargs, char **args) +{ + struct semaphore *sem; + + (void)nargs; (void)args; + + kprintf("This should crash with a kernel null dereference\n"); + sem = sem_create(NULL, 44); + (void)sem; + panic("semu2: sem_create accepted a null name\n"); + return 0; +} + +/* + * 3. Passing a null semaphore to sem_destroy asserts or crashes. + */ +int +semu3(int nargs, char **args) +{ + (void)nargs; (void)args; + + kprintf("This should assert that sem != NULL\n"); + sem_destroy(NULL); + panic("semu3: sem_destroy accepted a null semaphore\n"); +} + + +/* + * 4. sem_count is an unsigned type. + */ +int +semu4(int nargs, char **args) +{ + struct semaphore *sem; + + (void)nargs; (void)args; + + /* Create a semaphore with count 0. */ + sem = makesem(0); + /* Decrement the count. */ + sem->sem_count--; + /* This value should be positive. */ + KASSERT(sem->sem_count > 0); + + /* Clean up. */ + ok(); + sem_destroy(sem); + return 0; +} + +/* + * 5. A semaphore can be successfully initialized with a count of at + * least 0xf0000000. + */ +int +semu5(int nargs, char **args) +{ + struct semaphore *sem; + + (void)nargs; (void)args; + + sem = sem_create(NAMESTRING, 0xf0000000U); + if (sem == NULL) { + /* This might not be an innocuous malloc shortage. */ + panic("semu5: sem_create failed\n"); + } + KASSERT(sem->sem_count == 0xf0000000U); + + /* Clean up. */ + ok(); + sem_destroy(sem); + return 0; +} + +/* + * 6. Passing a semaphore with a waiting thread to sem_destroy asserts + * (in the wchan code). + */ +int +semu6(int nargs, char **args) +{ + struct semaphore *sem; + + (void)nargs; (void)args; + + sem = makesem(0); + makewaiter(sem); + kprintf("This should assert that the wchan's threadlist is empty\n"); + sem_destroy(sem); + panic("semu6: wchan_destroy with waiters succeeded\n"); + return 0; +} + +/* + * 7. Calling V on a semaphore does not block the caller, regardless + * of the semaphore count. + */ +int +semu7(int nargs, char **args) +{ + struct semaphore *sem; + struct spinlock lk; + + (void)nargs; (void)args; + + sem = makesem(0); + + /* + * Check for blocking by taking a spinlock; if we block while + * holding a spinlock, wchan_sleep will assert. + */ + spinlock_init(&lk); + spinlock_acquire(&lk); + + /* try with count 0, count 1, and count 2, just for completeness */ + V(sem); + V(sem); + V(sem); + + /* Clean up. */ + ok(); + spinlock_release(&lk); + spinlock_cleanup(&lk); + sem_destroy(sem); + return 0; +} + +/* + * 8/9. After calling V on a semaphore with no threads waiting: + * - sem_name is unchanged + * - sem_wchan is unchanged + * - sem_lock is (still) unheld and has no owner + * - sem_count is increased by one + * + * This is true even if we are in an interrupt handler. + */ +static +void +do_semu89(bool interrupthandler) +{ + struct semaphore *sem; + struct wchan *wchan; + const char *name; + + sem = makesem(0); + + /* check preconditions */ + name = sem->sem_name; + wchan = sem->sem_wchan; + KASSERT(!strcmp(name, NAMESTRING)); + KASSERT(spinlock_not_held(&sem->sem_lock)); + + /* + * The right way to this is to set up an actual interrupt, + * e.g. an interprocessor interrupt, and hook onto it to run + * the V() in the actual interrupt handler. However, that + * requires a good bit of infrastructure that we don't + * have. Instead we'll fake it by explicitly setting + * curthread->t_in_interrupt. + */ + if (interrupthandler) { + KASSERT(curthread->t_in_interrupt == false); + curthread->t_in_interrupt = true; + } + + V(sem); + + if (interrupthandler) { + KASSERT(curthread->t_in_interrupt == true); + curthread->t_in_interrupt = false; + } + + /* check postconditions */ + KASSERT(name == sem->sem_name); + KASSERT(!strcmp(name, NAMESTRING)); + KASSERT(wchan == sem->sem_wchan); + KASSERT(spinlock_not_held(&sem->sem_lock)); + KASSERT(sem->sem_count == 1); + + /* clean up */ + ok(); + sem_destroy(sem); +} + +int +semu8(int nargs, char **args) +{ + (void)nargs; (void)args; + + do_semu89(false /*interrupthandler*/); + return 0; +} + +int +semu9(int nargs, char **args) +{ + (void)nargs; (void)args; + + do_semu89(true /*interrupthandler*/); + return 0; +} + +/* + * 10/11. After calling V on a semaphore with one thread waiting, and giving + * it time to run: + * - sem_name is unchanged + * - sem_wchan is unchanged + * - sem_lock is (still) unheld and has no owner + * - sem_count is still 0 + * - the other thread does in fact run + * + * This is true even if we are in an interrupt handler. + */ +static +int +do_semu1011(bool interrupthandler) +{ + struct semaphore *sem; + struct wchan *wchan; + const char *name; + + sem = makesem(0); + makewaiter(sem); + + /* check preconditions */ + name = sem->sem_name; + wchan = sem->sem_wchan; + KASSERT(!strcmp(name, NAMESTRING)); + KASSERT(spinlock_not_held(&sem->sem_lock)); + spinlock_acquire(&waiters_lock); + KASSERT(waiters_running == 1); + spinlock_release(&waiters_lock); + + /* see above */ + if (interrupthandler) { + KASSERT(curthread->t_in_interrupt == false); + curthread->t_in_interrupt = true; + } + + V(sem); + + if (interrupthandler) { + KASSERT(curthread->t_in_interrupt == true); + curthread->t_in_interrupt = false; + } + + /* give the waiter time to exit */ + clocksleep(1); + + /* check postconditions */ + KASSERT(name == sem->sem_name); + KASSERT(!strcmp(name, NAMESTRING)); + KASSERT(wchan == sem->sem_wchan); + KASSERT(spinlock_not_held(&sem->sem_lock)); + KASSERT(sem->sem_count == 0); + spinlock_acquire(&waiters_lock); + KASSERT(waiters_running == 0); + spinlock_release(&waiters_lock); + + /* clean up */ + ok(); + sem_destroy(sem); + return 0; + +} + +int +semu10(int nargs, char **args) +{ + (void)nargs; (void)args; + + do_semu1011(false /*interrupthandler*/); + return 0; +} + +int +semu11(int nargs, char **args) +{ + (void)nargs; (void)args; + + do_semu1011(true /*interrupthandler*/); + return 0; +} + + +/* + * 12/13. After calling V on a semaphore with two threads waiting, and + * giving it time to run: + * - sem_name is unchanged + * - sem_wchan is unchanged + * - sem_lock is (still) unheld and has no owner + * - sem_count is still 0 + * - one of the other threads does in fact run + * - the other one does not + */ +static +void +semu1213(bool interrupthandler) +{ + struct semaphore *sem; + struct wchan *wchan; + const char *name; + + sem = makesem(0); + makewaiter(sem); + makewaiter(sem); + + /* check preconditions */ + name = sem->sem_name; + wchan = sem->sem_wchan; + KASSERT(!strcmp(name, NAMESTRING)); + wchan = sem->sem_wchan; + KASSERT(spinlock_not_held(&sem->sem_lock)); + spinlock_acquire(&waiters_lock); + KASSERT(waiters_running == 2); + spinlock_release(&waiters_lock); + + /* see above */ + if (interrupthandler) { + KASSERT(curthread->t_in_interrupt == false); + curthread->t_in_interrupt = true; + } + + V(sem); + + if (interrupthandler) { + KASSERT(curthread->t_in_interrupt == true); + curthread->t_in_interrupt = false; + } + + /* give the waiter time to exit */ + clocksleep(1); + + /* check postconditions */ + KASSERT(name == sem->sem_name); + KASSERT(!strcmp(name, NAMESTRING)); + KASSERT(wchan == sem->sem_wchan); + KASSERT(spinlock_not_held(&sem->sem_lock)); + KASSERT(sem->sem_count == 0); + spinlock_acquire(&waiters_lock); + KASSERT(waiters_running == 1); + spinlock_release(&waiters_lock); + + /* clean up */ + ok(); + V(sem); + clocksleep(1); + spinlock_acquire(&waiters_lock); + KASSERT(waiters_running == 0); + spinlock_release(&waiters_lock); + sem_destroy(sem); +} + +int +semu12(int nargs, char **args) +{ + (void)nargs; (void)args; + + semu1213(false /*interrupthandler*/); + return 0; +} + +int +semu13(int nargs, char **args) +{ + (void)nargs; (void)args; + + semu1213(true /*interrupthandler*/); + return 0; +} + +/* + * 14. Calling V on a semaphore whose count is the maximum allowed value + * asserts. + */ +int +semu14(int nargs, char **args) +{ + struct semaphore *sem; + + (void)nargs; (void)args; + + kprintf("This should assert that sem_count is > 0.\n"); + sem = makesem(0); + + /* + * The maximum value is (unsigned)-1. Get this by decrementing + * from 0. + */ + sem->sem_count--; + V(sem); + KASSERT(sem->sem_count == 0); + panic("semu14: V tolerated count wraparound\n"); + return 0; +} + +/* + * 15. Calling V on a null semaphore asserts. + */ +int +semu15(int nargs, char **args) +{ + (void)nargs; (void)args; + + kprintf("This should assert that the semaphore isn't null.\n"); + V(NULL); + panic("semu15: V tolerated null semaphore\n"); + return 0; +} + +/* + * 16. Calling P on a semaphore with count > 0 does not block the caller. + */ +int +semu16(int nargs, char **args) +{ + struct semaphore *sem; + struct spinlock lk; + + (void)nargs; (void)args; + + sem = makesem(1); + + /* As above, check for improper blocking by taking a spinlock. */ + spinlock_init(&lk); + spinlock_acquire(&lk); + + P(sem); + + ok(); + spinlock_release(&lk); + spinlock_cleanup(&lk); + sem_destroy(sem); + return 0; +} + +/* + * 17. Calling P on a semaphore with count == 0 does block the caller. + */ + +static struct thread *semu17_thread; + +static +void +semu17_sub(void *semv, unsigned long junk) +{ + struct semaphore *sem = semv; + + (void)junk; + + semu17_thread = curthread; + + /* precondition */ + KASSERT(sem->sem_count == 0); + + P(sem); +} + +int +semu17(int nargs, char **args) +{ + struct semaphore *sem; + int result; + + (void)nargs; (void)args; + + semu17_thread = NULL; + + sem = makesem(0); + result = thread_fork("semu17_sub", NULL, semu17_sub, sem, 0); + if (result) { + panic("semu17: whoops: thread_fork failed\n"); + } + kprintf("Waiting for subthread...\n"); + clocksleep(1); + + /* The subthread should be blocked. */ + KASSERT(semu17_thread != NULL); + KASSERT(semu17_thread->t_state == S_SLEEP); + + /* Clean up. */ + ok(); + V(sem); + clocksleep(1); + sem_destroy(sem); + semu17_thread = NULL; + return 0; +} + +/* + * 18. After calling P on a semaphore with count > 0: + * - sem_name is unchanged + * - sem_wchan is unchanged + * - sem_lock is unheld and has no owner + * - sem_count is one less + */ +int +semu18(int nargs, char **args) +{ + struct semaphore *sem; + struct wchan *wchan; + const char *name; + + (void)nargs; (void)args; + + sem = makesem(1); + + /* preconditions */ + name = sem->sem_name; + KASSERT(!strcmp(name, NAMESTRING)); + wchan = sem->sem_wchan; + KASSERT(spinlock_not_held(&sem->sem_lock)); + KASSERT(sem->sem_count == 1); + + P(sem); + + /* postconditions */ + KASSERT(name == sem->sem_name); + KASSERT(!strcmp(name, NAMESTRING)); + KASSERT(wchan == sem->sem_wchan); + KASSERT(spinlock_not_held(&sem->sem_lock)); + KASSERT(sem->sem_count == 0); + + return 0; +} + +/* + * 19. After calling P on a semaphore with count == 0 and another + * thread uses V exactly once to cause a wakeup: + * - sem_name is unchanged + * - sem_wchan is unchanged + * - sem_lock is unheld and has no owner + * - sem_count is still 0 + */ + +static +void +semu19_sub(void *semv, unsigned long junk) +{ + struct semaphore *sem = semv; + + (void)junk; + + kprintf("semu19: waiting for parent to sleep\n"); + clocksleep(1); + /* + * We could assert here that the parent *is* sleeping; but for + * that we'd need its thread pointer and it's not worth the + * trouble. + */ + V(sem); +} + +int +semu19(int nargs, char **args) +{ + struct semaphore *sem; + struct wchan *wchan; + const char *name; + int result; + + (void)nargs; (void)args; + + sem = makesem(0); + result = thread_fork("semu19_sub", NULL, semu19_sub, sem, 0); + if (result) { + panic("semu19: whoops: thread_fork failed\n"); + } + + /* preconditions */ + name = sem->sem_name; + KASSERT(!strcmp(name, NAMESTRING)); + wchan = sem->sem_wchan; + KASSERT(spinlock_not_held(&sem->sem_lock)); + KASSERT(sem->sem_count == 0); + + P(sem); + + /* postconditions */ + KASSERT(name == sem->sem_name); + KASSERT(!strcmp(name, NAMESTRING)); + KASSERT(wchan == sem->sem_wchan); + KASSERT(spinlock_not_held(&sem->sem_lock)); + KASSERT(sem->sem_count == 0); + + return 0; +} + +/* + * 20/21. Calling P in an interrupt handler asserts, regardless of the + * count. + */ +int +semu20(int nargs, char **args) +{ + struct semaphore *sem; + + (void)nargs; (void)args; + + kprintf("This should assert that we aren't in an interrupt\n"); + + sem = makesem(0); + /* as above */ + curthread->t_in_interrupt = true; + P(sem); + panic("semu20: P tolerated being in an interrupt handler\n"); + return 0; +} + +int +semu21(int nargs, char **args) +{ + struct semaphore *sem; + + (void)nargs; (void)args; + + kprintf("This should assert that we aren't in an interrupt\n"); + + sem = makesem(1); + /* as above */ + curthread->t_in_interrupt = true; + P(sem); + panic("semu21: P tolerated being in an interrupt handler\n"); + return 0; +} + +/* + * 22. Calling P on a null semaphore asserts. + */ +int +semu22(int nargs, char **args) +{ + (void)nargs; (void)args; + + kprintf("This should assert that the semaphore isn't null.\n"); + P(NULL); + panic("semu22: P tolerated null semaphore\n"); + return 0; +} diff --git a/kern/test/synchtest.c b/kern/test/synchtest.c new file mode 100644 index 0000000..c5582e2 --- /dev/null +++ b/kern/test/synchtest.c @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Synchronization test code. + */ + +#include +#include +#include +#include +#include +#include + +#define NSEMLOOPS 63 +#define NLOCKLOOPS 120 +#define NCVLOOPS 5 +#define NTHREADS 32 + +static volatile unsigned long testval1; +static volatile unsigned long testval2; +static volatile unsigned long testval3; +static struct semaphore *testsem; +static struct lock *testlock; +static struct cv *testcv; +static struct semaphore *donesem; + +static +void +inititems(void) +{ + if (testsem==NULL) { + testsem = sem_create("testsem", 2); + if (testsem == NULL) { + panic("synchtest: sem_create failed\n"); + } + } + if (testlock==NULL) { + testlock = lock_create("testlock"); + if (testlock == NULL) { + panic("synchtest: lock_create failed\n"); + } + } + if (testcv==NULL) { + testcv = cv_create("testlock"); + if (testcv == NULL) { + panic("synchtest: cv_create failed\n"); + } + } + if (donesem==NULL) { + donesem = sem_create("donesem", 0); + if (donesem == NULL) { + panic("synchtest: sem_create failed\n"); + } + } +} + +static +void +semtestthread(void *junk, unsigned long num) +{ + int i; + (void)junk; + + /* + * Only one of these should print at a time. + */ + P(testsem); + kprintf("Thread %2lu: ", num); + for (i=0; i +#include +#include +#include +#include + +#define NUMNAMES 7 +static const char *const names[NUMNAMES] = { + "Aillard", + "Aldaran", + "Alton", + "Ardais", + "Elhalyn", + "Hastur", + "Ridenow", +}; + +static struct thread *fakethreads[NUMNAMES]; + +//////////////////////////////////////////////////////////// +// fakethread + +#define FAKE_MAGIC ((void *)0xbaabaa) + +/* + * Create a dummy struct thread that we can put on lists for testing. + */ +static +struct thread * +fakethread_create(const char *name) +{ + struct thread *t; + + t = kmalloc(sizeof(*t)); + if (t == NULL) { + panic("threadlisttest: Out of memory\n"); + } + /* ignore most of the fields, zero everything for tidiness */ + bzero(t, sizeof(*t)); + t->t_name = kstrdup(name); + if (t->t_name == NULL) { + panic("threadlisttest: Out of memory\n"); + } + t->t_stack = FAKE_MAGIC; + threadlistnode_init(&t->t_listnode, t); + return t; +} + +/* + * Destroy a fake thread. + */ +static +void +fakethread_destroy(struct thread *t) +{ + KASSERT(t->t_stack == FAKE_MAGIC); + threadlistnode_cleanup(&t->t_listnode); + kfree(t->t_name); + kfree(t); +} + +//////////////////////////////////////////////////////////// +// support stuff + +static +void +check_order(struct threadlist *tl, bool rev) +{ + const char string0[] = "..."; + const char stringN[] = "~~~"; + + struct thread *t; + const char *first = rev ? stringN : string0; + const char *last = rev ? string0 : stringN; + const char *prev; + int cmp; + + prev = first; + THREADLIST_FORALL(t, *tl) { + cmp = strcmp(prev, t->t_name); + KASSERT(rev ? (cmp > 0) : (cmp < 0)); + prev = t->t_name; + } + cmp = strcmp(prev, last); + KASSERT(rev ? (cmp > 0) : (cmp < 0)); +} + +//////////////////////////////////////////////////////////// +// tests + +static +void +threadlisttest_a(void) +{ + struct threadlist tl; + + threadlist_init(&tl); + KASSERT(threadlist_isempty(&tl)); + threadlist_cleanup(&tl); +} + +static +void +threadlisttest_b(void) +{ + struct threadlist tl; + struct thread *t; + + threadlist_init(&tl); + + threadlist_addhead(&tl, fakethreads[0]); + check_order(&tl, false); + check_order(&tl, true); + KASSERT(tl.tl_count == 1); + t = threadlist_remhead(&tl); + KASSERT(tl.tl_count == 0); + KASSERT(t == fakethreads[0]); + + threadlist_addtail(&tl, fakethreads[0]); + check_order(&tl, false); + check_order(&tl, true); + KASSERT(tl.tl_count == 1); + t = threadlist_remtail(&tl); + KASSERT(tl.tl_count == 0); + KASSERT(t == fakethreads[0]); + + threadlist_cleanup(&tl); +} + +static +void +threadlisttest_c(void) +{ + struct threadlist tl; + struct thread *t; + + threadlist_init(&tl); + + threadlist_addhead(&tl, fakethreads[0]); + threadlist_addhead(&tl, fakethreads[1]); + KASSERT(tl.tl_count == 2); + + check_order(&tl, true); + + t = threadlist_remhead(&tl); + KASSERT(t == fakethreads[1]); + t = threadlist_remhead(&tl); + KASSERT(t == fakethreads[0]); + KASSERT(tl.tl_count == 0); + + threadlist_addtail(&tl, fakethreads[0]); + threadlist_addtail(&tl, fakethreads[1]); + KASSERT(tl.tl_count == 2); + + check_order(&tl, false); + + t = threadlist_remtail(&tl); + KASSERT(t == fakethreads[1]); + t = threadlist_remtail(&tl); + KASSERT(t == fakethreads[0]); + KASSERT(tl.tl_count == 0); + + threadlist_cleanup(&tl); +} + +static +void +threadlisttest_d(void) +{ + struct threadlist tl; + struct thread *t; + + threadlist_init(&tl); + + threadlist_addhead(&tl, fakethreads[0]); + threadlist_addtail(&tl, fakethreads[1]); + KASSERT(tl.tl_count == 2); + + check_order(&tl, false); + + t = threadlist_remhead(&tl); + KASSERT(t == fakethreads[0]); + t = threadlist_remtail(&tl); + KASSERT(t == fakethreads[1]); + KASSERT(tl.tl_count == 0); + + threadlist_addhead(&tl, fakethreads[0]); + threadlist_addtail(&tl, fakethreads[1]); + KASSERT(tl.tl_count == 2); + + check_order(&tl, false); + + t = threadlist_remtail(&tl); + KASSERT(t == fakethreads[1]); + t = threadlist_remtail(&tl); + KASSERT(t == fakethreads[0]); + KASSERT(tl.tl_count == 0); + + threadlist_cleanup(&tl); +} + +static +void +threadlisttest_e(void) +{ + struct threadlist tl; + struct thread *t; + unsigned i; + + threadlist_init(&tl); + + threadlist_addhead(&tl, fakethreads[1]); + threadlist_addtail(&tl, fakethreads[3]); + KASSERT(tl.tl_count == 2); + check_order(&tl, false); + + threadlist_insertafter(&tl, fakethreads[3], fakethreads[4]); + KASSERT(tl.tl_count == 3); + check_order(&tl, false); + + threadlist_insertbefore(&tl, fakethreads[0], fakethreads[1]); + KASSERT(tl.tl_count == 4); + check_order(&tl, false); + + threadlist_insertafter(&tl, fakethreads[1], fakethreads[2]); + KASSERT(tl.tl_count == 5); + check_order(&tl, false); + + KASSERT(fakethreads[4]->t_listnode.tln_prev->tln_self == + fakethreads[3]); + KASSERT(fakethreads[3]->t_listnode.tln_prev->tln_self == + fakethreads[2]); + KASSERT(fakethreads[2]->t_listnode.tln_prev->tln_self == + fakethreads[1]); + KASSERT(fakethreads[1]->t_listnode.tln_prev->tln_self == + fakethreads[0]); + + for (i=0; i<5; i++) { + t = threadlist_remhead(&tl); + KASSERT(t == fakethreads[i]); + } + KASSERT(tl.tl_count == 0); + + threadlist_cleanup(&tl); +} + +static +void +threadlisttest_f(void) +{ + struct threadlist tl; + struct thread *t; + unsigned i; + + threadlist_init(&tl); + + for (i=0; i +#include +#include +#include +#include + +#define NTHREADS 8 + +static struct semaphore *tsem = NULL; + +static +void +init_sem(void) +{ + if (tsem==NULL) { + tsem = sem_create("tsem", 0); + if (tsem == NULL) { + panic("threadtest: sem_create failed\n"); + } + } +} + +static +void +loudthread(void *junk, unsigned long num) +{ + int ch = '0' + num; + int i; + + (void)junk; + + for (i=0; i<120; i++) { + putch(ch); + } + V(tsem); +} + +/* + * The idea with this is that you should see + * + * 01234567 01234567 + * + * (possibly with the numbers in different orders) + * + * The delay loop is supposed to be long enough that it should be clear + * if either timeslicing or the scheduler is not working right. + */ +static +void +quietthread(void *junk, unsigned long num) +{ + int ch = '0' + num; + volatile int i; + + (void)junk; + + putch(ch); + for (i=0; i<200000; i++); + putch(ch); + + V(tsem); +} + +static +void +runthreads(int doloud) +{ + char name[16]; + int i, result; + + for (i=0; i +#include +#include +#include +#include +#include + +/* dimension of matrices (cannot be too large or will overflow stack) */ + +#define DIM 70 + +/* number of iterations for sleepalot threads */ +#define SLEEPALOT_PRINTS 20 /* number of printouts */ +#define SLEEPALOT_ITERS 4 /* iterations per printout */ +/* polling frequency of waker thread */ +#define WAKER_WAKES 100 +/* number of iterations per compute thread */ +#define COMPUTE_ITERS 10 + +/* N distinct wait channels */ +#define NWAITCHANS 12 +static struct spinlock spinlocks[NWAITCHANS]; +static struct wchan *waitchans[NWAITCHANS]; + +static volatile int wakerdone; +static struct semaphore *wakersem; +static struct semaphore *donesem; + +static +void +setup(void) +{ + char tmp[16]; + int i; + + if (wakersem == NULL) { + wakersem = sem_create("wakersem", 1); + donesem = sem_create("donesem", 0); + for (i=0; im[i][j] = rand >> 16; + m2->m[i][j] = rand & 0xffff; + } + } + + for (i=0; im[i][k] * m2->m[k][j]; + } + m3->m[i][j] = tot; + } + } + + tot = 0; + for (i=0; im[i][i]; + } + + kprintf("{%lu: %u}", num, (unsigned) tot); + thread_yield(); + } + + kfree(m1); + kfree(m2); + kfree(m3); + + V(donesem); +} + +static +void +make_computes(int howmany) +{ + char name[16]; + int i, result; + + for (i=0; i +#include +#include +#include +#include +#include +#include + +/* + * Time handling. + * + * This is pretty primitive. A real kernel will typically have some + * kind of support for scheduling callbacks to happen at specific + * points in the future, usually with more resolution than one second. + * + * A real kernel also has to maintain the time of day; in OS/161 we + * skimp on that because we have a known-good hardware clock. + */ + +/* + * Timing constants. These should be tuned along with any work done on + * the scheduler. + */ +#define SCHEDULE_HARDCLOCKS 4 /* Reschedule every 4 hardclocks. */ +#define MIGRATE_HARDCLOCKS 16 /* Migrate every 16 hardclocks. */ + +/* + * Once a second, everything waiting on lbolt is awakened by CPU 0. + */ +static struct wchan *lbolt; +static struct spinlock lbolt_lock; + +/* + * Setup. + */ +void +hardclock_bootstrap(void) +{ + spinlock_init(&lbolt_lock); + lbolt = wchan_create("lbolt"); + if (lbolt == NULL) { + panic("Couldn't create lbolt\n"); + } +} + +/* + * This is called once per second, on one processor, by the timer + * code. + */ +void +timerclock(void) +{ + /* Just broadcast on lbolt */ + spinlock_acquire(&lbolt_lock); + wchan_wakeall(lbolt, &lbolt_lock); + spinlock_release(&lbolt_lock); +} + +/* + * This is called HZ times a second (on each processor) by the timer + * code. + */ +void +hardclock(void) +{ + /* + * Collect statistics here as desired. + */ + + curcpu->c_hardclocks++; + if ((curcpu->c_hardclocks % MIGRATE_HARDCLOCKS) == 0) { + thread_consider_migration(); + } + if ((curcpu->c_hardclocks % SCHEDULE_HARDCLOCKS) == 0) { + schedule(); + } + thread_yield(); +} + +/* + * Suspend execution for n seconds. + */ +void +clocksleep(int num_secs) +{ + spinlock_acquire(&lbolt_lock); + while (num_secs > 0) { + wchan_sleep(lbolt, &lbolt_lock); + num_secs--; + } + spinlock_release(&lbolt_lock); +} diff --git a/kern/thread/hangman.c b/kern/thread/hangman.c new file mode 100644 index 0000000..127167a --- /dev/null +++ b/kern/thread/hangman.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2015 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Simple deadlock detector. + */ + +#include +#include +#include +#include +#include + +static struct spinlock hangman_lock = SPINLOCK_INITIALIZER; + +/* + * Look for a path through the waits-for graph that goes from START to + * TARGET. + * + * Because lockables can only be held by one actor, and actors can + * only be waiting for one thing at a time, this turns out to be + * quite simple. + */ +static +void +hangman_check(const struct hangman_lockable *start, + const struct hangman_actor *target) +{ + const struct hangman_actor *cur; + + cur = start->l_holding; + while (cur != NULL) { + if (cur == target) { + goto found; + } + if (cur->a_waiting == NULL) { + break; + } + cur = cur->a_waiting->l_holding; + } + return; + + found: + /* + * None of this can change while we print it (that's the point + * of it being a deadlock) so drop hangman_lock while + * printing; otherwise we can come back via kprintf_spinlock + * and that makes a mess. But force splhigh() explicitly so + * the console prints in polled mode and to discourage other + * things from running in the middle of the printout. + */ + splhigh(); + spinlock_release(&hangman_lock); + + kprintf("hangman: Detected lock cycle!\n"); + kprintf("hangman: in %s (%p);\n", target->a_name, target); + kprintf("hangman: waiting for %s (%p), but:\n", start->l_name, start); + kprintf(" lockable %s (%p)\n", start->l_name, start); + cur = start->l_holding; + while (cur != target) { + kprintf(" held by actor %s (%p)\n", cur->a_name, cur); + kprintf(" waiting for lockable %s (%p)\n", + cur->a_waiting->l_name, cur->a_waiting); + cur = cur->a_waiting->l_holding; + } + kprintf(" held by actor %s (%p)\n", cur->a_name, cur); + panic("Deadlock.\n"); +} + +/* + * Note that a is about to wait for l. + * + * Note that there's no point calling this if a isn't going to wait, + * because in that case l->l_holding will be null and the check + * won't go anywhere. + * + * One could also maintain in memory a graph of all requests ever + * seen, in order to detect lock order inversions that haven't + * actually deadlocked; but there are a lot of ways in which this is + * tricky and problematic. For now we'll settle for just detecting and + * reporting deadlocks that do happen. + */ +void +hangman_wait(struct hangman_actor *a, + struct hangman_lockable *l) +{ + if (l == &hangman_lock.splk_hangman) { + /* don't recurse */ + return; + } + + spinlock_acquire(&hangman_lock); + + if (a->a_waiting != NULL) { + spinlock_release(&hangman_lock); + panic("hangman_wait: already waiting for something?\n"); + } + + hangman_check(l, a); + a->a_waiting = l; + + spinlock_release(&hangman_lock); +} + +void +hangman_acquire(struct hangman_actor *a, + struct hangman_lockable *l) +{ + if (l == &hangman_lock.splk_hangman) { + /* don't recurse */ + return; + } + + spinlock_acquire(&hangman_lock); + + if (a->a_waiting != l) { + spinlock_release(&hangman_lock); + panic("hangman_acquire: not waiting for lock %s (%p)\n", + l->l_name, l); + } + if (l->l_holding != NULL) { + spinlock_release(&hangman_lock); + panic("hangman_acquire: lock %s (%p) still held by %s (%p)\n", + l->l_name, l, a->a_name, a); + } + + l->l_holding = a; + a->a_waiting = NULL; + + spinlock_release(&hangman_lock); +} + +void +hangman_release(struct hangman_actor *a, + struct hangman_lockable *l) +{ + if (l == &hangman_lock.splk_hangman) { + /* don't recurse */ + return; + } + + spinlock_acquire(&hangman_lock); + + if (a->a_waiting != NULL) { + spinlock_release(&hangman_lock); + panic("hangman_release: waiting for something?\n"); + } + if (l->l_holding != a) { + spinlock_release(&hangman_lock); + panic("hangman_release: not the holder\n"); + } + + l->l_holding = NULL; + + spinlock_release(&hangman_lock); +} diff --git a/kern/thread/spinlock.c b/kern/thread/spinlock.c new file mode 100644 index 0000000..0cdf9aa --- /dev/null +++ b/kern/thread/spinlock.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Make sure to build out-of-line versions of inline functions */ +#define SPINLOCK_INLINE /* empty */ +#define MEMBAR_INLINE /* empty */ + +#include +#include +#include +#include +#include +#include +#include /* for curcpu */ + +/* + * Spinlocks. + */ + + +/* + * Initialize spinlock. + */ +void +spinlock_init(struct spinlock *splk) +{ + spinlock_data_set(&splk->splk_lock, 0); + splk->splk_holder = NULL; + HANGMAN_LOCKABLEINIT(&splk->splk_hangman, "spinlock"); +} + +/* + * Clean up spinlock. + */ +void +spinlock_cleanup(struct spinlock *splk) +{ + KASSERT(splk->splk_holder == NULL); + KASSERT(spinlock_data_get(&splk->splk_lock) == 0); +} + +/* + * Get the lock. + * + * First disable interrupts (otherwise, if we get a timer interrupt we + * might come back to this lock and deadlock), then use a machine-level + * atomic operation to wait for the lock to be free. + */ +void +spinlock_acquire(struct spinlock *splk) +{ + struct cpu *mycpu; + + splraise(IPL_NONE, IPL_HIGH); + + /* this must work before curcpu initialization */ + if (CURCPU_EXISTS()) { + mycpu = curcpu->c_self; + if (splk->splk_holder == mycpu) { + panic("Deadlock on spinlock %p\n", splk); + } + mycpu->c_spinlocks++; + + HANGMAN_WAIT(&curcpu->c_hangman, &splk->splk_hangman); + } + else { + mycpu = NULL; + } + + while (1) { + /* + * Do test-test-and-set, that is, read first before + * doing test-and-set, to reduce bus contention. + * + * Test-and-set is a machine-level atomic operation + * that writes 1 into the lock word and returns the + * previous value. If that value was 0, the lock was + * previously unheld and we now own it. If it was 1, + * we don't. + */ + if (spinlock_data_get(&splk->splk_lock) != 0) { + continue; + } + if (spinlock_data_testandset(&splk->splk_lock) != 0) { + continue; + } + break; + } + + membar_store_any(); + splk->splk_holder = mycpu; + + if (CURCPU_EXISTS()) { + HANGMAN_ACQUIRE(&curcpu->c_hangman, &splk->splk_hangman); + } +} + +/* + * Release the lock. + */ +void +spinlock_release(struct spinlock *splk) +{ + /* this must work before curcpu initialization */ + if (CURCPU_EXISTS()) { + KASSERT(splk->splk_holder == curcpu->c_self); + KASSERT(curcpu->c_spinlocks > 0); + curcpu->c_spinlocks--; + HANGMAN_RELEASE(&curcpu->c_hangman, &splk->splk_hangman); + } + + splk->splk_holder = NULL; + membar_any_store(); + spinlock_data_set(&splk->splk_lock, 0); + spllower(IPL_HIGH, IPL_NONE); +} + +/* + * Check if the current cpu holds the lock. + */ +bool +spinlock_do_i_hold(struct spinlock *splk) +{ + if (!CURCPU_EXISTS()) { + return true; + } + + /* Assume we can read splk_holder atomically enough for this to work */ + return (splk->splk_holder == curcpu->c_self); +} diff --git a/kern/thread/spl.c b/kern/thread/spl.c new file mode 100644 index 0000000..cbdfef9 --- /dev/null +++ b/kern/thread/spl.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Make sure to build out-of-line versions of spl inline functions */ +#define SPL_INLINE /* empty */ + +#include +#include +#include +#include +#include +#include + +/* + * Machine-independent interrupt handling functions. + * + * Traditionally, all this code is machine-dependent. + * + * However. + * + * Since on OS/161 we don't support interrupt levels on any platform, + * all we require under this logic is cpu_irqoff() and cpu_irqon() + * that explicitly turn interrupts off and on. + * + * If we had multiple interrupt levels, the number of levels would in + * general be different on different platforms (depending on hardware + * requirements and hardware capabilities) so things would get more + * complicated -- but nearly all of this code could remain MI. + */ + + +/* + * Raise and lower the interrupt priority level. + * + * Each spinlock acquisition can raise and lower the priority level + * independently. The spl calls also raise and lower the priority + * level independently of the spinlocks. This is necessary because in + * general spinlock acquisitions and releases don't nest perfectly, + * and don't necessarily nest with respect to spl calls either. + * + * For example: + * + * struct spinlock red, blue; + * int s; + * + * spinlock_acquire(&red); + * s = splhigh(); + * spinlock_acquire(&blue); + * splx(s); + * spinlock_release(&red); + * spinlock_release(&blue); + * + * In order to make this work we need to count the number of times + * IPL_HIGH (or, if we had multiple interrupt priority levels, each + * level independently) has been raised. Interrupts go off on the + * first raise, and go on again only on the last lower. + * + * curthread->t_iplhigh_count is used to track this. + */ +void +splraise(int oldspl, int newspl) +{ + struct thread *cur = curthread; + + /* only one priority level, only one valid args configuration */ + KASSERT(oldspl == IPL_NONE); + KASSERT(newspl == IPL_HIGH); + + if (!CURCPU_EXISTS()) { + /* before curcpu initialization; interrupts are off anyway */ + return; + } + + if (cur->t_iplhigh_count == 0) { + cpu_irqoff(); + } + cur->t_iplhigh_count++; +} + +void +spllower(int oldspl, int newspl) +{ + struct thread *cur = curthread; + + /* only one priority level, only one valid args configuration */ + KASSERT(oldspl == IPL_HIGH); + KASSERT(newspl == IPL_NONE); + + if (!CURCPU_EXISTS()) { + /* before curcpu initialization; interrupts are off anyway */ + return; + } + + cur->t_iplhigh_count--; + if (cur->t_iplhigh_count == 0) { + cpu_irqon(); + } +} + + +/* + * Disable or enable interrupts and adjust curspl setting. Return old + * spl level. + */ +int +splx(int spl) +{ + struct thread *cur = curthread; + int ret; + + if (!CURCPU_EXISTS()) { + /* before curcpu initialization; interrupts are off anyway */ + return spl; + } + + if (cur->t_curspl < spl) { + /* turning interrupts off */ + splraise(cur->t_curspl, spl); + ret = cur->t_curspl; + cur->t_curspl = spl; + } + else if (cur->t_curspl > spl) { + /* turning interrupts on */ + ret = cur->t_curspl; + cur->t_curspl = spl; + spllower(ret, spl); + } + else { + /* do nothing */ + ret = spl; + } + + return ret; +} diff --git a/kern/thread/synch.c b/kern/thread/synch.c new file mode 100644 index 0000000..ad58934 --- /dev/null +++ b/kern/thread/synch.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Synchronization primitives. + * The specifications of the functions are in synch.h. + */ + +#include +#include +#include +#include +#include +#include +#include + +//////////////////////////////////////////////////////////// +// +// Semaphore. + +struct semaphore * +sem_create(const char *name, unsigned initial_count) +{ + struct semaphore *sem; + + sem = kmalloc(sizeof(*sem)); + if (sem == NULL) { + return NULL; + } + + sem->sem_name = kstrdup(name); + if (sem->sem_name == NULL) { + kfree(sem); + return NULL; + } + + sem->sem_wchan = wchan_create(sem->sem_name); + if (sem->sem_wchan == NULL) { + kfree(sem->sem_name); + kfree(sem); + return NULL; + } + + spinlock_init(&sem->sem_lock); + sem->sem_count = initial_count; + + return sem; +} + +void +sem_destroy(struct semaphore *sem) +{ + KASSERT(sem != NULL); + + /* wchan_cleanup will assert if anyone's waiting on it */ + spinlock_cleanup(&sem->sem_lock); + wchan_destroy(sem->sem_wchan); + kfree(sem->sem_name); + kfree(sem); +} + +void +P(struct semaphore *sem) +{ + KASSERT(sem != NULL); + + /* + * May not block in an interrupt handler. + * + * For robustness, always check, even if we can actually + * complete the P without blocking. + */ + KASSERT(curthread->t_in_interrupt == false); + + /* Use the semaphore spinlock to protect the wchan as well. */ + spinlock_acquire(&sem->sem_lock); + while (sem->sem_count == 0) { + /* + * + * Note that we don't maintain strict FIFO ordering of + * threads going through the semaphore; that is, we + * might "get" it on the first try even if other + * threads are waiting. Apparently according to some + * textbooks semaphores must for some reason have + * strict ordering. Too bad. :-) + * + * Exercise: how would you implement strict FIFO + * ordering? + */ + wchan_sleep(sem->sem_wchan, &sem->sem_lock); + } + KASSERT(sem->sem_count > 0); + sem->sem_count--; + spinlock_release(&sem->sem_lock); +} + +void +V(struct semaphore *sem) +{ + KASSERT(sem != NULL); + + spinlock_acquire(&sem->sem_lock); + + sem->sem_count++; + KASSERT(sem->sem_count > 0); + wchan_wakeone(sem->sem_wchan, &sem->sem_lock); + + spinlock_release(&sem->sem_lock); +} + +//////////////////////////////////////////////////////////// +// +// Lock. + +struct lock * +lock_create(const char *name) +{ + struct lock *lock; + + lock = kmalloc(sizeof(*lock)); + if (lock == NULL) { + return NULL; + } + + lock->lk_name = kstrdup(name); + if (lock->lk_name == NULL) { + kfree(lock); + return NULL; + } + + HANGMAN_LOCKABLEINIT(&lock->lk_hangman, lock->lk_name); + + // add stuff here as needed + + return lock; +} + +void +lock_destroy(struct lock *lock) +{ + KASSERT(lock != NULL); + + // add stuff here as needed + + kfree(lock->lk_name); + kfree(lock); +} + +void +lock_acquire(struct lock *lock) +{ + /* Call this (atomically) before waiting for a lock */ + //HANGMAN_WAIT(&curthread->t_hangman, &lock->lk_hangman); + + // Write this + + (void)lock; // suppress warning until code gets written + + /* Call this (atomically) once the lock is acquired */ + //HANGMAN_ACQUIRE(&curthread->t_hangman, &lock->lk_hangman); +} + +void +lock_release(struct lock *lock) +{ + /* Call this (atomically) when the lock is released */ + //HANGMAN_RELEASE(&curthread->t_hangman, &lock->lk_hangman); + + // Write this + + (void)lock; // suppress warning until code gets written +} + +bool +lock_do_i_hold(struct lock *lock) +{ + // Write this + + (void)lock; // suppress warning until code gets written + + return true; // dummy until code gets written +} + +//////////////////////////////////////////////////////////// +// +// CV + + +struct cv * +cv_create(const char *name) +{ + struct cv *cv; + + cv = kmalloc(sizeof(*cv)); + if (cv == NULL) { + return NULL; + } + + cv->cv_name = kstrdup(name); + if (cv->cv_name==NULL) { + kfree(cv); + return NULL; + } + + // add stuff here as needed + + return cv; +} + +void +cv_destroy(struct cv *cv) +{ + KASSERT(cv != NULL); + + // add stuff here as needed + + kfree(cv->cv_name); + kfree(cv); +} + +void +cv_wait(struct cv *cv, struct lock *lock) +{ + // Write this + (void)cv; // suppress warning until code gets written + (void)lock; // suppress warning until code gets written +} + +void +cv_signal(struct cv *cv, struct lock *lock) +{ + // Write this + (void)cv; // suppress warning until code gets written + (void)lock; // suppress warning until code gets written +} + +void +cv_broadcast(struct cv *cv, struct lock *lock) +{ + // Write this + (void)cv; // suppress warning until code gets written + (void)lock; // suppress warning until code gets written +} diff --git a/kern/thread/thread.c b/kern/thread/thread.c new file mode 100644 index 0000000..e6fe983 --- /dev/null +++ b/kern/thread/thread.c @@ -0,0 +1,1212 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2010 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Core kernel-level thread system. + */ + +#define THREADINLINE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Magic number used as a guard value on kernel thread stacks. */ +#define THREAD_STACK_MAGIC 0xbaadf00d + +/* Wait channel. A wchan is protected by an associated, passed-in spinlock. */ +struct wchan { + const char *wc_name; /* name for this channel */ + struct threadlist wc_threads; /* list of waiting threads */ +}; + +/* Master array of CPUs. */ +DECLARRAY(cpu, static __UNUSED inline); +DEFARRAY(cpu, static __UNUSED inline); +static struct cpuarray allcpus; + +/* Used to wait for secondary CPUs to come online. */ +static struct semaphore *cpu_startup_sem; + +//////////////////////////////////////////////////////////// + +/* + * Stick a magic number on the bottom end of the stack. This will + * (sometimes) catch kernel stack overflows. Use thread_checkstack() + * to test this. + */ +static +void +thread_checkstack_init(struct thread *thread) +{ + ((uint32_t *)thread->t_stack)[0] = THREAD_STACK_MAGIC; + ((uint32_t *)thread->t_stack)[1] = THREAD_STACK_MAGIC; + ((uint32_t *)thread->t_stack)[2] = THREAD_STACK_MAGIC; + ((uint32_t *)thread->t_stack)[3] = THREAD_STACK_MAGIC; +} + +/* + * Check the magic number we put on the bottom end of the stack in + * thread_checkstack_init. If these assertions go off, it most likely + * means you overflowed your stack at some point, which can cause all + * kinds of mysterious other things to happen. + * + * Note that when ->t_stack is NULL, which is the case if the stack + * cannot be freed (which in turn is the case if the stack is the boot + * stack, and the thread is the boot thread) this doesn't do anything. + */ +static +void +thread_checkstack(struct thread *thread) +{ + if (thread->t_stack != NULL) { + KASSERT(((uint32_t*)thread->t_stack)[0] == THREAD_STACK_MAGIC); + KASSERT(((uint32_t*)thread->t_stack)[1] == THREAD_STACK_MAGIC); + KASSERT(((uint32_t*)thread->t_stack)[2] == THREAD_STACK_MAGIC); + KASSERT(((uint32_t*)thread->t_stack)[3] == THREAD_STACK_MAGIC); + } +} + +/* + * Create a thread. This is used both to create a first thread + * for each CPU and to create subsequent forked threads. + */ +static +struct thread * +thread_create(const char *name) +{ + struct thread *thread; + + DEBUGASSERT(name != NULL); + + thread = kmalloc(sizeof(*thread)); + if (thread == NULL) { + return NULL; + } + + thread->t_name = kstrdup(name); + if (thread->t_name == NULL) { + kfree(thread); + return NULL; + } + thread->t_wchan_name = "NEW"; + thread->t_state = S_READY; + + /* Thread subsystem fields */ + thread_machdep_init(&thread->t_machdep); + threadlistnode_init(&thread->t_listnode, thread); + thread->t_stack = NULL; + thread->t_context = NULL; + thread->t_cpu = NULL; + thread->t_proc = NULL; + HANGMAN_ACTORINIT(&thread->t_hangman, thread->t_name); + + /* Interrupt state fields */ + thread->t_in_interrupt = false; + thread->t_curspl = IPL_HIGH; + thread->t_iplhigh_count = 1; /* corresponding to t_curspl */ + + /* If you add to struct thread, be sure to initialize here */ + + return thread; +} + +/* + * Create a CPU structure. This is used for the bootup CPU and + * also for secondary CPUs. + * + * The hardware number (the number assigned by firmware or system + * board config or whatnot) is tracked separately because it is not + * necessarily anything sane or meaningful. + */ +struct cpu * +cpu_create(unsigned hardware_number) +{ + struct cpu *c; + int result; + char namebuf[16]; + + c = kmalloc(sizeof(*c)); + if (c == NULL) { + panic("cpu_create: Out of memory\n"); + } + + c->c_self = c; + c->c_hardware_number = hardware_number; + + c->c_curthread = NULL; + threadlist_init(&c->c_zombies); + c->c_hardclocks = 0; + c->c_spinlocks = 0; + + c->c_isidle = false; + threadlist_init(&c->c_runqueue); + spinlock_init(&c->c_runqueue_lock); + + c->c_ipi_pending = 0; + c->c_numshootdown = 0; + spinlock_init(&c->c_ipi_lock); + + result = cpuarray_add(&allcpus, c, &c->c_number); + if (result != 0) { + panic("cpu_create: array_add: %s\n", strerror(result)); + } + + snprintf(namebuf, sizeof(namebuf), "", c->c_number); + c->c_curthread = thread_create(namebuf); + if (c->c_curthread == NULL) { + panic("cpu_create: thread_create failed\n"); + } + c->c_curthread->t_cpu = c; + + if (c->c_number == 0) { + /* + * Leave c->c_curthread->t_stack NULL for the boot + * cpu. This means we're using the boot stack, which + * can't be freed. (Exercise: what would it take to + * make it possible to free the boot stack?) + */ + /*c->c_curthread->t_stack = ... */ + } + else { + c->c_curthread->t_stack = kmalloc(STACK_SIZE); + if (c->c_curthread->t_stack == NULL) { + panic("cpu_create: couldn't allocate stack"); + } + thread_checkstack_init(c->c_curthread); + } + + /* + * If there is no curcpu (or curthread) yet, we are creating + * the first (boot) cpu. Initialize curcpu and curthread as + * early as possible so that other code can take locks without + * exploding. + */ + if (!CURCPU_EXISTS()) { + /* + * Initializing curcpu and curthread is + * machine-dependent because either of curcpu and + * curthread might be defined in terms of the other. + */ + INIT_CURCPU(c, c->c_curthread); + + /* + * Now make sure both t_cpu and c_curthread are + * set. This might be partially redundant with + * INIT_CURCPU depending on how things are defined. + */ + curthread->t_cpu = curcpu; + curcpu->c_curthread = curthread; + } + + HANGMAN_ACTORINIT(&c->c_hangman, "cpu"); + + result = proc_addthread(kproc, c->c_curthread); + if (result) { + panic("cpu_create: proc_addthread:: %s\n", strerror(result)); + } + + cpu_machdep_init(c); + + return c; +} + +/* + * Destroy a thread. + * + * This function cannot be called in the victim thread's own context. + * Nor can it be called on a running thread. + * + * (Freeing the stack you're actually using to run is ... inadvisable.) + */ +static +void +thread_destroy(struct thread *thread) +{ + KASSERT(thread != curthread); + KASSERT(thread->t_state != S_RUN); + + /* + * If you add things to struct thread, be sure to clean them up + * either here or in thread_exit(). (And not both...) + */ + + /* Thread subsystem fields */ + KASSERT(thread->t_proc == NULL); + if (thread->t_stack != NULL) { + kfree(thread->t_stack); + } + threadlistnode_cleanup(&thread->t_listnode); + thread_machdep_cleanup(&thread->t_machdep); + + /* sheer paranoia */ + thread->t_wchan_name = "DESTROYED"; + + kfree(thread->t_name); + kfree(thread); +} + +/* + * Clean up zombies. (Zombies are threads that have exited but still + * need to have thread_destroy called on them.) + * + * The list of zombies is per-cpu. + */ +static +void +exorcise(void) +{ + struct thread *z; + + while ((z = threadlist_remhead(&curcpu->c_zombies)) != NULL) { + KASSERT(z != curthread); + KASSERT(z->t_state == S_ZOMBIE); + thread_destroy(z); + } +} + +/* + * On panic, stop the thread system (as much as is reasonably + * possible) to make sure we don't end up letting any other threads + * run. + */ +void +thread_panic(void) +{ + /* + * Kill off other CPUs. + * + * We could wait for them to stop, except that they might not. + */ + ipi_broadcast(IPI_PANIC); + + /* + * Drop runnable threads on the floor. + * + * Don't try to get the run queue lock; we might not be able + * to. Instead, blat the list structure by hand, and take the + * risk that it might not be quite atomic. + */ + curcpu->c_runqueue.tl_count = 0; + curcpu->c_runqueue.tl_head.tln_next = &curcpu->c_runqueue.tl_tail; + curcpu->c_runqueue.tl_tail.tln_prev = &curcpu->c_runqueue.tl_head; + + /* + * Ideally, we want to make sure sleeping threads don't wake + * up and start running. However, there's no good way to track + * down all the wchans floating around the system. Another + * alternative would be to set a global flag to make the wchan + * wakeup operations do nothing; but that would mean we + * ourselves couldn't sleep to wait for an I/O completion + * interrupt, and we'd like to be able to do that if the + * system isn't that badly hosed. + * + * So, do nothing else here. + * + * This may prove inadequate in practice and further steps + * might be needed. It may also be necessary to go through and + * forcibly unlock all locks or the like... + */ +} + +/* + * At system shutdown, ask the other CPUs to switch off. + */ +void +thread_shutdown(void) +{ + /* + * Stop the other CPUs. + * + * We should probably wait for them to stop and shut them off + * on the system board. + */ + ipi_broadcast(IPI_OFFLINE); +} + +/* + * Thread system initialization. + */ +void +thread_bootstrap(void) +{ + cpuarray_init(&allcpus); + + /* + * Create the cpu structure for the bootup CPU, the one we're + * currently running on. Assume the hardware number is 0; that + * might be updated later by mainbus-type code. This also + * creates a thread structure for the first thread, the one + * that's already implicitly running when the kernel is + * started from the bootloader. + */ + KASSERT(CURCPU_EXISTS() == false); + (void)cpu_create(0); + KASSERT(CURCPU_EXISTS() == true); + + /* cpu_create() should also have set t_proc. */ + KASSERT(curcpu != NULL); + KASSERT(curthread != NULL); + KASSERT(curthread->t_proc != NULL); + KASSERT(curthread->t_proc == kproc); + + /* Done */ +} + +/* + * New CPUs come here once MD initialization is finished. curthread + * and curcpu should already be initialized. + * + * Other than clearing thread_start_cpus() to continue, we don't need + * to do anything. The startup thread can just exit; we only need it + * to be able to get into thread_switch() properly. + */ +void +cpu_hatch(unsigned software_number) +{ + char buf[64]; + + KASSERT(curcpu != NULL); + KASSERT(curthread != NULL); + KASSERT(curcpu->c_number == software_number); + + spl0(); + cpu_identify(buf, sizeof(buf)); + + kprintf("cpu%u: %s\n", software_number, buf); + + V(cpu_startup_sem); + thread_exit(); +} + +/* + * Start up secondary cpus. Called from boot(). + */ +void +thread_start_cpus(void) +{ + char buf[64]; + unsigned i; + + cpu_identify(buf, sizeof(buf)); + kprintf("cpu0: %s\n", buf); + + cpu_startup_sem = sem_create("cpu_hatch", 0); + mainbus_start_cpus(); + + for (i=0; it_cpu; + + if (already_have_lock) { + /* The target thread's cpu should be already locked. */ + KASSERT(spinlock_do_i_hold(&targetcpu->c_runqueue_lock)); + } + else { + spinlock_acquire(&targetcpu->c_runqueue_lock); + } + + /* Target thread is now ready to run; put it on the run queue. */ + target->t_state = S_READY; + threadlist_addtail(&targetcpu->c_runqueue, target); + + if (targetcpu->c_isidle && targetcpu != curcpu->c_self) { + /* + * Other processor is idle; send interrupt to make + * sure it unidles. + */ + ipi_send(targetcpu, IPI_UNIDLE); + } + + if (!already_have_lock) { + spinlock_release(&targetcpu->c_runqueue_lock); + } +} + +/* + * Create a new thread based on an existing one. + * + * The new thread has name NAME, and starts executing in function + * ENTRYPOINT. DATA1 and DATA2 are passed to ENTRYPOINT. + * + * The new thread is created in the process P. If P is null, the + * process is inherited from the caller. It will start on the same CPU + * as the caller, unless the scheduler intervenes first. + */ +int +thread_fork(const char *name, + struct proc *proc, + void (*entrypoint)(void *data1, unsigned long data2), + void *data1, unsigned long data2) +{ + struct thread *newthread; + int result; + + newthread = thread_create(name); + if (newthread == NULL) { + return ENOMEM; + } + + /* Allocate a stack */ + newthread->t_stack = kmalloc(STACK_SIZE); + if (newthread->t_stack == NULL) { + thread_destroy(newthread); + return ENOMEM; + } + thread_checkstack_init(newthread); + + /* + * Now we clone various fields from the parent thread. + */ + + /* Thread subsystem fields */ + newthread->t_cpu = curthread->t_cpu; + + /* Attach the new thread to its process */ + if (proc == NULL) { + proc = curthread->t_proc; + } + result = proc_addthread(proc, newthread); + if (result) { + /* thread_destroy will clean up the stack */ + thread_destroy(newthread); + return result; + } + + /* + * Because new threads come out holding the cpu runqueue lock + * (see notes at bottom of thread_switch), we need to account + * for the spllower() that will be done releasing it. + */ + newthread->t_iplhigh_count++; + + /* Set up the switchframe so entrypoint() gets called */ + switchframe_init(newthread, entrypoint, data1, data2); + + /* Lock the current cpu's run queue and make the new thread runnable */ + thread_make_runnable(newthread, false); + + return 0; +} + +/* + * High level, machine-independent context switch code. + * + * The current thread is queued appropriately and its state is changed + * to NEWSTATE; another thread to run is selected and switched to. + * + * If NEWSTATE is S_SLEEP, the thread is queued on the wait channel + * WC, protected by the spinlock LK. Otherwise WC and Lk should be + * NULL. + */ +static +void +thread_switch(threadstate_t newstate, struct wchan *wc, struct spinlock *lk) +{ + struct thread *cur, *next; + int spl; + + DEBUGASSERT(curcpu->c_curthread == curthread); + DEBUGASSERT(curthread->t_cpu == curcpu->c_self); + + /* Explicitly disable interrupts on this processor */ + spl = splhigh(); + + cur = curthread; + + /* + * If we're idle, return without doing anything. This happens + * when the timer interrupt interrupts the idle loop. + */ + if (curcpu->c_isidle) { + splx(spl); + return; + } + + /* Check the stack guard band. */ + thread_checkstack(cur); + + /* Lock the run queue. */ + spinlock_acquire(&curcpu->c_runqueue_lock); + + /* Micro-optimization: if nothing to do, just return */ + if (newstate == S_READY && threadlist_isempty(&curcpu->c_runqueue)) { + spinlock_release(&curcpu->c_runqueue_lock); + splx(spl); + return; + } + + /* Put the thread in the right place. */ + switch (newstate) { + case S_RUN: + panic("Illegal S_RUN in thread_switch\n"); + case S_READY: + thread_make_runnable(cur, true /*have lock*/); + break; + case S_SLEEP: + cur->t_wchan_name = wc->wc_name; + /* + * Add the thread to the list in the wait channel, and + * unlock same. To avoid a race with someone else + * calling wchan_wake*, we must keep the wchan's + * associated spinlock locked from the point the + * caller of wchan_sleep locked it until the thread is + * on the list. + */ + threadlist_addtail(&wc->wc_threads, cur); + spinlock_release(lk); + break; + case S_ZOMBIE: + cur->t_wchan_name = "ZOMBIE"; + threadlist_addtail(&curcpu->c_zombies, cur); + break; + } + cur->t_state = newstate; + + /* + * Get the next thread. While there isn't one, call cpu_idle(). + * curcpu->c_isidle must be true when cpu_idle is + * called. Unlock the runqueue while idling too, to make sure + * things can be added to it. + * + * Note that we don't need to unlock the runqueue atomically + * with idling; becoming unidle requires receiving an + * interrupt (either a hardware interrupt or an interprocessor + * interrupt from another cpu posting a wakeup) and idling + * *is* atomic with respect to re-enabling interrupts. + * + * Note that c_isidle becomes true briefly even if we don't go + * idle. However, because one is supposed to hold the runqueue + * lock to look at it, this should not be visible or matter. + */ + + /* The current cpu is now idle. */ + curcpu->c_isidle = true; + do { + next = threadlist_remhead(&curcpu->c_runqueue); + if (next == NULL) { + spinlock_release(&curcpu->c_runqueue_lock); + cpu_idle(); + spinlock_acquire(&curcpu->c_runqueue_lock); + } + } while (next == NULL); + curcpu->c_isidle = false; + + /* + * Note that curcpu->c_curthread may be the same variable as + * curthread and it may not be, depending on how curthread and + * curcpu are defined by the MD code. We'll assign both and + * assume the compiler will optimize one away if they're the + * same. + */ + curcpu->c_curthread = next; + curthread = next; + + /* do the switch (in assembler in switch.S) */ + switchframe_switch(&cur->t_context, &next->t_context); + + /* + * When we get to this point we are either running in the next + * thread, or have come back to the same thread again, + * depending on how you look at it. That is, + * switchframe_switch returns immediately in another thread + * context, which in general will be executing here with a + * different stack and different values in the local + * variables. (Although new threads go to thread_startup + * instead.) But, later on when the processor, or some + * processor, comes back to the previous thread, it's also + * executing here with the *same* value in the local + * variables. + * + * The upshot, however, is as follows: + * + * - The thread now currently running is "cur", not "next", + * because when we return from switchrame_switch on the + * same stack, we're back to the thread that + * switchframe_switch call switched away from, which is + * "cur". + * + * - "cur" is _not_ the thread that just *called* + * switchframe_switch. + * + * - If newstate is S_ZOMB we never get back here in that + * context at all. + * + * - If the thread just chosen to run ("next") was a new + * thread, we don't get to this code again until + * *another* context switch happens, because when new + * threads return from switchframe_switch they teleport + * to thread_startup. + * + * - At this point the thread whose stack we're now on may + * have been migrated to another cpu since it last ran. + * + * The above is inherently confusing and will probably take a + * while to get used to. + * + * However, the important part is that code placed here, after + * the call to switchframe_switch, does not necessarily run on + * every context switch. Thus any such code must be either + * skippable on some switches or also called from + * thread_startup. + */ + + + /* Clear the wait channel and set the thread state. */ + cur->t_wchan_name = NULL; + cur->t_state = S_RUN; + + /* Unlock the run queue. */ + spinlock_release(&curcpu->c_runqueue_lock); + + /* Activate our address space in the MMU. */ + as_activate(); + + /* Clean up dead threads. */ + exorcise(); + + /* Turn interrupts back on. */ + splx(spl); +} + +/* + * This function is where new threads start running. The arguments + * ENTRYPOINT, DATA1, and DATA2 are passed through from thread_fork. + * + * Because new code comes here from inside the middle of + * thread_switch, the beginning part of this function must match the + * tail of thread_switch. + */ +void +thread_startup(void (*entrypoint)(void *data1, unsigned long data2), + void *data1, unsigned long data2) +{ + struct thread *cur; + + cur = curthread; + + /* Clear the wait channel and set the thread state. */ + cur->t_wchan_name = NULL; + cur->t_state = S_RUN; + + /* Release the runqueue lock acquired in thread_switch. */ + spinlock_release(&curcpu->c_runqueue_lock); + + /* Activate our address space in the MMU. */ + as_activate(); + + /* Clean up dead threads. */ + exorcise(); + + /* Enable interrupts. */ + spl0(); + + /* Call the function. */ + entrypoint(data1, data2); + + /* Done. */ + thread_exit(); +} + +/* + * Cause the current thread to exit. + * + * The parts of the thread structure we don't actually need to run + * should be cleaned up right away. The rest has to wait until + * thread_destroy is called from exorcise(). + * + * Does not return. + */ +void +thread_exit(void) +{ + struct thread *cur; + + cur = curthread; + + /* + * Detach from our process. You might need to move this action + * around, depending on how your wait/exit works. + */ + proc_remthread(cur); + + /* Make sure we *are* detached (move this only if you're sure!) */ + KASSERT(cur->t_proc == NULL); + + /* Check the stack guard band. */ + thread_checkstack(cur); + + /* Interrupts off on this processor */ + splhigh(); + thread_switch(S_ZOMBIE, NULL, NULL); + panic("braaaaaaaiiiiiiiiiiinssssss\n"); +} + +/* + * Yield the cpu to another process, but stay runnable. + */ +void +thread_yield(void) +{ + thread_switch(S_READY, NULL, NULL); +} + +//////////////////////////////////////////////////////////// + +/* + * Scheduler. + * + * This is called periodically from hardclock(). It should reshuffle + * the current CPU's run queue by job priority. + */ + +void +schedule(void) +{ + /* + * You can write this. If we do nothing, threads will run in + * round-robin fashion. + */ +} + +/* + * Thread migration. + * + * This is also called periodically from hardclock(). If the current + * CPU is busy and other CPUs are idle, or less busy, it should move + * threads across to those other other CPUs. + * + * Migrating threads isn't free because of cache affinity; a thread's + * working cache set will end up having to be moved to the other CPU, + * which is fairly slow. The tradeoff between this performance loss + * and the performance loss due to underutilization of some CPUs is + * something that needs to be tuned and probably is workload-specific. + * + * For here and now, because we know we're running on System/161 and + * System/161 does not (yet) model such cache effects, we'll be very + * aggressive. + */ +void +thread_consider_migration(void) +{ + unsigned my_count, total_count, one_share, to_send; + unsigned i, numcpus; + struct cpu *c; + struct threadlist victims; + struct thread *t; + + my_count = total_count = 0; + numcpus = cpuarray_num(&allcpus); + for (i=0; ic_runqueue_lock); + total_count += c->c_runqueue.tl_count; + if (c == curcpu->c_self) { + my_count = c->c_runqueue.tl_count; + } + spinlock_release(&c->c_runqueue_lock); + } + + one_share = DIVROUNDUP(total_count, numcpus); + if (my_count < one_share) { + return; + } + + to_send = my_count - one_share; + threadlist_init(&victims); + spinlock_acquire(&curcpu->c_runqueue_lock); + for (i=0; ic_runqueue); + threadlist_addhead(&victims, t); + } + spinlock_release(&curcpu->c_runqueue_lock); + + for (i=0; i < numcpus && to_send > 0; i++) { + c = cpuarray_get(&allcpus, i); + if (c == curcpu->c_self) { + continue; + } + spinlock_acquire(&c->c_runqueue_lock); + while (c->c_runqueue.tl_count < one_share && to_send > 0) { + t = threadlist_remhead(&victims); + /* + * Ordinarily, curthread will not appear on + * the run queue. However, it can under the + * following circumstances: + * - it went to sleep; + * - the processor became idle, so it + * remained curthread; + * - it was reawakened, so it was put on the + * run queue; + * - and the processor hasn't fully unidled + * yet, so all these things are still true. + * + * If the timer interrupt happens at (almost) + * exactly the proper moment, we can come here + * while things are in this state and see + * curthread. However, *migrating* curthread + * can cause bad things to happen (Exercise: + * Why? And what?) so shuffle it to the end of + * the list and decrement to_send in order to + * skip it. Then it goes back on our own run + * queue below. + */ + if (t == curthread) { + threadlist_addtail(&victims, t); + to_send--; + continue; + } + + t->t_cpu = c; + threadlist_addtail(&c->c_runqueue, t); + DEBUG(DB_THREADS, + "Migrated thread %s: cpu %u -> %u", + t->t_name, curcpu->c_number, c->c_number); + to_send--; + if (c->c_isidle) { + /* + * Other processor is idle; send + * interrupt to make sure it unidles. + */ + ipi_send(c, IPI_UNIDLE); + } + } + spinlock_release(&c->c_runqueue_lock); + } + + /* + * Because the code above isn't atomic, the thread counts may have + * changed while we were working and we may end up with leftovers. + * Don't panic; just put them back on our own run queue. + */ + if (!threadlist_isempty(&victims)) { + spinlock_acquire(&curcpu->c_runqueue_lock); + while ((t = threadlist_remhead(&victims)) != NULL) { + threadlist_addtail(&curcpu->c_runqueue, t); + } + spinlock_release(&curcpu->c_runqueue_lock); + } + + KASSERT(threadlist_isempty(&victims)); + threadlist_cleanup(&victims); +} + +//////////////////////////////////////////////////////////// + +/* + * Wait channel functions + */ + +/* + * Create a wait channel. NAME is a symbolic string name for it. + * This is what's displayed by ps -alx in Unix. + * + * NAME should generally be a string constant. If it isn't, alternate + * arrangements should be made to free it after the wait channel is + * destroyed. + */ +struct wchan * +wchan_create(const char *name) +{ + struct wchan *wc; + + wc = kmalloc(sizeof(*wc)); + if (wc == NULL) { + return NULL; + } + threadlist_init(&wc->wc_threads); + wc->wc_name = name; + + return wc; +} + +/* + * Destroy a wait channel. Must be empty and unlocked. + * (The corresponding cleanup functions require this.) + */ +void +wchan_destroy(struct wchan *wc) +{ + threadlist_cleanup(&wc->wc_threads); + kfree(wc); +} + +/* + * Yield the cpu to another process, and go to sleep, on the specified + * wait channel WC, whose associated spinlock is LK. Calling wakeup on + * the channel will make the thread runnable again. The spinlock must + * be locked. The call to thread_switch unlocks it; we relock it + * before returning. + */ +void +wchan_sleep(struct wchan *wc, struct spinlock *lk) +{ + /* may not sleep in an interrupt handler */ + KASSERT(!curthread->t_in_interrupt); + + /* must hold the spinlock */ + KASSERT(spinlock_do_i_hold(lk)); + + /* must not hold other spinlocks */ + KASSERT(curcpu->c_spinlocks == 1); + + thread_switch(S_SLEEP, wc, lk); + spinlock_acquire(lk); +} + +/* + * Wake up one thread sleeping on a wait channel. + */ +void +wchan_wakeone(struct wchan *wc, struct spinlock *lk) +{ + struct thread *target; + + KASSERT(spinlock_do_i_hold(lk)); + + /* Grab a thread from the channel */ + target = threadlist_remhead(&wc->wc_threads); + + if (target == NULL) { + /* Nobody was sleeping. */ + return; + } + + /* + * Note that thread_make_runnable acquires a runqueue lock + * while we're holding LK. This is ok; all spinlocks + * associated with wchans must come before the runqueue locks, + * as we also bridge from the wchan lock to the runqueue lock + * in thread_switch. + */ + + thread_make_runnable(target, false); +} + +/* + * Wake up all threads sleeping on a wait channel. + */ +void +wchan_wakeall(struct wchan *wc, struct spinlock *lk) +{ + struct thread *target; + struct threadlist list; + + KASSERT(spinlock_do_i_hold(lk)); + + threadlist_init(&list); + + /* + * Grab all the threads from the channel, moving them to a + * private list. + */ + while ((target = threadlist_remhead(&wc->wc_threads)) != NULL) { + threadlist_addtail(&list, target); + } + + /* + * We could conceivably sort by cpu first to cause fewer lock + * ops and fewer IPIs, but for now at least don't bother. Just + * make each thread runnable. + */ + while ((target = threadlist_remhead(&list)) != NULL) { + thread_make_runnable(target, false); + } + + threadlist_cleanup(&list); +} + +/* + * Return nonzero if there are no threads sleeping on the channel. + * This is meant to be used only for diagnostic purposes. + */ +bool +wchan_isempty(struct wchan *wc, struct spinlock *lk) +{ + bool ret; + + KASSERT(spinlock_do_i_hold(lk)); + ret = threadlist_isempty(&wc->wc_threads); + + return ret; +} + +//////////////////////////////////////////////////////////// + +/* + * Machine-independent IPI handling + */ + +/* + * Send an IPI (inter-processor interrupt) to the specified CPU. + */ +void +ipi_send(struct cpu *target, int code) +{ + KASSERT(code >= 0 && code < 32); + + spinlock_acquire(&target->c_ipi_lock); + target->c_ipi_pending |= (uint32_t)1 << code; + mainbus_send_ipi(target); + spinlock_release(&target->c_ipi_lock); +} + +/* + * Send an IPI to all CPUs. + */ +void +ipi_broadcast(int code) +{ + unsigned i; + struct cpu *c; + + for (i=0; i < cpuarray_num(&allcpus); i++) { + c = cpuarray_get(&allcpus, i); + if (c != curcpu->c_self) { + ipi_send(c, code); + } + } +} + +/* + * Send a TLB shootdown IPI to the specified CPU. + */ +void +ipi_tlbshootdown(struct cpu *target, const struct tlbshootdown *mapping) +{ + unsigned n; + + spinlock_acquire(&target->c_ipi_lock); + + n = target->c_numshootdown; + if (n == TLBSHOOTDOWN_MAX) { + /* + * If you have problems with this panic going off, + * consider: (1) increasing the maximum, (2) putting + * logic here to sleep until space appears (may + * interact awkwardly with VM system locking), (3) + * putting logic here to coalesce requests together, + * and/or (4) improving VM system state tracking to + * reduce the number of unnecessary shootdowns. + */ + panic("ipi_tlbshootdown: Too many shootdowns queued\n"); + } + else { + target->c_shootdown[n] = *mapping; + target->c_numshootdown = n+1; + } + + target->c_ipi_pending |= (uint32_t)1 << IPI_TLBSHOOTDOWN; + mainbus_send_ipi(target); + + spinlock_release(&target->c_ipi_lock); +} + +/* + * Handle an incoming interprocessor interrupt. + */ +void +interprocessor_interrupt(void) +{ + uint32_t bits; + unsigned i; + + spinlock_acquire(&curcpu->c_ipi_lock); + bits = curcpu->c_ipi_pending; + + if (bits & (1U << IPI_PANIC)) { + /* panic on another cpu - just stop dead */ + spinlock_release(&curcpu->c_ipi_lock); + cpu_halt(); + } + if (bits & (1U << IPI_OFFLINE)) { + /* offline request */ + spinlock_release(&curcpu->c_ipi_lock); + spinlock_acquire(&curcpu->c_runqueue_lock); + if (!curcpu->c_isidle) { + kprintf("cpu%d: offline: warning: not idle\n", + curcpu->c_number); + } + spinlock_release(&curcpu->c_runqueue_lock); + kprintf("cpu%d: offline.\n", curcpu->c_number); + cpu_halt(); + } + if (bits & (1U << IPI_UNIDLE)) { + /* + * The cpu has already unidled itself to take the + * interrupt; don't need to do anything else. + */ + } + if (bits & (1U << IPI_TLBSHOOTDOWN)) { + /* + * Note: depending on your VM system locking you might + * need to release the ipi lock while calling + * vm_tlbshootdown. + */ + for (i=0; ic_numshootdown; i++) { + vm_tlbshootdown(&curcpu->c_shootdown[i]); + } + curcpu->c_numshootdown = 0; + } + + curcpu->c_ipi_pending = 0; + spinlock_release(&curcpu->c_ipi_lock); +} diff --git a/kern/thread/threadlist.c b/kern/thread/threadlist.c new file mode 100644 index 0000000..7ae0595 --- /dev/null +++ b/kern/thread/threadlist.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Thread list functions, rather dull. + */ + +#include +#include +#include +#include + +void +threadlistnode_init(struct threadlistnode *tln, struct thread *t) +{ + DEBUGASSERT(tln != NULL); + KASSERT(t != NULL); + + tln->tln_next = NULL; + tln->tln_prev = NULL; + tln->tln_self = t; +} + +void +threadlistnode_cleanup(struct threadlistnode *tln) +{ + DEBUGASSERT(tln != NULL); + + KASSERT(tln->tln_next == NULL); + KASSERT(tln->tln_prev == NULL); + KASSERT(tln->tln_self != NULL); +} + +void +threadlist_init(struct threadlist *tl) +{ + DEBUGASSERT(tl != NULL); + + tl->tl_head.tln_next = &tl->tl_tail; + tl->tl_head.tln_prev = NULL; + tl->tl_tail.tln_next = NULL; + tl->tl_tail.tln_prev = &tl->tl_head; + tl->tl_head.tln_self = NULL; + tl->tl_tail.tln_self = NULL; + tl->tl_count = 0; +} + +void +threadlist_cleanup(struct threadlist *tl) +{ + DEBUGASSERT(tl != NULL); + DEBUGASSERT(tl->tl_head.tln_next == &tl->tl_tail); + DEBUGASSERT(tl->tl_head.tln_prev == NULL); + DEBUGASSERT(tl->tl_tail.tln_next == NULL); + DEBUGASSERT(tl->tl_tail.tln_prev == &tl->tl_head); + DEBUGASSERT(tl->tl_head.tln_self == NULL); + DEBUGASSERT(tl->tl_tail.tln_self == NULL); + + KASSERT(threadlist_isempty(tl)); + KASSERT(tl->tl_count == 0); + + /* nothing (else) to do */ +} + +bool +threadlist_isempty(struct threadlist *tl) +{ + DEBUGASSERT(tl != NULL); + + return (tl->tl_count == 0); +} + +//////////////////////////////////////////////////////////// +// internal + +/* + * Do insertion. Doesn't update tl_count. + */ +static +void +threadlist_insertafternode(struct threadlistnode *onlist, struct thread *t) +{ + struct threadlistnode *addee; + + addee = &t->t_listnode; + + DEBUGASSERT(addee->tln_prev == NULL); + DEBUGASSERT(addee->tln_next == NULL); + + addee->tln_prev = onlist; + addee->tln_next = onlist->tln_next; + addee->tln_prev->tln_next = addee; + addee->tln_next->tln_prev = addee; +} + +/* + * Do insertion. Doesn't update tl_count. + */ +static +void +threadlist_insertbeforenode(struct thread *t, struct threadlistnode *onlist) +{ + struct threadlistnode *addee; + + addee = &t->t_listnode; + + DEBUGASSERT(addee->tln_prev == NULL); + DEBUGASSERT(addee->tln_next == NULL); + + addee->tln_prev = onlist->tln_prev; + addee->tln_next = onlist; + addee->tln_prev->tln_next = addee; + addee->tln_next->tln_prev = addee; +} + +/* + * Do removal. Doesn't update tl_count. + */ +static +void +threadlist_removenode(struct threadlistnode *tln) +{ + DEBUGASSERT(tln != NULL); + DEBUGASSERT(tln->tln_prev != NULL); + DEBUGASSERT(tln->tln_next != NULL); + + tln->tln_prev->tln_next = tln->tln_next; + tln->tln_next->tln_prev = tln->tln_prev; + tln->tln_prev = NULL; + tln->tln_next = NULL; +} + +//////////////////////////////////////////////////////////// +// public + +void +threadlist_addhead(struct threadlist *tl, struct thread *t) +{ + DEBUGASSERT(tl != NULL); + DEBUGASSERT(t != NULL); + + threadlist_insertafternode(&tl->tl_head, t); + tl->tl_count++; +} + +void +threadlist_addtail(struct threadlist *tl, struct thread *t) +{ + DEBUGASSERT(tl != NULL); + DEBUGASSERT(t != NULL); + + threadlist_insertbeforenode(t, &tl->tl_tail); + tl->tl_count++; +} + +struct thread * +threadlist_remhead(struct threadlist *tl) +{ + struct threadlistnode *tln; + + DEBUGASSERT(tl != NULL); + + tln = tl->tl_head.tln_next; + if (tln->tln_next == NULL) { + /* list was empty */ + return NULL; + } + threadlist_removenode(tln); + DEBUGASSERT(tl->tl_count > 0); + tl->tl_count--; + return tln->tln_self; +} + +struct thread * +threadlist_remtail(struct threadlist *tl) +{ + struct threadlistnode *tln; + + DEBUGASSERT(tl != NULL); + + tln = tl->tl_tail.tln_prev; + if (tln->tln_prev == NULL) { + /* list was empty */ + return NULL; + } + threadlist_removenode(tln); + DEBUGASSERT(tl->tl_count > 0); + tl->tl_count--; + return tln->tln_self; +} + +void +threadlist_insertafter(struct threadlist *tl, + struct thread *onlist, struct thread *addee) +{ + threadlist_insertafternode(&onlist->t_listnode, addee); + tl->tl_count++; +} + +void +threadlist_insertbefore(struct threadlist *tl, + struct thread *addee, struct thread *onlist) +{ + threadlist_insertbeforenode(addee, &onlist->t_listnode); + tl->tl_count++; +} + +void +threadlist_remove(struct threadlist *tl, struct thread *t) +{ + threadlist_removenode(&t->t_listnode); + DEBUGASSERT(tl->tl_count > 0); + tl->tl_count--; +} diff --git a/kern/vfs/device.c b/kern/vfs/device.c new file mode 100644 index 0000000..a591749 --- /dev/null +++ b/kern/vfs/device.c @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Vnode operations for VFS devices. + * + * These hand off to the functions in the VFS device structure (see dev.h) + * but take care of a bunch of common tasks in a uniform fashion. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Called for each open(). + * + * We reject O_APPEND. + */ +static +int +dev_eachopen(struct vnode *v, int flags) +{ + struct device *d = v->vn_data; + + if (flags & (O_CREAT | O_TRUNC | O_EXCL | O_APPEND)) { + return EINVAL; + } + + return DEVOP_EACHOPEN(d, flags); +} + +/* + * Called when the vnode refcount reaches zero. + * Do nothing; devices are permanent. + */ +static +int +dev_reclaim(struct vnode *v) +{ + (void)v; + /* nothing - device continues to exist even when not in use */ + return 0; +} + +/* + * Check a seek position. + * + * For block devices, require block alignment. + * For character devices, we should prohibit seeking entirely, but + * for the moment we need to accept any position. (XXX) + */ +static +int +dev_tryseek(struct device *d, off_t pos) +{ + if (d->d_blocks > 0) { + if ((pos % d->d_blocksize)!=0) { + /* not block-aligned */ + return EINVAL; + } + if (pos / d->d_blocksize >= d->d_blocks) { + /* off the end */ + return EINVAL; + } + } + else { + //return ESPIPE; + } + return 0; +} + +/* + * Called for read. Hand off to DEVOP_IO. + */ +static +int +dev_read(struct vnode *v, struct uio *uio) +{ + struct device *d = v->vn_data; + int result; + + result = dev_tryseek(d, uio->uio_offset); + if (result) { + return result; + } + + KASSERT(uio->uio_rw == UIO_READ); + return DEVOP_IO(d, uio); +} + +/* + * Called for write. Hand off to DEVOP_IO. + */ +static +int +dev_write(struct vnode *v, struct uio *uio) +{ + struct device *d = v->vn_data; + int result; + + result = dev_tryseek(d, uio->uio_offset); + if (result) { + return result; + } + + KASSERT(uio->uio_rw == UIO_WRITE); + return DEVOP_IO(d, uio); +} + +/* + * Called for ioctl(). Just pass through. + */ +static +int +dev_ioctl(struct vnode *v, int op, userptr_t data) +{ + struct device *d = v->vn_data; + return DEVOP_IOCTL(d, op, data); +} + +/* + * Called for stat(). + * Set the type and the size (block devices only). + * The link count for a device is always 1. + */ +static +int +dev_stat(struct vnode *v, struct stat *statbuf) +{ + struct device *d = v->vn_data; + int result; + + bzero(statbuf, sizeof(struct stat)); + + if (d->d_blocks > 0) { + statbuf->st_size = d->d_blocks * d->d_blocksize; + statbuf->st_blksize = d->d_blocksize; + } + else { + statbuf->st_size = 0; + } + + result = VOP_GETTYPE(v, &statbuf->st_mode); + if (result) { + return result; + } + /* Make up some plausible default permissions. */ + statbuf->st_mode |= 0600; + + statbuf->st_nlink = 1; + statbuf->st_blocks = d->d_blocks; + + /* The device number this device sits on (in OS/161, it doesn't) */ + statbuf->st_dev = 0; + + /* The device number this device *is* */ + statbuf->st_rdev = d->d_devnumber; + + return 0; +} + +/* + * Return the type. A device is a "block device" if it has a known + * length. A device that generates data in a stream is a "character + * device". + */ +static +int +dev_gettype(struct vnode *v, mode_t *ret) +{ + struct device *d = v->vn_data; + if (d->d_blocks > 0) { + *ret = S_IFBLK; + } + else { + *ret = S_IFCHR; + } + return 0; +} + +/* + * Check if seeking is allowed. + */ +static +bool +dev_isseekable(struct vnode *v) +{ + struct device *d = v->vn_data; + + if (d->d_blocks == 0) { + return false; + } + return true; +} + +/* + * For fsync() - meaningless, do nothing. + */ +static +int +null_fsync(struct vnode *v) +{ + (void)v; + return 0; +} + +/* + * For mmap. If you want this to do anything, you have to write it + * yourself. Some devices may not make sense to map. Others do. + */ +static +int +dev_mmap(struct vnode *v /* add stuff as needed */) +{ + (void)v; + return ENOSYS; +} + +/* + * For ftruncate(). + */ +static +int +dev_truncate(struct vnode *v, off_t len) +{ + struct device *d = v->vn_data; + + /* + * Allow truncating to the object's own size, if it has one. + */ + if (d->d_blocks > 0 && (off_t)(d->d_blocks*d->d_blocksize) == len) { + return 0; + } + + return EINVAL; +} + +/* + * For namefile (which implements "pwd") + * + * This should never be reached, as it's not possible to chdir to a + * device vnode. + */ +static +int +dev_namefile(struct vnode *v, struct uio *uio) +{ + /* + * The name of a device is always just "device:". The VFS + * layer puts in the device name for us, so we don't need to + * do anything further. + */ + + (void)v; + (void)uio; + + return 0; +} + +/* + * Name lookup. + * + * One interesting feature of device:name pathname syntax is that you + * can implement pathnames on arbitrary devices. For instance, if you + * had a graphics device that supported multiple resolutions (which we + * don't), you might arrange things so that you could open it with + * pathnames like "video:800x600/24bpp" in order to select the operating + * mode. + * + * However, we have no support for this in the base system. + */ +static +int +dev_lookup(struct vnode *dir, + char *pathname, struct vnode **result) +{ + /* + * If the path was "device:", we get "". For that, return self. + * Anything else is an error. + * Increment the ref count of the vnode before returning it. + */ + if (strlen(pathname)>0) { + return ENOENT; + } + VOP_INCREF(dir); + *result = dir; + return 0; +} + +/* + * Function table for device vnodes. + */ +static const struct vnode_ops dev_vnode_ops = { + .vop_magic = VOP_MAGIC, + + .vop_eachopen = dev_eachopen, + .vop_reclaim = dev_reclaim, + .vop_read = dev_read, + .vop_readlink = vopfail_uio_inval, + .vop_getdirentry = vopfail_uio_notdir, + .vop_write = dev_write, + .vop_ioctl = dev_ioctl, + .vop_stat = dev_stat, + .vop_gettype = dev_gettype, + .vop_isseekable = dev_isseekable, + .vop_fsync = null_fsync, + .vop_mmap = dev_mmap, + .vop_truncate = dev_truncate, + .vop_namefile = dev_namefile, + .vop_creat = vopfail_creat_notdir, + .vop_symlink = vopfail_symlink_notdir, + .vop_mkdir = vopfail_mkdir_notdir, + .vop_link = vopfail_link_notdir, + .vop_remove = vopfail_string_notdir, + .vop_rmdir = vopfail_string_notdir, + .vop_rename = vopfail_rename_notdir, + .vop_lookup = dev_lookup, + .vop_lookparent = vopfail_lookparent_notdir, +}; + +/* + * Function to create a vnode for a VFS device. + */ +struct vnode * +dev_create_vnode(struct device *dev) +{ + int result; + struct vnode *v; + + v = kmalloc(sizeof(struct vnode)); + if (v==NULL) { + return NULL; + } + + result = vnode_init(v, &dev_vnode_ops, NULL, dev); + if (result != 0) { + panic("While creating vnode for device: vnode_init: %s\n", + strerror(result)); + } + + return v; +} + +/* + * Undo dev_create_vnode. + * + * Note: this is only used in failure paths; we don't support + * hotpluggable devices, so once a device is attached it's permanent. + */ +void +dev_uncreate_vnode(struct vnode *vn) +{ + KASSERT(vn->vn_ops == &dev_vnode_ops); + vnode_cleanup(vn); + kfree(vn); +} diff --git a/kern/vfs/devnull.c b/kern/vfs/devnull.c new file mode 100644 index 0000000..35f3e2e --- /dev/null +++ b/kern/vfs/devnull.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Implementation of the null device, "null:", which generates an + * immediate EOF on read and throws away anything written to it. + */ +#include +#include +#include +#include +#include +#include + +/* For open() */ +static +int +nullopen(struct device *dev, int openflags) +{ + (void)dev; + (void)openflags; + + return 0; +} + +/* For d_io() */ +static +int +nullio(struct device *dev, struct uio *uio) +{ + /* + * On write, discard everything without looking at it. + * (Notice that you can write to the null device from invalid + * buffer pointers and it will still succeed. This behavior is + * traditional.) + * + * On read, do nothing, generating an immediate EOF. + */ + + (void)dev; // unused + + if (uio->uio_rw == UIO_WRITE) { + uio->uio_resid = 0; + } + + return 0; +} + +/* For ioctl() */ +static +int +nullioctl(struct device *dev, int op, userptr_t data) +{ + /* + * No ioctls. + */ + + (void)dev; + (void)op; + (void)data; + + return EINVAL; +} + +static const struct device_ops null_devops = { + .devop_eachopen = nullopen, + .devop_io = nullio, + .devop_ioctl = nullioctl, +}; + +/* + * Function to create and attach null: + */ +void +devnull_create(void) +{ + int result; + struct device *dev; + + dev = kmalloc(sizeof(*dev)); + if (dev==NULL) { + panic("Could not add null device: out of memory\n"); + } + + dev->d_ops = &null_devops; + + dev->d_blocks = 0; + dev->d_blocksize = 1; + + dev->d_devnumber = 0; /* assigned by vfs_adddev */ + + dev->d_data = NULL; + + result = vfs_adddev("null", dev, 0); + if (result) { + panic("Could not add null device: %s\n", strerror(result)); + } +} diff --git a/kern/vfs/vfscwd.c b/kern/vfs/vfscwd.c new file mode 100644 index 0000000..dac5fb7 --- /dev/null +++ b/kern/vfs/vfscwd.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * VFS operations involving the current directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Get current directory as a vnode. + */ +int +vfs_getcurdir(struct vnode **ret) +{ + int rv = 0; + + spinlock_acquire(&curproc->p_lock); + if (curproc->p_cwd!=NULL) { + VOP_INCREF(curproc->p_cwd); + *ret = curproc->p_cwd; + } + else { + rv = ENOENT; + } + spinlock_release(&curproc->p_lock); + + return rv; +} + +/* + * Set current directory as a vnode. + * The passed vnode must in fact be a directory. + */ +int +vfs_setcurdir(struct vnode *dir) +{ + struct vnode *old; + mode_t vtype; + int result; + + result = VOP_GETTYPE(dir, &vtype); + if (result) { + return result; + } + if (vtype != S_IFDIR) { + return ENOTDIR; + } + + VOP_INCREF(dir); + + spinlock_acquire(&curproc->p_lock); + old = curproc->p_cwd; + curproc->p_cwd = dir; + spinlock_release(&curproc->p_lock); + + if (old!=NULL) { + VOP_DECREF(old); + } + + return 0; +} + +/* + * Set current directory to "none". + */ +int +vfs_clearcurdir(void) +{ + struct vnode *old; + + spinlock_acquire(&curproc->p_lock); + old = curproc->p_cwd; + curproc->p_cwd = NULL; + spinlock_release(&curproc->p_lock); + + if (old!=NULL) { + VOP_DECREF(old); + } + + return 0; +} + +/* + * Set current directory, as a pathname. Use vfs_lookup to translate + * it to a vnode. + */ +int +vfs_chdir(char *path) +{ + struct vnode *vn; + int result; + + result = vfs_lookup(path, &vn); + if (result) { + return result; + } + result = vfs_setcurdir(vn); + VOP_DECREF(vn); + return result; +} + +/* + * Get current directory, as a pathname. + * Use VOP_NAMEFILE to get the pathname and FSOP_GETVOLNAME to get the + * volume name. + */ +int +vfs_getcwd(struct uio *uio) +{ + struct vnode *cwd; + int result; + const char *name; + char colon=':'; + + KASSERT(uio->uio_rw==UIO_READ); + + result = vfs_getcurdir(&cwd); + if (result) { + return result; + } + + /* The current dir must be a directory, and thus it is not a device. */ + KASSERT(cwd->vn_fs != NULL); + + name = FSOP_GETVOLNAME(cwd->vn_fs); + if (name==NULL) { + vfs_biglock_acquire(); + name = vfs_getdevname(cwd->vn_fs); + vfs_biglock_release(); + } + KASSERT(name != NULL); + + result = uiomove((char *)name, strlen(name), uio); + if (result) { + goto out; + } + result = uiomove(&colon, 1, uio); + if (result) { + goto out; + } + + result = VOP_NAMEFILE(cwd, uio); + + out: + + VOP_DECREF(cwd); + return result; +} diff --git a/kern/vfs/vfsfail.c b/kern/vfs/vfsfail.c new file mode 100644 index 0000000..6aaf360 --- /dev/null +++ b/kern/vfs/vfsfail.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +/* + * Routines that fail. + * + * It is kind of silly to write these out each with their particular + * arguments; however, portable C doesn't let you cast function + * pointers with different argument signatures even if the arguments + * are never used. + * + * The 4.4BSD approach (all vnode ops take a void pointer that's cast + * to a op-specific args structure, so they're all the same type) + * avoids this problem but is otherwise not very appealing. + */ + +//////////////////////////////////////////////////////////// +// uio ops (read, readlink, getdirentry, write, namefile) + +int +vopfail_uio_notdir(struct vnode *vn, struct uio *uio) +{ + (void)vn; + (void)uio; + return ENOTDIR; +} + +int +vopfail_uio_isdir(struct vnode *vn, struct uio *uio) +{ + (void)vn; + (void)uio; + return EISDIR; +} + +int +vopfail_uio_inval(struct vnode *vn, struct uio *uio) +{ + (void)vn; + (void)uio; + return EINVAL; +} + +int +vopfail_uio_nosys(struct vnode *vn, struct uio *uio) +{ + (void)vn; + (void)uio; + return ENOSYS; +} + +//////////////////////////////////////////////////////////// +// mmap + +int +vopfail_mmap_isdir(struct vnode *vn /*add stuff */) +{ + (void)vn; + return EISDIR; +} + +int +vopfail_mmap_perm(struct vnode *vn /*add stuff */) +{ + (void)vn; + return EPERM; +} + +int +vopfail_mmap_nosys(struct vnode *vn /*add stuff */) +{ + (void)vn; + return ENOSYS; +} + +//////////////////////////////////////////////////////////// +// truncate + +int +vopfail_truncate_isdir(struct vnode *vn, off_t pos) +{ + (void)vn; + (void)pos; + return EISDIR; +} + +//////////////////////////////////////////////////////////// +// creat + +int +vopfail_creat_notdir(struct vnode *vn, const char *name, bool excl, + mode_t mode, struct vnode **result) +{ + (void)vn; + (void)name; + (void)excl; + (void)mode; + (void)result; + return ENOTDIR; +} + +//////////////////////////////////////////////////////////// +// symlink + +int +vopfail_symlink_notdir(struct vnode *vn, const char *contents, + const char *name) +{ + (void)vn; + (void)contents; + (void)name; + return ENOTDIR; +} + +int +vopfail_symlink_nosys(struct vnode *vn, const char *contents, + const char *name) +{ + (void)vn; + (void)contents; + (void)name; + return ENOSYS; +} + +//////////////////////////////////////////////////////////// +// mkdir + +int +vopfail_mkdir_notdir(struct vnode *vn, const char *name, mode_t mode) +{ + (void)vn; + (void)name; + (void)mode; + return ENOTDIR; +} + +int +vopfail_mkdir_nosys(struct vnode *vn, const char *name, mode_t mode) +{ + (void)vn; + (void)name; + (void)mode; + return ENOSYS; +} + +//////////////////////////////////////////////////////////// +// link + +int +vopfail_link_notdir(struct vnode *dir, const char *name, struct vnode *file) +{ + (void)dir; + (void)name; + (void)file; + return ENOTDIR; +} + +int +vopfail_link_nosys(struct vnode *dir, const char *name, struct vnode *file) +{ + (void)dir; + (void)name; + (void)file; + return ENOSYS; +} + +//////////////////////////////////////////////////////////// +// string ops (remove and rmdir) + +int +vopfail_string_notdir(struct vnode *vn, const char *name) +{ + (void)vn; + (void)name; + return ENOTDIR; +} + +int +vopfail_string_nosys(struct vnode *vn, const char *name) +{ + (void)vn; + (void)name; + return ENOSYS; +} + +//////////////////////////////////////////////////////////// +// rename + +int +vopfail_rename_notdir(struct vnode *fromdir, const char *fromname, + struct vnode *todir, const char *toname) +{ + (void)fromdir; + (void)fromname; + (void)todir; + (void)toname; + return ENOTDIR; +} + +int +vopfail_rename_nosys(struct vnode *fromdir, const char *fromname, + struct vnode *todir, const char *toname) +{ + (void)fromdir; + (void)fromname; + (void)todir; + (void)toname; + return ENOSYS; +} + +//////////////////////////////////////////////////////////// +// lookup + +int +vopfail_lookup_notdir(struct vnode *vn, char *path, struct vnode **result) +{ + (void)vn; + (void)path; + (void)result; + return ENOTDIR; +} + +int +vopfail_lookparent_notdir(struct vnode *vn, char *path, struct vnode **result, + char *buf, size_t len) +{ + (void)vn; + (void)path; + (void)result; + (void)buf; + (void)len; + return ENOTDIR; +} + diff --git a/kern/vfs/vfslist.c b/kern/vfs/vfslist.c new file mode 100644 index 0000000..64f6a9d --- /dev/null +++ b/kern/vfs/vfslist.c @@ -0,0 +1,786 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * VFS operations that involve the list of VFS (named) devices + * (the "dev" in "dev:path" syntax). + */ + +#define VFSINLINE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Structure for a single named device. + * + * kd_name - Name of device (eg, "lhd0"). Should always be set to + * a valid string. + * + * kd_rawname - Name of raw device (eg, "lhd0raw"). Is non-NULL if and + * only if this device can have a filesystem mounted on + * it. + * + * kd_device - Device object this name refers to. May be NULL if kd_fs + * is hardwired. + * + * kd_fs - Filesystem object mounted on, or associated with, this + * device. NULL if there is no filesystem. + * + * A filesystem can be associated with a device without having been + * mounted if the device was created that way. In this case, + * kd_rawname is NULL (prohibiting mount/unmount), and, as there is + * then no way to access kd_device, it will be NULL as well. This is + * intended for devices that are inherently filesystems, like emu0. + * + * Referencing kd_name, or the filesystem volume name, on a device + * with a filesystem mounted returns the root of the filesystem. + * Referencing kd_name on a mountable device with no filesystem + * returns ENXIO. Referencing kd_name on a device that is not + * mountable and has no filesystem, or kd_rawname on a mountable + * device, returns the device itself. + */ + +struct knowndev { + char *kd_name; + char *kd_rawname; + struct device *kd_device; + struct vnode *kd_vnode; + struct fs *kd_fs; +}; + +/* A placeholder for kd_fs for devices used as swap */ +#define SWAP_FS ((struct fs *)-1) + +DECLARRAY(knowndev, static __UNUSED inline); +DEFARRAY(knowndev, static __UNUSED inline); + +static struct knowndevarray *knowndevs; + +/* The big lock for all FS ops. Remove for filesystem assignment. */ +static struct lock *vfs_biglock; +static unsigned vfs_biglock_depth; + + +/* + * Setup function + */ +void +vfs_bootstrap(void) +{ + knowndevs = knowndevarray_create(); + if (knowndevs==NULL) { + panic("vfs: Could not create knowndevs array\n"); + } + + vfs_biglock = lock_create("vfs_biglock"); + if (vfs_biglock==NULL) { + panic("vfs: Could not create vfs big lock\n"); + } + vfs_biglock_depth = 0; + + devnull_create(); + semfs_bootstrap(); +} + +/* + * Operations on vfs_biglock. We make it recursive to avoid having to + * think about where we do and don't already hold it. This is an + * undesirable hack that's frequently necessary when a lock covers too + * much material. Your solution scheme for FS and VFS locking should + * not require recursive locks. + */ +void +vfs_biglock_acquire(void) +{ + if (!lock_do_i_hold(vfs_biglock)) { + lock_acquire(vfs_biglock); + } + else if (vfs_biglock_depth == 0) { + /* + * Supposedly we hold it, but the depth is 0. This may + * mean: (1) the count is messed up, or (2) + * lock_do_i_hold is lying. Since OS/161 ships out of + * the box with unimplemented locks (students + * implement them) that always return true, assume + * situation (2). In this case acquire the lock + * anyway. + * + * Once you have working locks, this won't be the + * case, and if you get here it should be situation + * (1), in which case the count is messed up and one + * can panic. + */ + lock_acquire(vfs_biglock); + } + vfs_biglock_depth++; +} + +void +vfs_biglock_release(void) +{ + KASSERT(lock_do_i_hold(vfs_biglock)); + KASSERT(vfs_biglock_depth > 0); + vfs_biglock_depth--; + if (vfs_biglock_depth == 0) { + lock_release(vfs_biglock); + } +} + +bool +vfs_biglock_do_i_hold(void) +{ + return lock_do_i_hold(vfs_biglock); +} + +/* + * Global sync function - call FSOP_SYNC on all devices. + */ +int +vfs_sync(void) +{ + struct knowndev *dev; + unsigned i, num; + + vfs_biglock_acquire(); + + num = knowndevarray_num(knowndevs); + for (i=0; ikd_fs != NULL && dev->kd_fs != SWAP_FS) { + /*result =*/ FSOP_SYNC(dev->kd_fs); + } + } + + vfs_biglock_release(); + + return 0; +} + +/* + * Given a device name (lhd0, emu0, somevolname, null, etc.), hand + * back an appropriate vnode. + */ +int +vfs_getroot(const char *devname, struct vnode **ret) +{ + struct knowndev *kd; + unsigned i, num; + + KASSERT(vfs_biglock_do_i_hold()); + + num = knowndevarray_num(knowndevs); + for (i=0; ikd_fs != NULL && kd->kd_fs != SWAP_FS) { + const char *volname; + volname = FSOP_GETVOLNAME(kd->kd_fs); + + if (!strcmp(kd->kd_name, devname) || + (volname!=NULL && !strcmp(volname, devname))) { + return FSOP_GETROOT(kd->kd_fs, ret); + } + } + else { + if (kd->kd_rawname!=NULL && + !strcmp(kd->kd_name, devname)) { + return ENXIO; + } + } + + /* + * If DEVNAME names the device, and we get here, it + * must have no fs and not be mountable. In this case, + * we return the device itself. + */ + if (!strcmp(kd->kd_name, devname)) { + KASSERT(kd->kd_fs==NULL); + KASSERT(kd->kd_rawname==NULL); + KASSERT(kd->kd_device != NULL); + VOP_INCREF(kd->kd_vnode); + *ret = kd->kd_vnode; + return 0; + } + + /* + * If the device has a rawname and DEVNAME names that, + * return the device itself. + */ + if (kd->kd_rawname!=NULL && !strcmp(kd->kd_rawname, devname)) { + KASSERT(kd->kd_device != NULL); + VOP_INCREF(kd->kd_vnode); + *ret = kd->kd_vnode; + return 0; + } + + /* + * If none of the above tests matched, we didn't name + * any of the names of this device, so go on to the + * next one. + */ + } + + /* + * If we got here, the device specified by devname doesn't exist. + */ + + return ENODEV; +} + +/* + * Given a filesystem, hand back the name of the device it's mounted on. + */ +const char * +vfs_getdevname(struct fs *fs) +{ + struct knowndev *kd; + unsigned i, num; + + KASSERT(fs != NULL); + + KASSERT(vfs_biglock_do_i_hold()); + + num = knowndevarray_num(knowndevs); + for (i=0; ikd_fs == fs) { + /* + * This is not a race condition: as long as the + * guy calling us holds a reference to the fs, + * the fs cannot go away, and the device can't + * go away until the fs goes away. + */ + return kd->kd_name; + } + } + + return NULL; +} + +/* + * Assemble the name for a raw device from the name for the regular device. + */ +static +char * +mkrawname(const char *name) +{ + char *s = kmalloc(strlen(name)+3+1); + if (!s) { + return NULL; + } + strcpy(s, name); + strcat(s, "raw"); + return s; +} + + +/* + * Check if the two strings passed in are the same, if they're both + * not NULL (the latter part being significant). + */ +static +inline +int +samestring(const char *a, const char *b) +{ + if (a==NULL || b==NULL) { + return 0; + } + return !strcmp(a, b); +} + +/* + * Check if the first string passed is the same as any of the three others, + * if they're not NULL. + */ +static +inline +int +samestring3(const char *a, const char *b, const char *c, const char *d) +{ + return samestring(a,b) || samestring(a,c) || samestring(a,d); +} + +/* + * Check if any of the three names passed in already exists as a device + * name. + */ + +static +int +badnames(const char *n1, const char *n2, const char *n3) +{ + const char *volname; + unsigned i, num; + struct knowndev *kd; + + KASSERT(vfs_biglock_do_i_hold()); + + num = knowndevarray_num(knowndevs); + for (i=0; ikd_fs != NULL && kd->kd_fs != SWAP_FS) { + volname = FSOP_GETVOLNAME(kd->kd_fs); + if (samestring3(volname, n1, n2, n3)) { + return 1; + } + } + + if (samestring3(kd->kd_rawname, n1, n2, n3) || + samestring3(kd->kd_name, n1, n2, n3)) { + return 1; + } + } + + return 0; +} + +/* + * Add a new device to the VFS layer's device table. + * + * If "mountable" is set, the device will be treated as one that expects + * to have a filesystem mounted on it, and a raw device will be created + * for direct access. + */ +static +int +vfs_doadd(const char *dname, int mountable, struct device *dev, struct fs *fs) +{ + char *name=NULL, *rawname=NULL; + struct knowndev *kd=NULL; + struct vnode *vnode=NULL; + const char *volname=NULL; + unsigned index; + int result; + + /* Silence warning with gcc 4.8 -Og (but not -O2) */ + index = 0; + + vfs_biglock_acquire(); + + name = kstrdup(dname); + if (name==NULL) { + result = ENOMEM; + goto fail; + } + if (mountable) { + rawname = mkrawname(name); + if (rawname==NULL) { + result = ENOMEM; + goto fail; + } + } + + vnode = dev_create_vnode(dev); + if (vnode==NULL) { + result = ENOMEM; + goto fail; + } + + kd = kmalloc(sizeof(struct knowndev)); + if (kd==NULL) { + result = ENOMEM; + goto fail; + } + + kd->kd_name = name; + kd->kd_rawname = rawname; + kd->kd_device = dev; + kd->kd_vnode = vnode; + kd->kd_fs = fs; + + if (fs!=NULL) { + volname = FSOP_GETVOLNAME(fs); + } + + if (badnames(name, rawname, volname)) { + result = EEXIST; + goto fail; + } + + result = knowndevarray_add(knowndevs, kd, &index); + if (result) { + goto fail; + } + + if (dev != NULL) { + /* use index+1 as the device number, so 0 is reserved */ + dev->d_devnumber = index+1; + } + + vfs_biglock_release(); + return 0; + + fail: + if (name) { + kfree(name); + } + if (rawname) { + kfree(rawname); + } + if (vnode) { + dev_uncreate_vnode(vnode); + } + if (kd) { + kfree(kd); + } + + vfs_biglock_release(); + return result; +} + +/* + * Add a new device, by name. See above for the description of + * mountable. + */ +int +vfs_adddev(const char *devname, struct device *dev, int mountable) +{ + return vfs_doadd(devname, mountable, dev, NULL); +} + +/* + * Add a filesystem that does not have an underlying device. + * This is used for emufs, but might also be used for network + * filesystems and the like. + */ +int +vfs_addfs(const char *devname, struct fs *fs) +{ + return vfs_doadd(devname, 0, NULL, fs); +} + +////////////////////////////////////////////////// + +/* + * Look for a mountable device named DEVNAME. + * Should already hold knowndevs_lock. + */ +static +int +findmount(const char *devname, struct knowndev **result) +{ + struct knowndev *dev; + unsigned i, num; + bool found = false; + + KASSERT(vfs_biglock_do_i_hold()); + + num = knowndevarray_num(knowndevs); + for (i=0; !found && ikd_rawname==NULL) { + /* not mountable/unmountable */ + continue; + } + + if (!strcmp(devname, dev->kd_name)) { + *result = dev; + found = true; + } + } + + return found ? 0 : ENODEV; +} + +/* + * Mount a filesystem. Once we've found the device, call MOUNTFUNC to + * set up the filesystem and hand back a struct fs. + * + * The DATA argument is passed through unchanged to MOUNTFUNC. + */ +int +vfs_mount(const char *devname, void *data, + int (*mountfunc)(void *data, struct device *, struct fs **ret)) +{ + const char *volname; + struct knowndev *kd; + struct fs *fs; + int result; + + vfs_biglock_acquire(); + + result = findmount(devname, &kd); + if (result) { + vfs_biglock_release(); + return result; + } + + if (kd->kd_fs != NULL) { + vfs_biglock_release(); + return EBUSY; + } + KASSERT(kd->kd_rawname != NULL); + KASSERT(kd->kd_device != NULL); + + result = mountfunc(data, kd->kd_device, &fs); + if (result) { + vfs_biglock_release(); + return result; + } + + KASSERT(fs != NULL); + KASSERT(fs != SWAP_FS); + + kd->kd_fs = fs; + + volname = FSOP_GETVOLNAME(fs); + kprintf("vfs: Mounted %s: on %s\n", + volname ? volname : kd->kd_name, kd->kd_name); + + vfs_biglock_release(); + return 0; +} + +/* + * Like mount, but for attaching swap. Hands back the raw device + * vnode. Unlike mount tolerates a trailing colon on the device name, + * to avoid student-facing confusion. + */ +int +vfs_swapon(const char *devname, struct vnode **ret) +{ + char *myname = NULL; + size_t len; + struct knowndev *kd; + int result; + + len = strlen(devname); + if (len > 0 && devname[len - 1] == ':') { + /* tolerate trailing :, e.g. lhd0: rather than lhd0 */ + myname = kstrdup(devname); + if (myname == NULL) { + return ENOMEM; + } + myname[len - 1] = 0; + devname = myname; + } + + vfs_biglock_acquire(); + + result = findmount(devname, &kd); + if (result) { + goto out; + } + + if (kd->kd_fs != NULL) { + result = EBUSY; + goto out; + } + KASSERT(kd->kd_rawname != NULL); + KASSERT(kd->kd_device != NULL); + + kprintf("vfs: Swap attached to %s\n", kd->kd_name); + + kd->kd_fs = SWAP_FS; + VOP_INCREF(kd->kd_vnode); + *ret = kd->kd_vnode; + + out: + vfs_biglock_release(); + if (myname != NULL) { + kfree(myname); + } + + return result; +} + +/* + * Unmount a filesystem/device by name. + * First calls FSOP_SYNC on the filesystem; then calls FSOP_UNMOUNT. + */ +int +vfs_unmount(const char *devname) +{ + struct knowndev *kd; + int result; + + vfs_biglock_acquire(); + + result = findmount(devname, &kd); + if (result) { + goto fail; + } + + if (kd->kd_fs == NULL || kd->kd_fs == SWAP_FS) { + result = EINVAL; + goto fail; + } + KASSERT(kd->kd_rawname != NULL); + KASSERT(kd->kd_device != NULL); + + /* sync the fs */ + result = FSOP_SYNC(kd->kd_fs); + if (result) { + goto fail; + } + + result = FSOP_UNMOUNT(kd->kd_fs); + if (result) { + goto fail; + } + + kprintf("vfs: Unmounted %s:\n", kd->kd_name); + + /* now drop the filesystem */ + kd->kd_fs = NULL; + + KASSERT(result==0); + + fail: + vfs_biglock_release(); + return result; +} + +/* + * Detach swap. Like unmount. + * + * (Provided for completeness; there is no real need to remove swap + * explicitly prior to shutting down, except perhaps when swapping to + * things that themselves want a clean shutdown, like RAIDs.) + */ +int +vfs_swapoff(const char *devname) +{ + struct knowndev *kd; + int result; + + vfs_biglock_acquire(); + + result = findmount(devname, &kd); + if (result) { + goto fail; + } + + if (kd->kd_fs != SWAP_FS) { + result = EINVAL; + goto fail; + } + + kprintf("vfs: Swap detached from %s:\n", kd->kd_name); + + /* drop it */ + kd->kd_fs = NULL; + + KASSERT(result==0); + + fail: + vfs_biglock_release(); + return result; +} + +/* + * Global unmount function. + */ +int +vfs_unmountall(void) +{ + struct knowndev *dev; + unsigned i, num; + int result; + + vfs_biglock_acquire(); + + num = knowndevarray_num(knowndevs); + for (i=0; ikd_rawname == NULL) { + /* not mountable/unmountable */ + continue; + } + if (dev->kd_fs == NULL) { + /* not mounted */ + continue; + } + if (dev->kd_fs == SWAP_FS) { + /* just drop it */ + dev->kd_fs = NULL; + continue; + } + + kprintf("vfs: Unmounting %s:\n", dev->kd_name); + + result = FSOP_SYNC(dev->kd_fs); + if (result) { + kprintf("vfs: Warning: sync failed for %s: %s, trying " + "again\n", dev->kd_name, strerror(result)); + + result = FSOP_SYNC(dev->kd_fs); + if (result) { + kprintf("vfs: Warning: sync failed second time" + " for %s: %s, giving up...\n", + dev->kd_name, strerror(result)); + /* + * Do not attempt to complete the + * unmount as it will likely explode. + */ + continue; + } + } + + result = FSOP_UNMOUNT(dev->kd_fs); + if (result == EBUSY) { + kprintf("vfs: Cannot unmount %s: (busy)\n", + dev->kd_name); + continue; + } + if (result) { + kprintf("vfs: Warning: unmount failed for %s:" + " %s, already synced, dropping...\n", + dev->kd_name, strerror(result)); + continue; + } + + /* now drop the filesystem */ + dev->kd_fs = NULL; + } + + vfs_biglock_release(); + + return 0; +} diff --git a/kern/vfs/vfslookup.c b/kern/vfs/vfslookup.c new file mode 100644 index 0000000..afeacea --- /dev/null +++ b/kern/vfs/vfslookup.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * VFS operations relating to pathname translation + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct vnode *bootfs_vnode = NULL; + +/* + * Helper function for actually changing bootfs_vnode. + */ +static +void +change_bootfs(struct vnode *newvn) +{ + struct vnode *oldvn; + + oldvn = bootfs_vnode; + bootfs_vnode = newvn; + + if (oldvn != NULL) { + VOP_DECREF(oldvn); + } +} + +/* + * Set bootfs_vnode. + * + * Bootfs_vnode is the vnode used for beginning path translation of + * pathnames starting with /. + * + * It is also incidentally the system's first current directory. + */ +int +vfs_setbootfs(const char *fsname) +{ + char tmp[NAME_MAX+1]; + char *s; + int result; + struct vnode *newguy; + + vfs_biglock_acquire(); + + snprintf(tmp, sizeof(tmp)-1, "%s", fsname); + s = strchr(tmp, ':'); + if (s) { + /* If there's a colon, it must be at the end */ + if (strlen(s)>0) { + vfs_biglock_release(); + return EINVAL; + } + } + else { + strcat(tmp, ":"); + } + + result = vfs_chdir(tmp); + if (result) { + vfs_biglock_release(); + return result; + } + + result = vfs_getcurdir(&newguy); + if (result) { + vfs_biglock_release(); + return result; + } + + change_bootfs(newguy); + + vfs_biglock_release(); + return 0; +} + +/* + * Clear the bootfs vnode (preparatory to system shutdown). + */ +void +vfs_clearbootfs(void) +{ + vfs_biglock_acquire(); + change_bootfs(NULL); + vfs_biglock_release(); +} + + +/* + * Common code to pull the device name, if any, off the front of a + * path and choose the vnode to begin the name lookup relative to. + */ + +static +int +getdevice(char *path, char **subpath, struct vnode **startvn) +{ + int slash=-1, colon=-1, i; + struct vnode *vn; + int result; + + KASSERT(vfs_biglock_do_i_hold()); + + /* + * Entirely empty filenames aren't legal. + */ + if (path[0] == 0) { + return EINVAL; + } + + /* + * Locate the first colon or slash. + */ + + for (i=0; path[i]; i++) { + if (path[i]==':') { + colon = i; + break; + } + if (path[i]=='/') { + slash = i; + break; + } + } + + if (colon < 0 && slash != 0) { + /* + * No colon before a slash, so no device name + * specified, and the slash isn't leading or is also + * absent, so this is a relative path or just a bare + * filename. Start from the current directory, and + * use the whole thing as the subpath. + */ + *subpath = path; + return vfs_getcurdir(startvn); + } + + if (colon>0) { + /* device:path - get root of device's filesystem */ + path[colon]=0; + while (path[colon+1]=='/') { + /* device:/path - skip slash, treat as device:path */ + colon++; + } + *subpath = &path[colon+1]; + + result = vfs_getroot(path, startvn); + if (result) { + return result; + } + + return 0; + } + + /* + * We have either /path or :path. + * + * /path is a path relative to the root of the "boot filesystem". + * :path is a path relative to the root of the current filesystem. + */ + KASSERT(colon==0 || slash==0); + + if (path[0]=='/') { + if (bootfs_vnode==NULL) { + return ENOENT; + } + VOP_INCREF(bootfs_vnode); + *startvn = bootfs_vnode; + } + else { + KASSERT(path[0]==':'); + + result = vfs_getcurdir(&vn); + if (result) { + return result; + } + + /* + * The current directory may not be a device, so it + * must have a fs. + */ + KASSERT(vn->vn_fs!=NULL); + + result = FSOP_GETROOT(vn->vn_fs, startvn); + + VOP_DECREF(vn); + + if (result) { + return result; + } + } + + while (path[1]=='/') { + /* ///... or :/... */ + path++; + } + + *subpath = path+1; + + return 0; +} + +/* + * Name-to-vnode translation. + * (In BSD, both of these are subsumed by namei().) + */ + +int +vfs_lookparent(char *path, struct vnode **retval, + char *buf, size_t buflen) +{ + struct vnode *startvn; + int result; + + vfs_biglock_acquire(); + + result = getdevice(path, &path, &startvn); + if (result) { + vfs_biglock_release(); + return result; + } + + if (strlen(path)==0) { + /* + * It does not make sense to use just a device name in + * a context where "lookparent" is the desired + * operation. + */ + result = EINVAL; + } + else { + result = VOP_LOOKPARENT(startvn, path, retval, buf, buflen); + } + + VOP_DECREF(startvn); + + vfs_biglock_release(); + return result; +} + +int +vfs_lookup(char *path, struct vnode **retval) +{ + struct vnode *startvn; + int result; + + vfs_biglock_acquire(); + + result = getdevice(path, &path, &startvn); + if (result) { + vfs_biglock_release(); + return result; + } + + if (strlen(path)==0) { + *retval = startvn; + vfs_biglock_release(); + return 0; + } + + result = VOP_LOOKUP(startvn, path, retval); + + VOP_DECREF(startvn); + vfs_biglock_release(); + return result; +} diff --git a/kern/vfs/vfspath.c b/kern/vfs/vfspath.c new file mode 100644 index 0000000..a7198a4 --- /dev/null +++ b/kern/vfs/vfspath.c @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * High-level VFS operations on pathnames. + */ + +#include +#include +#include +#include +#include +#include +#include + + +/* Does most of the work for open(). */ +int +vfs_open(char *path, int openflags, mode_t mode, struct vnode **ret) +{ + int how; + int result; + int canwrite; + struct vnode *vn = NULL; + + how = openflags & O_ACCMODE; + + switch (how) { + case O_RDONLY: + canwrite=0; + break; + case O_WRONLY: + case O_RDWR: + canwrite=1; + break; + default: + return EINVAL; + } + + if (openflags & O_CREAT) { + char name[NAME_MAX+1]; + struct vnode *dir; + int excl = (openflags & O_EXCL)!=0; + + result = vfs_lookparent(path, &dir, name, sizeof(name)); + if (result) { + return result; + } + + result = VOP_CREAT(dir, name, excl, mode, &vn); + + VOP_DECREF(dir); + } + else { + result = vfs_lookup(path, &vn); + } + + if (result) { + return result; + } + + KASSERT(vn != NULL); + + result = VOP_EACHOPEN(vn, openflags); + if (result) { + VOP_DECREF(vn); + return result; + } + + if (openflags & O_TRUNC) { + if (canwrite==0) { + result = EINVAL; + } + else { + result = VOP_TRUNCATE(vn, 0); + } + if (result) { + VOP_DECREF(vn); + return result; + } + } + + *ret = vn; + + return 0; +} + +/* Does most of the work for close(). */ +void +vfs_close(struct vnode *vn) +{ + /* + * VOP_DECREF doesn't return an error. + * + * We assume that the file system makes every reasonable + * effort to not fail. If it does fail - such as on a hard I/O + * error or something - vnode.c prints a warning. The reason + * we don't report errors up to or above this level is that + * (1) most application software does not check for close + * failing, and more importantly + * (2) we're often called from places like process exit + * where reporting the error is impossible and + * meaningful recovery is entirely impractical. + */ + + VOP_DECREF(vn); +} + +/* Does most of the work for remove(). */ +int +vfs_remove(char *path) +{ + struct vnode *dir; + char name[NAME_MAX+1]; + int result; + + result = vfs_lookparent(path, &dir, name, sizeof(name)); + if (result) { + return result; + } + + result = VOP_REMOVE(dir, name); + VOP_DECREF(dir); + + return result; +} + +/* Does most of the work for rename(). */ +int +vfs_rename(char *oldpath, char *newpath) +{ + struct vnode *olddir; + char oldname[NAME_MAX+1]; + struct vnode *newdir; + char newname[NAME_MAX+1]; + int result; + + result = vfs_lookparent(oldpath, &olddir, oldname, sizeof(oldname)); + if (result) { + return result; + } + result = vfs_lookparent(newpath, &newdir, newname, sizeof(newname)); + if (result) { + VOP_DECREF(olddir); + return result; + } + + if (olddir->vn_fs==NULL || newdir->vn_fs==NULL || + olddir->vn_fs != newdir->vn_fs) { + VOP_DECREF(newdir); + VOP_DECREF(olddir); + return EXDEV; + } + + result = VOP_RENAME(olddir, oldname, newdir, newname); + + VOP_DECREF(newdir); + VOP_DECREF(olddir); + + return result; +} + +/* Does most of the work for link(). */ +int +vfs_link(char *oldpath, char *newpath) +{ + struct vnode *oldfile; + struct vnode *newdir; + char newname[NAME_MAX+1]; + int result; + + result = vfs_lookup(oldpath, &oldfile); + if (result) { + return result; + } + result = vfs_lookparent(newpath, &newdir, newname, sizeof(newname)); + if (result) { + VOP_DECREF(oldfile); + return result; + } + + if (oldfile->vn_fs==NULL || newdir->vn_fs==NULL || + oldfile->vn_fs != newdir->vn_fs) { + VOP_DECREF(newdir); + VOP_DECREF(oldfile); + return EXDEV; + } + + result = VOP_LINK(newdir, newname, oldfile); + + VOP_DECREF(newdir); + VOP_DECREF(oldfile); + + return result; +} + +/* + * Does most of the work for symlink(). + * + * Note, however, if you're implementing symlinks, that various + * other parts of the VFS layer are missing crucial elements of + * support for symlinks. + */ +int +vfs_symlink(const char *contents, char *path) +{ + struct vnode *newdir; + char newname[NAME_MAX+1]; + int result; + + result = vfs_lookparent(path, &newdir, newname, sizeof(newname)); + if (result) { + return result; + } + + result = VOP_SYMLINK(newdir, newname, contents); + VOP_DECREF(newdir); + + return result; +} + +/* + * Does most of the work for readlink(). + * + * Note, however, if you're implementing symlinks, that various + * other parts of the VFS layer are missing crucial elements of + * support for symlinks. + */ +int +vfs_readlink(char *path, struct uio *uio) +{ + struct vnode *vn; + int result; + + result = vfs_lookup(path, &vn); + if (result) { + return result; + } + + result = VOP_READLINK(vn, uio); + + VOP_DECREF(vn); + + return result; +} + +/* + * Does most of the work for mkdir. + */ +int +vfs_mkdir(char *path, mode_t mode) +{ + struct vnode *parent; + char name[NAME_MAX+1]; + int result; + + result = vfs_lookparent(path, &parent, name, sizeof(name)); + if (result) { + return result; + } + + result = VOP_MKDIR(parent, name, mode); + + VOP_DECREF(parent); + + return result; +} + +/* + * Does most of the work for rmdir. + */ +int +vfs_rmdir(char *path) +{ + struct vnode *parent; + char name[NAME_MAX+1]; + int result; + + result = vfs_lookparent(path, &parent, name, sizeof(name)); + if (result) { + return result; + } + + result = VOP_RMDIR(parent, name); + + VOP_DECREF(parent); + + return result; +} + diff --git a/kern/vfs/vnode.c b/kern/vfs/vnode.c new file mode 100644 index 0000000..7322707 --- /dev/null +++ b/kern/vfs/vnode.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Basic vnode support functions. + */ +#include +#include +#include +#include +#include +#include + +/* + * Initialize an abstract vnode. + */ +int +vnode_init(struct vnode *vn, const struct vnode_ops *ops, + struct fs *fs, void *fsdata) +{ + KASSERT(vn != NULL); + KASSERT(ops != NULL); + + vn->vn_ops = ops; + vn->vn_refcount = 1; + spinlock_init(&vn->vn_countlock); + vn->vn_fs = fs; + vn->vn_data = fsdata; + return 0; +} + +/* + * Destroy an abstract vnode. + */ +void +vnode_cleanup(struct vnode *vn) +{ + KASSERT(vn->vn_refcount == 1); + + spinlock_cleanup(&vn->vn_countlock); + + vn->vn_ops = NULL; + vn->vn_refcount = 0; + vn->vn_fs = NULL; + vn->vn_data = NULL; +} + + +/* + * Increment refcount. + * Called by VOP_INCREF. + */ +void +vnode_incref(struct vnode *vn) +{ + KASSERT(vn != NULL); + + spinlock_acquire(&vn->vn_countlock); + vn->vn_refcount++; + spinlock_release(&vn->vn_countlock); +} + +/* + * Decrement refcount. + * Called by VOP_DECREF. + * Calls VOP_RECLAIM if the refcount hits zero. + */ +void +vnode_decref(struct vnode *vn) +{ + bool destroy; + int result; + + KASSERT(vn != NULL); + + spinlock_acquire(&vn->vn_countlock); + + KASSERT(vn->vn_refcount > 0); + if (vn->vn_refcount > 1) { + vn->vn_refcount--; + destroy = false; + } + else { + /* Don't decrement; pass the reference to VOP_RECLAIM. */ + destroy = true; + } + spinlock_release(&vn->vn_countlock); + + if (destroy) { + result = VOP_RECLAIM(vn); + if (result != 0 && result != EBUSY) { + // XXX: lame. + kprintf("vfs: Warning: VOP_RECLAIM: %s\n", + strerror(result)); + } + } +} + +/* + * Check for various things being valid. + * Called before all VOP_* calls. + */ +void +vnode_check(struct vnode *v, const char *opstr) +{ + /* not safe, and not really needed to check constant fields */ + /*vfs_biglock_acquire();*/ + + if (v == NULL) { + panic("vnode_check: vop_%s: null vnode\n", opstr); + } + if (v == (void *)0xdeadbeef) { + panic("vnode_check: vop_%s: deadbeef vnode\n", opstr); + } + + if (v->vn_ops == NULL) { + panic("vnode_check: vop_%s: null ops pointer\n", opstr); + } + if (v->vn_ops == (void *)0xdeadbeef) { + panic("vnode_check: vop_%s: deadbeef ops pointer\n", opstr); + } + + if (v->vn_ops->vop_magic != VOP_MAGIC) { + panic("vnode_check: vop_%s: ops with bad magic number %lx\n", + opstr, v->vn_ops->vop_magic); + } + + // Device vnodes have null fs pointers. + //if (v->vn_fs == NULL) { + // panic("vnode_check: vop_%s: null fs pointer\n", opstr); + //} + if (v->vn_fs == (void *)0xdeadbeef) { + panic("vnode_check: vop_%s: deadbeef fs pointer\n", opstr); + } + + spinlock_acquire(&v->vn_countlock); + + if (v->vn_refcount < 0) { + panic("vnode_check: vop_%s: negative refcount %d\n", opstr, + v->vn_refcount); + } + else if (v->vn_refcount == 0) { + panic("vnode_check: vop_%s: zero refcount\n", opstr); + } + else if (v->vn_refcount > 0x100000) { + kprintf("vnode_check: vop_%s: warning: large refcount %d\n", + opstr, v->vn_refcount); + } + + spinlock_release(&v->vn_countlock); + /*vfs_biglock_release();*/ +} diff --git a/kern/vm/addrspace.c b/kern/vm/addrspace.c new file mode 100644 index 0000000..7da1c95 --- /dev/null +++ b/kern/vm/addrspace.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +/* + * Note! If OPT_DUMBVM is set, as is the case until you start the VM + * assignment, this file is not compiled or linked or in any way + * used. The cheesy hack versions in dumbvm.c are used instead. + */ + +struct addrspace * +as_create(void) +{ + struct addrspace *as; + + as = kmalloc(sizeof(struct addrspace)); + if (as == NULL) { + return NULL; + } + + /* + * Initialize as needed. + */ + + return as; +} + +int +as_copy(struct addrspace *old, struct addrspace **ret) +{ + struct addrspace *newas; + + newas = as_create(); + if (newas==NULL) { + return ENOMEM; + } + + /* + * Write this. + */ + + (void)old; + + *ret = newas; + return 0; +} + +void +as_destroy(struct addrspace *as) +{ + /* + * Clean up as needed. + */ + + kfree(as); +} + +void +as_activate(void) +{ + struct addrspace *as; + + as = proc_getas(); + if (as == NULL) { + /* + * Kernel thread without an address space; leave the + * prior address space in place. + */ + return; + } + + /* + * Write this. + */ +} + +void +as_deactivate(void) +{ + /* + * Write this. For many designs it won't need to actually do + * anything. See proc.c for an explanation of why it (might) + * be needed. + */ +} + +/* + * Set up a segment at virtual address VADDR of size MEMSIZE. The + * segment in memory extends from VADDR up to (but not including) + * VADDR+MEMSIZE. + * + * The READABLE, WRITEABLE, and EXECUTABLE flags are set if read, + * write, or execute permission should be set on the segment. At the + * moment, these are ignored. When you write the VM system, you may + * want to implement them. + */ +int +as_define_region(struct addrspace *as, vaddr_t vaddr, size_t memsize, + int readable, int writeable, int executable) +{ + /* + * Write this. + */ + + (void)as; + (void)vaddr; + (void)memsize; + (void)readable; + (void)writeable; + (void)executable; + return ENOSYS; +} + +int +as_prepare_load(struct addrspace *as) +{ + /* + * Write this. + */ + + (void)as; + return 0; +} + +int +as_complete_load(struct addrspace *as) +{ + /* + * Write this. + */ + + (void)as; + return 0; +} + +int +as_define_stack(struct addrspace *as, vaddr_t *stackptr) +{ + /* + * Write this. + */ + + (void)as; + + /* Initial user-level stack pointer */ + *stackptr = USERSTACK; + + return 0; +} + diff --git a/kern/vm/copyinout.c b/kern/vm/copyinout.c new file mode 100644 index 0000000..5ca1aa1 --- /dev/null +++ b/kern/vm/copyinout.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * User/kernel memory copying functions. + * + * These are arranged to prevent fatal kernel memory faults if invalid + * addresses are supplied by user-level code. This code is itself + * machine-independent; it uses the machine-dependent C setjmp/longjmp + * facility to perform recovery. + * + * However, it assumes things about the memory subsystem that may not + * be true on all platforms. + * + * (1) It assumes that user memory is mapped into the current address + * space while running in the kernel, and can be accessed by just + * dereferencing a pointer in the ordinary way. (And not, for example, + * with special instructions or via special segment registers.) + * + * (2) It assumes that the user-space region of memory is contiguous + * and extends from 0 to some virtual address USERSPACETOP, and so if + * a user process passes a kernel address the logic in copycheck() + * will trap it. + * + * (3) It assumes that access to user memory from the kernel behaves + * the same way as access to user memory from user space: for + * instance, that the processor honors read-only bits on memory pages + * when in kernel mode. + * + * (4) It assumes that if a proper user-space address that is valid + * but not present, or not valid at all, is touched from the kernel, + * that the correct faults will occur and the VM system will load the + * necessary pages and whatnot. + * + * (5) It assumes that the machine-dependent trap logic provides and + * honors a tm_badfaultfunc field in the thread_machdep structure. + * This feature works as follows: if an otherwise fatal fault occurs + * in kernel mode, and tm_badfaultfunc is set, execution resumes in + * the function pointed to by tm_badfaultfunc. + * + * This code works by setting tm_badfaultfunc and then copying memory + * in an ordinary fashion. If these five assumptions are satisfied, + * which is the case for many ordinary CPU types, this code should + * function correctly. If the assumptions are not satisfied on some + * platform (for instance, certain old 80386 processors violate + * assumption 3), this code cannot be used, and cpu- or platform- + * specific code must be written. + * + * To make use of this code, in addition to tm_badfaultfunc the + * thread_machdep structure should contain a jmp_buf called + * "tm_copyjmp". + */ + +/* + * Recovery function. If a fatal fault occurs during copyin, copyout, + * copyinstr, or copyoutstr, execution resumes here. (This behavior is + * caused by setting t_machdep.tm_badfaultfunc and is implemented in + * machine-dependent code.) + * + * We use the C standard function longjmp() to teleport up the call + * stack to where setjmp() was called. At that point we return EFAULT. + */ +static +void +copyfail(void) +{ + longjmp(curthread->t_machdep.tm_copyjmp, 1); +} + +/* + * Memory region check function. This checks to make sure the block of + * user memory provided (an address and a length) falls within the + * proper userspace region. If it does not, EFAULT is returned. + * + * stoplen is set to the actual maximum length that can be copied. + * This differs from len if and only if the region partially overlaps + * the kernel. + * + * Assumes userspace runs from 0 through USERSPACETOP-1. + */ +static +int +copycheck(const_userptr_t userptr, size_t len, size_t *stoplen) +{ + vaddr_t bot, top; + + *stoplen = len; + + bot = (vaddr_t) userptr; + top = bot+len-1; + + if (top < bot) { + /* addresses wrapped around */ + return EFAULT; + } + + if (bot >= USERSPACETOP) { + /* region is within the kernel */ + return EFAULT; + } + + if (top >= USERSPACETOP) { + /* region overlaps the kernel. adjust the max length. */ + *stoplen = USERSPACETOP - bot; + } + + return 0; +} + +/* + * copyin + * + * Copy a block of memory of length LEN from user-level address USERSRC + * to kernel address DEST. We can use memcpy because it's protected by + * the tm_badfaultfunc/copyfail logic. + */ +int +copyin(const_userptr_t usersrc, void *dest, size_t len) +{ + int result; + size_t stoplen; + + result = copycheck(usersrc, len, &stoplen); + if (result) { + return result; + } + if (stoplen != len) { + /* Single block, can't legally truncate it. */ + return EFAULT; + } + + curthread->t_machdep.tm_badfaultfunc = copyfail; + + result = setjmp(curthread->t_machdep.tm_copyjmp); + if (result) { + curthread->t_machdep.tm_badfaultfunc = NULL; + return EFAULT; + } + + memcpy(dest, (const void *)usersrc, len); + + curthread->t_machdep.tm_badfaultfunc = NULL; + return 0; +} + +/* + * copyout + * + * Copy a block of memory of length LEN from kernel address SRC to + * user-level address USERDEST. We can use memcpy because it's + * protected by the tm_badfaultfunc/copyfail logic. + */ +int +copyout(const void *src, userptr_t userdest, size_t len) +{ + int result; + size_t stoplen; + + result = copycheck(userdest, len, &stoplen); + if (result) { + return result; + } + if (stoplen != len) { + /* Single block, can't legally truncate it. */ + return EFAULT; + } + + curthread->t_machdep.tm_badfaultfunc = copyfail; + + result = setjmp(curthread->t_machdep.tm_copyjmp); + if (result) { + curthread->t_machdep.tm_badfaultfunc = NULL; + return EFAULT; + } + + memcpy((void *)userdest, src, len); + + curthread->t_machdep.tm_badfaultfunc = NULL; + return 0; +} + +/* + * Common string copying function that behaves the way that's desired + * for copyinstr and copyoutstr. + * + * Copies a null-terminated string of maximum length MAXLEN from SRC + * to DEST. If GOTLEN is not null, store the actual length found + * there. Both lengths include the null-terminator. If the string + * exceeds the available length, the call fails and returns + * ENAMETOOLONG. + * + * STOPLEN is like MAXLEN but is assumed to have come from copycheck. + * If we hit MAXLEN it's because the string is too long to fit; if we + * hit STOPLEN it's because the string has run into the end of + * userspace. Thus in the latter case we return EFAULT, not + * ENAMETOOLONG. + */ +static +int +copystr(char *dest, const char *src, size_t maxlen, size_t stoplen, + size_t *gotlen) +{ + size_t i; + + for (i=0; it_machdep.tm_badfaultfunc = copyfail; + + result = setjmp(curthread->t_machdep.tm_copyjmp); + if (result) { + curthread->t_machdep.tm_badfaultfunc = NULL; + return EFAULT; + } + + result = copystr(dest, (const char *)usersrc, len, stoplen, actual); + + curthread->t_machdep.tm_badfaultfunc = NULL; + return result; +} + +/* + * copyoutstr + * + * Copy a string from kernel address SRC to user-level address + * USERDEST, as per copystr above. Uses the tm_badfaultfunc/copyfail + * logic to protect against invalid addresses supplied by a user + * process. + */ +int +copyoutstr(const char *src, userptr_t userdest, size_t len, size_t *actual) +{ + int result; + size_t stoplen; + + result = copycheck(userdest, len, &stoplen); + if (result) { + return result; + } + + curthread->t_machdep.tm_badfaultfunc = copyfail; + + result = setjmp(curthread->t_machdep.tm_copyjmp); + if (result) { + curthread->t_machdep.tm_badfaultfunc = NULL; + return EFAULT; + } + + result = copystr((char *)userdest, src, len, stoplen, actual); + + curthread->t_machdep.tm_badfaultfunc = NULL; + return result; +} diff --git a/kern/vm/kmalloc.c b/kern/vm/kmalloc.c new file mode 100644 index 0000000..b8a1204 --- /dev/null +++ b/kern/vm/kmalloc.c @@ -0,0 +1,1224 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +/* + * Kernel malloc. + */ + + +/* + * Fill a block with 0xdeadbeef. + */ +static +void +fill_deadbeef(void *vptr, size_t len) +{ + uint32_t *ptr = vptr; + size_t i; + + for (i=0; ipageaddr_and_blocktype & PAGE_FRAME) +#define PR_BLOCKTYPE(pr) ((pr)->pageaddr_and_blocktype & ~PAGE_FRAME) +#define MKPAB(pa, blk) (((pa)&PAGE_FRAME) | ((blk) & ~PAGE_FRAME)) + +//////////////////////////////////////// + +/* + * Use one spinlock for the whole thing. Making parts of the kmalloc + * logic per-cpu is worthwhile for scalability; however, for the time + * being at least we won't, because it adds a lot of complexity and in + * OS/161 performance and scalability aren't super-critical. + */ + +static struct spinlock kmalloc_spinlock = SPINLOCK_INITIALIZER; + +//////////////////////////////////////// + +/* + * We can only allocate whole pages of pageref structure at a time. + * This is a struct type for such a page. + * + * Each pageref page contains 256 pagerefs, which can manage up to + * 256 * 4K = 1M of kernel heap. + */ + +#define NPAGEREFS_PER_PAGE (PAGE_SIZE / sizeof(struct pageref)) + +struct pagerefpage { + struct pageref refs[NPAGEREFS_PER_PAGE]; +}; + +/* + * This structure holds a pointer to a pageref page and also its + * bitmap of free entries. + */ + +#define INUSE_WORDS (NPAGEREFS_PER_PAGE / 32) + +struct kheap_root { + struct pagerefpage *page; + uint32_t pagerefs_inuse[INUSE_WORDS]; + unsigned numinuse; +}; + +/* + * It would be better to make this dynamically sizeable. However, + * since we only actually run on System/161 and System/161 is + * specifically limited to 16M of RAM, we'll just adopt that as a + * static size limit. + * + * FUTURE: it would be better to pick this number based on the RAM + * size we find at boot time. + */ + +#define NUM_PAGEREFPAGES 16 +#define TOTAL_PAGEREFS (NUM_PAGEREFPAGES * NPAGEREFS_PER_PAGE) + +static struct kheap_root kheaproots[NUM_PAGEREFPAGES]; + +/* + * Allocate a page to hold pagerefs. + */ +static +void +allocpagerefpage(struct kheap_root *root) +{ + vaddr_t va; + + KASSERT(root->page == NULL); + + /* + * We release the spinlock while calling alloc_kpages. This + * avoids deadlock if alloc_kpages needs to come back here. + * Note that this means things can change behind our back... + */ + spinlock_release(&kmalloc_spinlock); + va = alloc_kpages(1); + spinlock_acquire(&kmalloc_spinlock); + if (va == 0) { + kprintf("kmalloc: Couldn't get a pageref page\n"); + return; + } + KASSERT(va % PAGE_SIZE == 0); + + if (root->page != NULL) { + /* Oops, somebody else allocated it. */ + spinlock_release(&kmalloc_spinlock); + free_kpages(va); + spinlock_acquire(&kmalloc_spinlock); + /* Once allocated it isn't ever freed. */ + KASSERT(root->page != NULL); + return; + } + + root->page = (struct pagerefpage *)va; +} + +/* + * Allocate a pageref structure. + */ +static +struct pageref * +allocpageref(void) +{ + unsigned i,j; + uint32_t k; + unsigned whichroot; + struct kheap_root *root; + + for (whichroot=0; whichroot < NUM_PAGEREFPAGES; whichroot++) { + root = &kheaproots[whichroot]; + if (root->numinuse >= NPAGEREFS_PER_PAGE) { + continue; + } + + /* + * This should probably not be a linear search. + */ + for (i=0; ipagerefs_inuse[i]==0xffffffff) { + /* full */ + continue; + } + for (k=1,j=0; k!=0; k<<=1,j++) { + if ((root->pagerefs_inuse[i] & k)==0) { + root->pagerefs_inuse[i] |= k; + root->numinuse++; + if (root->page == NULL) { + allocpagerefpage(root); + } + if (root->page == NULL) { + return NULL; + } + return &root->page->refs[i*32 + j]; + } + } + KASSERT(0); + } + } + + /* ran out */ + return NULL; +} + +/* + * Release a pageref structure. + */ +static +void +freepageref(struct pageref *p) +{ + size_t i, j; + uint32_t k; + unsigned whichroot; + struct kheap_root *root; + struct pagerefpage *page; + + for (whichroot=0; whichroot < NUM_PAGEREFPAGES; whichroot++) { + root = &kheaproots[whichroot]; + + page = root->page; + if (page == NULL) { + KASSERT(root->numinuse == 0); + continue; + } + + j = p-page->refs; + /* note: j is unsigned, don't test < 0 */ + if (j < NPAGEREFS_PER_PAGE) { + /* on this page */ + i = j/32; + k = ((uint32_t)1) << (j%32); + KASSERT((root->pagerefs_inuse[i] & k) != 0); + root->pagerefs_inuse[i] &= ~k; + KASSERT(root->numinuse > 0); + root->numinuse--; + return; + } + } + /* pageref wasn't on any of the pages */ + KASSERT(0); +} + +//////////////////////////////////////// + +/* + * Each pageref is on two linked lists: one list of pages of blocks of + * that same size, and one of all blocks. + */ +static struct pageref *sizebases[NSIZES]; +static struct pageref *allbase; + +//////////////////////////////////////// + +#ifdef GUARDS + +/* Space returned to the client is filled with GUARD_RETBYTE */ +#define GUARD_RETBYTE 0xa9 +/* Padding space (internal fragmentation loss) is filled with GUARD_FILLBYTE */ +#define GUARD_FILLBYTE 0xba +/* The guard bands on an allocated block should contain GUARD_HALFWORD */ +#define GUARD_HALFWORD 0xb0b0 + +/* The guard scheme uses 8 bytes per block. */ +#define GUARD_OVERHEAD 8 + +/* Pointers are offset by 4 bytes when guards are in use. */ +#define GUARD_PTROFFSET 4 + +/* + * Set up the guard values in a block we're about to return. + */ +static +void * +establishguardband(void *block, size_t clientsize, size_t blocksize) +{ + vaddr_t lowguard, lowsize, data, enddata, highguard, highsize, i; + + KASSERT(clientsize + GUARD_OVERHEAD <= blocksize); + KASSERT(clientsize < 65536U); + + lowguard = (vaddr_t)block; + lowsize = lowguard + 2; + data = lowsize + 2; + enddata = data + clientsize; + highguard = lowguard + blocksize - 4; + highsize = highguard + 2; + + *(uint16_t *)lowguard = GUARD_HALFWORD; + *(uint16_t *)lowsize = clientsize; + for (i=data; i smallerblocksize); + KASSERT(clientsize + GUARD_OVERHEAD <= blocksize); + enddata = data + clientsize; + for (i=enddata; ifreelist_offset == INVALID_OFFSET) { + KASSERT(pr->nfree==0); + return; + } + + prpage = PR_PAGEADDR(pr); + blktype = PR_BLOCKTYPE(pr); + KASSERT(blktype >= 0 && blktype < NSIZES); + blocksize = sizes[blktype]; + +#ifdef CHECKGUARDS + smallerblocksize = blktype > 0 ? sizes[blktype - 1] : 0; + for (i=0; i= MIPS_KSEG0); + KASSERT(prpage < MIPS_KSEG1); +#endif + + KASSERT(pr->freelist_offset < PAGE_SIZE); + KASSERT(pr->freelist_offset % blocksize == 0); + + fla = prpage + pr->freelist_offset; + fl = (struct freelist *)fla; + + for (; fl != NULL; fl = fl->next) { + fla = (vaddr_t)fl; + KASSERT(fla >= prpage && fla < prpage + PAGE_SIZE); + KASSERT((fla-prpage) % blocksize == 0); +#ifdef CHECKBEEF + checkdeadbeef(fl, blocksize); +#endif +#ifdef CHECKGUARDS + blocknum = (fla-prpage) / blocksize; + mask = 1U << (blocknum % 32); + KASSERT((isfree[blocknum / 32] & mask) == 0); + isfree[blocknum / 32] |= mask; +#endif + KASSERT(fl->next != fl); + nfree++; + } + KASSERT(nfree==pr->nfree); + +#ifdef CHECKGUARDS + numblocks = PAGE_SIZE / blocksize; + for (i=0; inext_samesize) { + checksubpage(pr); + KASSERT(sc < TOTAL_PAGEREFS); + sc++; + } + } + + for (pr = allbase; pr != NULL; pr = pr->next_all) { + checksubpage(pr); + KASSERT(ac < TOTAL_PAGEREFS); + ac++; + } + + KASSERT(sc==ac); +} +#else +#define checksubpages() +#endif + +//////////////////////////////////////// + +#ifdef LABELS + +#define LABEL_PTROFFSET sizeof(struct malloclabel) +#define LABEL_OVERHEAD LABEL_PTROFFSET + +struct malloclabel { + vaddr_t label; + unsigned generation; +}; + +static unsigned mallocgeneration; + +/* + * Label a block of memory. + */ +static +void * +establishlabel(void *block, vaddr_t label) +{ + struct malloclabel *ml; + + ml = block; + ml->label = label; + ml->generation = mallocgeneration; + ml++; + return ml; +} + +static +void +dump_subpage(struct pageref *pr, unsigned generation) +{ + unsigned blocksize = sizes[PR_BLOCKTYPE(pr)]; + unsigned numblocks = PAGE_SIZE / blocksize; + unsigned numfreewords = DIVROUNDUP(numblocks, 32); + uint32_t isfree[numfreewords], mask; + vaddr_t prpage; + struct freelist *fl; + vaddr_t blockaddr; + struct malloclabel *ml; + unsigned i; + + for (i=0; ifreelist_offset); + for (; fl != NULL; fl = fl->next) { + i = ((vaddr_t)fl - prpage) / blocksize; + mask = 1U << (i % 32); + isfree[i / 32] |= mask; + } + + for (i=0; igeneration != generation) { + continue; + } + kprintf("%5zu bytes at %p, allocated at %p\n", + blocksize, (void *)blockaddr, (void *)ml->label); + } +} + +static +void +dump_subpages(unsigned generation) +{ + struct pageref *pr; + int i; + + kprintf("Remaining allocations from generation %u:\n", generation); + for (i=0; inext_samesize) { + dump_subpage(pr, generation); + } + } +} + +#else + +#define LABEL_OVERHEAD 0 + +#endif /* LABELS */ + +void +kheap_nextgeneration(void) +{ +#ifdef LABELS + spinlock_acquire(&kmalloc_spinlock); + mallocgeneration++; + spinlock_release(&kmalloc_spinlock); +#endif +} + +void +kheap_dump(void) +{ +#ifdef LABELS + /* print the whole thing with interrupts off */ + spinlock_acquire(&kmalloc_spinlock); + dump_subpages(mallocgeneration); + spinlock_release(&kmalloc_spinlock); +#else + kprintf("Enable LABELS in kmalloc.c to use this functionality.\n"); +#endif +} + +void +kheap_dumpall(void) +{ +#ifdef LABELS + unsigned i; + + /* print the whole thing with interrupts off */ + spinlock_acquire(&kmalloc_spinlock); + for (i=0; i<=mallocgeneration; i++) { + dump_subpages(i); + } + spinlock_release(&kmalloc_spinlock); +#else + kprintf("Enable LABELS in kmalloc.c to use this functionality.\n"); +#endif +} + +//////////////////////////////////////// + +/* + * Print the allocated/freed map of a single kernel heap page. + */ +static +void +subpage_stats(struct pageref *pr) +{ + vaddr_t prpage, fla; + struct freelist *fl; + int blktype; + unsigned i, n, index; + uint32_t freemap[PAGE_SIZE / (SMALLEST_SUBPAGE_SIZE*32)]; + + checksubpage(pr); + KASSERT(spinlock_do_i_hold(&kmalloc_spinlock)); + + /* clear freemap[] */ + for (i=0; i= 0 && blktype < NSIZES); + + /* compute how many bits we need in freemap and assert we fit */ + n = PAGE_SIZE / sizes[blktype]; + KASSERT(n <= 32 * ARRAYCOUNT(freemap)); + + if (pr->freelist_offset != INVALID_OFFSET) { + fla = prpage + pr->freelist_offset; + fl = (struct freelist *)fla; + + for (; fl != NULL; fl = fl->next) { + fla = (vaddr_t)fl; + index = (fla-prpage) / sizes[blktype]; + KASSERT(indexnfree, n); + kprintf(" "); + for (i=0; inext_all) { + subpage_stats(pr); + } + + spinlock_release(&kmalloc_spinlock); +} + +//////////////////////////////////////// + +/* + * Remove a pageref from both lists that it's on. + */ +static +void +remove_lists(struct pageref *pr, int blktype) +{ + struct pageref **guy; + + KASSERT(blktype>=0 && blktypenext_samesize) { + checksubpage(*guy); + if (*guy == pr) { + *guy = pr->next_samesize; + break; + } + } + + for (guy = &allbase; *guy; guy = &(*guy)->next_all) { + checksubpage(*guy); + if (*guy == pr) { + *guy = pr->next_all; + break; + } + } +} + +/* + * Given a requested client size, return the block type, that is, the + * index into the sizes[] array for the block size to use. + */ +static +inline +int blocktype(size_t clientsz) +{ + unsigned i; + for (i=0; inext_samesize) { + + /* check for corruption */ + KASSERT(PR_BLOCKTYPE(pr) == blktype); + checksubpage(pr); + + if (pr->nfree > 0) { + + doalloc: /* comes here after getting a whole fresh page */ + + KASSERT(pr->freelist_offset < PAGE_SIZE); + prpage = PR_PAGEADDR(pr); + fla = prpage + pr->freelist_offset; + fl = (struct freelist *)fla; + + retptr = fl; + fl = fl->next; + pr->nfree--; + + if (fl != NULL) { + KASSERT(pr->nfree > 0); + fla = (vaddr_t)fl; + KASSERT(fla - prpage < PAGE_SIZE); + pr->freelist_offset = fla - prpage; + } + else { + KASSERT(pr->nfree == 0); + pr->freelist_offset = INVALID_OFFSET; + } +#ifdef GUARDS + retptr = establishguardband(retptr, clientsz, sz); +#endif +#ifdef LABELS + retptr = establishlabel(retptr, label); +#endif + + checksubpages(); + + spinlock_release(&kmalloc_spinlock); + return retptr; + } + } + + /* + * No page of the right size available. + * Make a new one. + * + * We release the spinlock while calling alloc_kpages. This + * avoids deadlock if alloc_kpages needs to come back here. + * Note that this means things can change behind our back... + */ + + spinlock_release(&kmalloc_spinlock); + prpage = alloc_kpages(1); + if (prpage==0) { + /* Out of memory. */ + kprintf("kmalloc: Subpage allocator couldn't get a page\n"); + return NULL; + } + KASSERT(prpage % PAGE_SIZE == 0); +#ifdef CHECKBEEF + /* deadbeef the whole page, as it probably starts zeroed */ + fill_deadbeef((void *)prpage, PAGE_SIZE); +#endif + spinlock_acquire(&kmalloc_spinlock); + + pr = allocpageref(); + if (pr==NULL) { + /* Couldn't allocate accounting space for the new page. */ + spinlock_release(&kmalloc_spinlock); + free_kpages(prpage); + kprintf("kmalloc: Subpage allocator couldn't get pageref\n"); + return NULL; + } + + pr->pageaddr_and_blocktype = MKPAB(prpage, blktype); + pr->nfree = PAGE_SIZE / sizes[blktype]; + + /* + * Note: fl is volatile because the MIPS toolchain we were + * using in spring 2001 attempted to optimize this loop and + * blew it. Making fl volatile inhibits the optimization. + */ + + fla = prpage; + fl = (struct freelist *)fla; + fl->next = NULL; + for (i=1; infree; i++) { + fl = (struct freelist *)(fla + i*sizes[blktype]); + fl->next = (struct freelist *)(fla + (i-1)*sizes[blktype]); + KASSERT(fl != fl->next); + } + fla = (vaddr_t) fl; + pr->freelist_offset = fla - prpage; + KASSERT(pr->freelist_offset == (pr->nfree-1)*sizes[blktype]); + + pr->next_samesize = sizebases[blktype]; + sizebases[blktype] = pr; + + pr->next_all = allbase; + allbase = pr; + + /* This is kind of cheesy, but avoids duplicating the alloc code. */ + goto doalloc; +} + +/* + * Free a pointer previously returned from subpage_kmalloc. If the + * pointer is not on any heap page we recognize, return -1. + */ +static +int +subpage_kfree(void *ptr) +{ + int blktype; // index into sizes[] that we're using + vaddr_t ptraddr; // same as ptr + struct pageref *pr; // pageref for page we're freeing in + vaddr_t prpage; // PR_PAGEADDR(pr) + vaddr_t fla; // free list entry address + struct freelist *fl; // free list entry + vaddr_t offset; // offset into page +#ifdef GUARDS + size_t blocksize, smallerblocksize; +#endif + + ptraddr = (vaddr_t)ptr; +#ifdef GUARDS + if (ptraddr % PAGE_SIZE == 0) { + /* + * With guard bands, all client-facing subpage + * pointers are offset by GUARD_PTROFFSET (which is 4) + * from the underlying blocks and are therefore not + * page-aligned. So a page-aligned pointer is not one + * of ours. Catch this up front, as otherwise + * subtracting GUARD_PTROFFSET could give a pointer on + * a page we *do* own, and then we'll panic because + * it's not a valid one. + */ + return -1; + } + ptraddr -= GUARD_PTROFFSET; +#endif +#ifdef LABELS + if (ptraddr % PAGE_SIZE == 0) { + /* ditto */ + return -1; + } + ptraddr -= LABEL_PTROFFSET; +#endif + + spinlock_acquire(&kmalloc_spinlock); + + checksubpages(); + + /* Silence warnings with gcc 4.8 -Og (but not -O2) */ + prpage = 0; + blktype = 0; + + for (pr = allbase; pr; pr = pr->next_all) { + prpage = PR_PAGEADDR(pr); + blktype = PR_BLOCKTYPE(pr); + KASSERT(blktype >= 0 && blktype < NSIZES); + + /* check for corruption */ + KASSERT(blktype>=0 && blktype= prpage && ptraddr < prpage + PAGE_SIZE) { + break; + } + } + + if (pr==NULL) { + /* Not on any of our pages - not a subpage allocation */ + spinlock_release(&kmalloc_spinlock); + return -1; + } + + offset = ptraddr - prpage; + + /* Check for proper positioning and alignment */ + if (offset >= PAGE_SIZE || offset % sizes[blktype] != 0) { + panic("kfree: subpage free of invalid addr %p\n", ptr); + } + +#ifdef GUARDS + blocksize = sizes[blktype]; + smallerblocksize = blktype > 0 ? sizes[blktype - 1] : 0; + checkguardband(ptraddr, smallerblocksize, blocksize); +#endif + + /* + * Clear the block to 0xdeadbeef to make it easier to detect + * uses of dangling pointers. + */ + fill_deadbeef((void *)ptraddr, sizes[blktype]); + + /* + * We probably ought to check for free twice by seeing if the block + * is already on the free list. But that's expensive, so we don't. + */ + + fla = prpage + offset; + fl = (struct freelist *)fla; + if (pr->freelist_offset == INVALID_OFFSET) { + fl->next = NULL; + } else { + fl->next = (struct freelist *)(prpage + pr->freelist_offset); + + /* this block should not already be on the free list! */ +#ifdef SLOW + { + struct freelist *fl2; + + for (fl2 = fl->next; fl2 != NULL; fl2 = fl2->next) { + KASSERT(fl2 != fl); + } + } +#else + /* check just the head */ + KASSERT(fl != fl->next); +#endif + } + pr->freelist_offset = offset; + pr->nfree++; + + KASSERT(pr->nfree <= PAGE_SIZE / sizes[blktype]); + if (pr->nfree == PAGE_SIZE / sizes[blktype]) { + /* Whole page is free. */ + remove_lists(pr, blktype); + freepageref(pr); + /* Call free_kpages without kmalloc_spinlock. */ + spinlock_release(&kmalloc_spinlock); + free_kpages(prpage); + } + else { + spinlock_release(&kmalloc_spinlock); + } + +#ifdef SLOWER /* Don't get the lock unless checksubpages does something. */ + spinlock_acquire(&kmalloc_spinlock); + checksubpages(); + spinlock_release(&kmalloc_spinlock); +#endif + + return 0; +} + +// +//////////////////////////////////////////////////////////// + +/* + * Allocate a block of size SZ. Redirect either to subpage_kmalloc or + * alloc_kpages depending on how big SZ is. + */ +void * +kmalloc(size_t sz) +{ + size_t checksz; +#ifdef LABELS + vaddr_t label; +#endif + +#ifdef LABELS +#ifdef __GNUC__ + label = (vaddr_t)__builtin_return_address(0); +#else +#error "Don't know how to get return address with this compiler" +#endif /* __GNUC__ */ +#endif /* LABELS */ + + checksz = sz + GUARD_OVERHEAD + LABEL_OVERHEAD; + if (checksz >= LARGEST_SUBPAGE_SIZE) { + unsigned long npages; + vaddr_t address; + + /* Round up to a whole number of pages. */ + npages = (sz + PAGE_SIZE - 1)/PAGE_SIZE; + address = alloc_kpages(npages); + if (address==0) { + return NULL; + } + KASSERT(address % PAGE_SIZE == 0); + + return (void *)address; + } + +#ifdef LABELS + return subpage_kmalloc(sz, label); +#else + return subpage_kmalloc(sz); +#endif +} + +/* + * Free a block previously returned from kmalloc. + */ +void +kfree(void *ptr) +{ + /* + * Try subpage first; if that fails, assume it's a big allocation. + */ + if (ptr == NULL) { + return; + } else if (subpage_kfree(ptr)) { + KASSERT((vaddr_t)ptr%PAGE_SIZE==0); + free_kpages((vaddr_t)ptr); + } +} + diff --git a/man/Makefile b/man/Makefile new file mode 100644 index 0000000..383833e --- /dev/null +++ b/man/Makefile @@ -0,0 +1,16 @@ +# +# Makefile for src/man (man page tree) +# + +TOP=.. +.include "$(TOP)/mk/os161.config.mk" + +SUBDIRS=bin sbin testbin libc syscall dev misc + +# Top level man pages +MANDIR=/man +MANFILES=index.html man.css manindex.css + +.include "$(TOP)/mk/os161.subdir.mk" +.include "$(TOP)/mk/os161.man.mk" + diff --git a/man/bin/Makefile b/man/bin/Makefile new file mode 100644 index 0000000..346f330 --- /dev/null +++ b/man/bin/Makefile @@ -0,0 +1,13 @@ +# Man pages for /bin programs + +TOP=../.. +.include "$(TOP)/mk/os161.config.mk" + +MANDIR=/man/bin +MANFILES=\ + cat.html cp.html false.html index.html ln.html ls.html mkdir.html \ + mv.html pwd.html rm.html rmdir.html sh.html sync.html tac.html \ + true.html + +.include "$(TOP)/mk/os161.man.mk" + diff --git a/man/bin/cat.html b/man/bin/cat.html new file mode 100644 index 0000000..6d405df --- /dev/null +++ b/man/bin/cat.html @@ -0,0 +1,81 @@ + + + +cat + + + +

cat

+

OS/161 Reference Manual

+ +

Name

+

+cat - concatenate and print files +

+ +

Synopsis

+

+/bin/cat files... +

+ +

Description

+

+cat prints the files listed on its command line in order to its +standard output. If the magic filename "-" is encountered, cat +prints its standard input up to the first EOF. +

+ +

+With no arguments, cat prints its standard input. +

+ +

+cat takes no options. +

+ +

Requirements

+

+cat uses the following syscalls: +

+

+ +

+cat should function properly once the basic system calls +assignment is completed. +

+ + + diff --git a/man/bin/cp.html b/man/bin/cp.html new file mode 100644 index 0000000..44fa23e --- /dev/null +++ b/man/bin/cp.html @@ -0,0 +1,88 @@ + + + +cp + + + +

cp

+

OS/161 Reference Manual

+ +

Name

+

+cp - copy files +

+ +

Synopsis

+

+/bin/cp oldfile newfile +

+ +

Description

+

+cp copies the file oldfile to the file newfile, +overwriting newfile if it already exists. +

+ +

+cp supports no options. +

+ +

+Note that cp does not support the Unix idiom +cp file1 file2 ... destination-dir to copy a number of files +at once. In particular, cp foo bar/ will fail, probably with +"Is a directory". +

+ +

Requirements

+

+cp uses the following syscalls: +

+

+ +

+cp should function properly once the basic system calls +assignment is completed. +

+ +

See Also

+

+ln, mv +

+ + + diff --git a/man/bin/false.html b/man/bin/false.html new file mode 100644 index 0000000..3269ffd --- /dev/null +++ b/man/bin/false.html @@ -0,0 +1,69 @@ + + + +false + + + +

false

+

OS/161 Reference Manual

+ +

Name

+

+false - return false value +

+ +

Synopsis

+

+/bin/false +

+ +

Description

+

+false exits with exit code 1, signifying failure. +

+ +

Requirements

+

+false uses the _exit system call. +

+ +

+false should function properly once the basic system calls assignment +is completed. +

+ +

See Also

+

+true +

+ + + diff --git a/man/bin/index.html b/man/bin/index.html new file mode 100644 index 0000000..a976558 --- /dev/null +++ b/man/bin/index.html @@ -0,0 +1,67 @@ + + + +OS/161 Binaries + + + + +

OS/161 Binaries (/bin)

+ +

+Top | +Sysadmin binaries | +Test binaries | +System calls | +C standard library | +Device drivers | +Miscellaneous +

+
+ +
    +
  • cat - concatenate and print files +
  • cp - copy files +
  • false - return false value +
  • ln - link files +
  • ls - list files or directory contents +
  • mkdir - create directory +
  • mv - rename or move files +
  • pwd - print working directory +
  • rm - remove (unlink) files +
  • rmdir - remove directory +
  • sh - user command shell +
  • sync - synchronize buffers to disk +
  • tac - print files backwards +
  • true - return true value +
+ + + diff --git a/man/bin/ln.html b/man/bin/ln.html new file mode 100644 index 0000000..e6d1495 --- /dev/null +++ b/man/bin/ln.html @@ -0,0 +1,99 @@ + + + +ln + + + +

ln

+

OS/161 Reference Manual

+ +

Name

+

+ln - link files +

+ +

Synopsis

+

+/bin/ln oldfile newfile +
+/bin/ln -s oldfile newfile +

+ +

Description

+

+ln creates links to files. The first usage creates a hard link, that +is, an additional name for the same file. The second +usage, with the -s option, creates a symbolic link, a special +filesystem entry that redirects accesses back to the first original +file. +

+ +

+The symlink created is of the form newfile -> oldfile. +

+ +

+Note that ln does not support the Unix idiom +ln file1 file2 ... destination-dir to link a number of files +at once. In particular, ln foo bar/ will fail, probably with +"Is a directory". +

+ +

Requirements

+

+ln uses the following syscalls: +

+

+ +

+ln without the -s option should work once (or if) you +implement hard links. ln with the -s option should work once +(or if) you implement symbolic links. Check your assignments for when +(or if) you need to implement these features. +

+ +

+ln is able to create symlinks even if hard links are not +implemented, and vice versa. +

+ +

See Also

+

+cp, mv +

+ + + diff --git a/man/bin/ls.html b/man/bin/ls.html new file mode 100644 index 0000000..3161b01 --- /dev/null +++ b/man/bin/ls.html @@ -0,0 +1,110 @@ + + + +ls + + + +

ls

+

OS/161 Reference Manual

+ +

Name

+

+ls - list files or directory contents +

+ +

Synopsis

+

+/bin/ls [-adlRs] [path...] +

+ +

Description

+

+ls lists the filesystem objects specified on the command +line. If they are directories, the contents of the directories are +listed (unless the -d option is used). +

+ +

+If the -a option is given, filenames beginning with dot (.) +will be listed. Ordinarily, they are skipped. +

+ +

+If the -d option is given, directory contents will not be +listed; the directories themselves will be. +

+ +

+If the -l option is given, a long format listing showing the +file size, type, and link count will be displayed instead of just the +filenames. +

+ +

+If the -R option is given, subdirectories encountered will be +listed recursively. +

+ +

+If the -s option is given, the number of filesystem blocks +used by each object will be displayed in addition to other +information. +

+ +

+If no paths are specified, the current directory is assumed. +

+ +

Requirements

+

+ls uses the following syscalls: +

+

+ +

+As fstat and getdirentry are generally not part of the basic system +calls assignment, ls will usually still not function after +the basic system calls assignment is complete. +These calls are typically part of a later assignment, usually the file +system assignment. You may also need to implement the getdirentry +functionality at the file system level. +Consult your course materials for specific information. +

+ + + diff --git a/man/bin/mkdir.html b/man/bin/mkdir.html new file mode 100644 index 0000000..babe5d0 --- /dev/null +++ b/man/bin/mkdir.html @@ -0,0 +1,81 @@ + + + +mkdir + + + +

mkdir

+

OS/161 Reference Manual

+ +

Name

+

+mkdir - create directory +

+ +

Synopsis

+

+/bin/mkdir directory +

+ +

Description

+

+mkdir creates the named directory. All intermediate +components must already exist. If the named directory already exists, +an error occurs. +

+ +

Requirements

+

+mkdir uses the following syscalls: +

+

+ +

+As the mkdir system call is generally not part of the basic system +calls assignment, mkdir will usually still not function after +the basic system calls assignment is complete. +This call is typically part of a later assignment, usually the file +system assignment. You may also need to implement subdirectories in +the file system. +Consult your course materials for specific information. +

+ +

See Also

+

+rmdir +

+ + + diff --git a/man/bin/mv.html b/man/bin/mv.html new file mode 100644 index 0000000..f608c60 --- /dev/null +++ b/man/bin/mv.html @@ -0,0 +1,98 @@ + + + +mv + + + +

mv

+

OS/161 Reference Manual

+ +

Name

+

+mv - rename or move files +

+ +

Synopsis

+

+/bin/mv oldname newname +

+ +

Description

+

+mv renames the filesystem object specified by +oldname so that it is subsequently named newname. +Both files and directories can be renamed or moved into other parts of +the filesystem tree. However, devices may not be renamed and +filesystem objects may not be moved across filesystems. +

+ +

+mv accepts no options. +

+ +

+Note that mv does not support the Unix idiom +mv file1 file2 ... destination-dir to move a number of files +at once. In particular, mv foo bar/ will fail, probably with +"Is a directory". +

+ +

Requirements

+

+mv uses the following system calls: +

+

+ +

+As the rename system call is generally not part of the basic system +calls assignment, mv will usually still not function after +the basic system calls assignment is complete. +This call is typically part of a later assignment, usually the file +system assignment. +Once you implement the system call you should be able to rename +objects within the same directory. +To move things between directories you will need to implement +cross-directory support for rename at the file system layer. +This may or may not be part of your file system assignment; +consult your course materials for specific information. +

+ +

See Also

+

+cp, ln +

+ + + diff --git a/man/bin/pwd.html b/man/bin/pwd.html new file mode 100644 index 0000000..c9b69ff --- /dev/null +++ b/man/bin/pwd.html @@ -0,0 +1,77 @@ + + + +pwd + + + +

pwd

+

OS/161 Reference Manual

+ +

Name

+

+pwd - print working directory +

+ +

Synopsis

+

+/bin/pwd +

+ +

Description

+

+pwd prints the current working directory. +

+ +

Requirements

+

+pwd uses the following system calls: +

+

+ +

+pwd should function properly once the basic system calls assignment is +completed, except on filesystems or in directories that do not support +getcwd. +Note that by default emufs does not +support getcwd except in its root directory. +

+ +

+pwd should function properly in all directories of your +filesystem once the file system assignment is completed. +

+ + + diff --git a/man/bin/rm.html b/man/bin/rm.html new file mode 100644 index 0000000..026e5c3 --- /dev/null +++ b/man/bin/rm.html @@ -0,0 +1,91 @@ + + + +rm + + + +

rm

+

OS/161 Reference Manual

+ +

Name

+

+rm - remove (unlink) files +

+ +

Synopsis

+

+/bin/rm file... +

+ +

Description

+

+rm deletes the files specified on its command line. (If one +of the filenames specified is one of several hard links to the same +file, the file is only removed erased when all links to it are +deleted.) +

+ +

+Using rm on directories produces an error. Use +rmdir to remove directories. +

+ +

Requirements

+

+rm uses the following system calls: +

+ +

+As the remove system call is generally not part of the basic system +calls assignment, rm will usually still not function after +the basic system calls assignment is complete. +This call is typically part of a later assignment, usually the file +system assignment. +Consult your course materials for specific information. +

+ +

Restrictions

+

+emufs does not support rm. (This is +intentional.) +

+ +

See Also

+

+rmdir +

+ + + diff --git a/man/bin/rmdir.html b/man/bin/rmdir.html new file mode 100644 index 0000000..4c5ae17 --- /dev/null +++ b/man/bin/rmdir.html @@ -0,0 +1,90 @@ + + + +rmdir + + + +

rmdir

+

OS/161 Reference Manual

+ +

Name

+

+rmdir - remove directory +

+ +

Synopsis

+

+/bin/rmdir directory +

+ +

Description

+

+rmdir removes the specified directory. The directory must be empty. +

+ +

+It is an error to attempt to remove the . or .. names in a directory, +or to apply rmdir to a filesystem object that is not a directory. +

+ +

Requirements

+

+rmdir uses the following system calls: +

+

+ +

+As the rmdir system call is generally not part of the basic system +calls assignment, rmdir will usually still not function after +the basic system calls assignment is complete. +This call is typically part of a later assignment, usually the file +system assignment. You may also need to implement subdirectories in +the file system. +Consult your course materials for specific information. +

+ +

Restrictions

+

+emufs does not support rmdir. +(This is intentional.) +

+ +

See Also

+

+mkdir, rm +

+ + + diff --git a/man/bin/sh.html b/man/bin/sh.html new file mode 100644 index 0000000..06d48a6 --- /dev/null +++ b/man/bin/sh.html @@ -0,0 +1,77 @@ + + + +sh + + + +

sh

+

OS/161 Reference Manual

+ +

Name

+

+sh - user command shell +

+ +

Synopsis

+

+/bin/sh [-c command] +

+ +

Description

+

+This is a simple command interpreter. The shell provided with OS/161 +(or, perhaps, provided as a solution set, if you had to write a shell) +is a simple shell accepting some basic Unix-like syntax. +

+ +

Requirements

+

+sh uses these system calls: +

+

+ +

+This shell's basic functionality should work properly once the basic +system calls assignment is complete. Some features may require +additional support which may be part of subsequent assignments. +

+ + + diff --git a/man/bin/sync.html b/man/bin/sync.html new file mode 100644 index 0000000..7f62d8f --- /dev/null +++ b/man/bin/sync.html @@ -0,0 +1,66 @@ + + + +sync + + + +

sync

+

OS/161 Reference Manual

+ +

Name

+

+sync - synchronize buffers to disk +

+ +

Synopsis

+

+/bin/sync +

+ +

Description

+

+sync causes filesystem I/O buffers that have been modified +but not yet written to be written to disk. +

+ +

Requirements

+

+sync uses the sync system +call, and of course _exit. +

+ +

+sync should function once the sync system call is wired up. +This is likely part of the file system assignment +

+ + + diff --git a/man/bin/tac.html b/man/bin/tac.html new file mode 100644 index 0000000..ba878ff --- /dev/null +++ b/man/bin/tac.html @@ -0,0 +1,87 @@ + + + +tac + + + +

tac

+

OS/161 Reference Manual

+ +

Name

+

+tac - print in reverse order +

+ +

Synopsis

+

+/bin/tac files... +

+ +

Description

+

+tac prints the files listed on its command line in reverse +order to its standard output. If the magic filename "-" is +encountered, tac prints its standard input up to the first +EOF. Each file is printed backwards in line-by-line fashion. +

+ +

+With no arguments, tac prints its standard input. +

+ +

+tac takes no options. +

+ +

Requirements

+ +

+tac uses the following syscalls: +

+

+ +

+tac should function properly once the basic system calls +assignment is completed. However, until the file system assignment is +done and the remove system call +implemented, it will leave two scratch files behind per invocation. +

+ + + diff --git a/man/bin/true.html b/man/bin/true.html new file mode 100644 index 0000000..8bc4e16 --- /dev/null +++ b/man/bin/true.html @@ -0,0 +1,69 @@ + + + +true + + + +

true

+

OS/161 Reference Manual

+ +

Name

+

+true - return true value +

+ +

Synopsis

+

+/bin/true +

+ +

Description

+

+true exits with exit code 0, signifying success. +

+ +

Requirements

+

+true uses the _exit system call. +

+ +

+true should function properly once the basic system calls +assignment is completed. +

+ +

See Also

+

+false +

+ + + diff --git a/man/dev/Makefile b/man/dev/Makefile new file mode 100644 index 0000000..1641693 --- /dev/null +++ b/man/dev/Makefile @@ -0,0 +1,13 @@ +# Man pages for device drivers + +TOP=../.. +.include "$(TOP)/mk/os161.config.mk" + +MANDIR=/man/dev +MANFILES=\ + beep.html con.html emu.html index.html lamebus.html lhd.html \ + lnet.html lrandom.html lscreen.html lser.html ltimer.html \ + null.html random.html rtclock.html + +.include "$(TOP)/mk/os161.man.mk" + diff --git a/man/dev/beep.html b/man/dev/beep.html new file mode 100644 index 0000000..3722843 --- /dev/null +++ b/man/dev/beep.html @@ -0,0 +1,62 @@ + + + +beep + + + +

beep

+

OS/161 Reference Manual

+ +

Name

+

+beep - console beep device +

+ +

Synopsis

+

+device beep0 at ltimer* +

+ +

Description

+

+The beep device is an abstract entry point for in-kernel beeping. The +beep() function is provided, and redirected to the first attached +device. If no beep device is available, beeping will cause a warning +to be printed to the system console. +

+ +

See Also

+

+ltimer +

+ + + diff --git a/man/dev/con.html b/man/dev/con.html new file mode 100644 index 0000000..5de24fe --- /dev/null +++ b/man/dev/con.html @@ -0,0 +1,73 @@ + + + +console + + + +

con

+

OS/161 Reference Manual

+ +

Name

+

+con - system login console +

+ +

Synopsis

+

+device con0 at lser*
+device con0 at lscreen*
+

+ +

Description

+

+The generic console device can be attached to either a serial port or +a memory-mapped screen. It provides a small input buffer but no input +editing. You may add such features if you desire. +

+ +

+The in-kernel kprintf() routine and its relatives send their +output to the console device. +

+ +

Files

+

+con: +

+ +

See Also

+

+lser, +lscreen +

+ + + diff --git a/man/dev/emu.html b/man/dev/emu.html new file mode 100644 index 0000000..81e202f --- /dev/null +++ b/man/dev/emu.html @@ -0,0 +1,83 @@ + + + +emu + + + +

emu

+

OS/161 Reference Manual

+ +

Name

+

+emu - emulator pass-through filesystem +

+ +

Synopsis

+

+device emu* at lamebus* +

+ +

Description

+

+emu, also known as emufs, is a driver for a special-purpose System/161 +device that provides access to the filesystem System/161 is running +atop. It provides the appearance of a mounted filesystem. +

+ +

+It is not recommended to access the same underlying files through +different instances of emufs. +

+ +

Files

+

+emu0:, emu1:, etc. +

+ +

Restrictions

+

+emufs does not restrict access to the host directory tree under and +including its root directory. This is so symbolic links out of this +tree work without requiring special handling. +

+ +

+A number of file system operations, most notably remove and rmdir, are +not supported. +

+ +

See Also

+

+lamebus +

+ + + diff --git a/man/dev/index.html b/man/dev/index.html new file mode 100644 index 0000000..26de94f --- /dev/null +++ b/man/dev/index.html @@ -0,0 +1,67 @@ + + + +OS/161 Devices + + + + +

OS/161 Devices

+ +

+Top | +Binaries | +Sysadmin binaries | +Test binaries | +System calls | +C standard library | +Miscellaneous +

+
+ +
    +
  • beep - console beep device +
  • con - system login console +
  • emu - emulator pass-through filesystem +
  • lamebus - driver for LAMEbus system bus +
  • lhd - LAMEbus hard drive +
  • lnet - LAMEbus network card +
  • lrandom - LAMEbus random source +
  • lscreen - LAMEbus memory-mapped screen +
  • lser - LAMEbus serial port +
  • ltimer - LAMEbus timer device +
  • ltrace - LAMEbus trace/debug device +
  • null - null device +
  • random - kernel randomness source +
  • rtclock - realtime clock +
+ + + diff --git a/man/dev/lamebus.html b/man/dev/lamebus.html new file mode 100644 index 0000000..d3ab53e --- /dev/null +++ b/man/dev/lamebus.html @@ -0,0 +1,68 @@ + + + +lamebus + + + +

lamebus

+

OS/161 Reference Manual

+ +

Name

+

+lamebus - driver for LAMEbus system bus +

+ +

Synopsis

+

+device lamebus0 +

+ +

Description

+

+LAMEbus (Linear Always-Mapped Extents bus) is the system bus for +System/161. This driver takes care of managing the bus controller, +distributing interrupts, and similar issues. It serves mostly as an +attachment point for other drivers. +

+ +

See Also

+

+emu, +lhd, +lnet, +lrandom, +lscreen, +lser, +ltimer +

+ + + diff --git a/man/dev/lhd.html b/man/dev/lhd.html new file mode 100644 index 0000000..ae7bc34 --- /dev/null +++ b/man/dev/lhd.html @@ -0,0 +1,65 @@ + + + +lhd + + + +

lhd

+

OS/161 Reference Manual

+ +

Name

+

+lhd - LAMEbus hard drive +

+ +

Synopsis

+

+device lhd* at lamebus* +

+ +

Description

+

+lhd is the driver for the LAMEbus fixed disk interface. It +provides mountable block-device and raw-device access to the disk. +

+ +

Files

+

+lhd0:, lhd0raw:, lhd1:, lhd1raw:, etc. +

+ +

See Also

+

+lamebus +

+ + + diff --git a/man/dev/lnet.html b/man/dev/lnet.html new file mode 100644 index 0000000..935a3d4 --- /dev/null +++ b/man/dev/lnet.html @@ -0,0 +1,62 @@ + + + +lnet + + + +

lnet

+

OS/161 Reference Manual

+ +

Name

+

+lnet - LAMEbus network card +

+ +

Synopsis

+

+options net
+device lnet* at lamebus*
+

+ +

Description

+

+lnet is the driver for the LAMEbus network interface card. As +of this writing the driver is not completed and is thus not available +for actual use yet. +

+ +

See Also

+

+lamebus +

+ + + diff --git a/man/dev/lrandom.html b/man/dev/lrandom.html new file mode 100644 index 0000000..6b65611 --- /dev/null +++ b/man/dev/lrandom.html @@ -0,0 +1,64 @@ + + + +lrandom + + + +

lrandom

+

OS/161 Reference Manual

+ +

Name

+

+lrandom - LAMEbus random source +

+ +

Synopsis

+

+device lrandom* at lamebus* +

+ +

Description

+

+lrandom is the driver for the LAMEbus random source card. +

+ +

+The generic random device can be attached to +an lrandom instance. +

+ +

See Also

+

+lamebus +

+ + + diff --git a/man/dev/lscreen.html b/man/dev/lscreen.html new file mode 100644 index 0000000..db60a7f --- /dev/null +++ b/man/dev/lscreen.html @@ -0,0 +1,72 @@ + + + +lscreen + + + +

lscreen

+

OS/161 Reference Manual

+ +

Name

+

+lscreen - LAMEbus memory-mapped screen +

+ +

Synopsis

+

+device lscreen* at lamebus* +

+ +

Description

+

+lscreen is the driver for the LAMEbus memory-mapped screen +card. It does not provide any internal input buffering; that is +expected to happen at a higher level. +

+ +

+Since the memory-mapped screen card is not actually available yet as +of this writing, the driver has not been tested and probably does not +work. +

+ +

+The system console device can be attached to an +lscreen instance. +

+ +

See Also

+

+lamebus +

+ + + diff --git a/man/dev/lser.html b/man/dev/lser.html new file mode 100644 index 0000000..98b87fc --- /dev/null +++ b/man/dev/lser.html @@ -0,0 +1,67 @@ + + + +lser + + + +

lser

+

OS/161 Reference Manual

+ +

Name

+

+lser - LAMEbus serial port +

+ +

Synopsis

+

+device lser* at lamebus* +

+ +

Description

+

+lser is the driver for the LAMEbus serial port card. It does not +provide any internal buffering; that is expected to happen at a higher +level. It can, however, operate in either polled or interrupt-driven +output mode. +

+ +

+The system console device can be attached to an +lser instance. +

+ +

See Also

+

+lamebus +

+ + + diff --git a/man/dev/ltimer.html b/man/dev/ltimer.html new file mode 100644 index 0000000..f484dd6 --- /dev/null +++ b/man/dev/ltimer.html @@ -0,0 +1,65 @@ + + + +ltimer + + + +

ltimer

+

OS/161 Reference Manual

+ +

Name

+

+ltimer - LAMEbus timer device +

+ +

Synopsis

+

+device ltimer* at lamebus* +

+ +

Description

+

+ltimer is a driver for the LAMEbus clock/timer card. The +card can also provide beep services to the kernel. +

+ +

+The beep and rtclock +generic devices can be attached to an ltimer instance. +

+ +

See Also

+

+lamebus +

+ + + diff --git a/man/dev/ltrace.html b/man/dev/ltrace.html new file mode 100644 index 0000000..d91df32 --- /dev/null +++ b/man/dev/ltrace.html @@ -0,0 +1,74 @@ + + + +ltrace + + + +

ltrace

+

OS/161 Reference Manual

+ +

Name

+

+ltrace - LAMEbus trace device +

+ +

Synopsis

+

+device ltrace* at lamebus* +

+ +

Description

+

+ltrace is a driver for the LAMEbus trace and debug card. +This device can be used to turn on and off System/161 tracing (with +trace161); it can also be used to emit debug printouts with +much lower latency than printing to the console. +Finally, it can be used to cause a dump of the entire System/161 +system state. +

+ +

+The calls for these operations are provided to the kernel via the +header file <lamebus/ltrace.h>. +

+ +

+Only the first ltrace device found, if any, is actually used. If none +is found, the calls have no effect. +

+ +

See Also

+

+lamebus +

+ + + diff --git a/man/dev/null.html b/man/dev/null.html new file mode 100644 index 0000000..fb4a51a --- /dev/null +++ b/man/dev/null.html @@ -0,0 +1,55 @@ + + + +null + + + +

null

+

OS/161 Reference Manual

+ +

Name

+

+null - null device +

+ +

Description

+

+The null device does nothing. Reads generate immediate EOF. Any data +written is thrown away. +

+ +

Files

+

+null: +

+ + + diff --git a/man/dev/random.html b/man/dev/random.html new file mode 100644 index 0000000..6cb95ee --- /dev/null +++ b/man/dev/random.html @@ -0,0 +1,73 @@ + + + +random + + + +

random

+

OS/161 Reference Manual

+ +

Name

+

+random - kernel randomness source +

+ +

Synopsis

+

+device random0 at lrandom*
+device random0 at pseudorand0
+

+ +

Description

+

+The random device is the generalized interface to randomness sources. +Only one random device is used; if more are attached they are ignored. +If no random device is found, the kernel may not run. +

+ +

+The random device provides both the in-kernel random() function and a +VFS-level character device, called random:. Bytes read from the +latter have random values; writes are discarded. +

+ +

Files

+

+random: +

+ +

See Also

+

+lrandom +

+ + + diff --git a/man/dev/rtclock.html b/man/dev/rtclock.html new file mode 100644 index 0000000..d08cd2f --- /dev/null +++ b/man/dev/rtclock.html @@ -0,0 +1,65 @@ + + + +rtclock + + + +

rtclock

+

OS/161 Reference Manual

+ +

Name

+

+rtclock - realtime clock +

+ +

Synopsis

+

+device rtclock0 at ltimer* +

+ +

Description

+

+The rtclock device is the generalized interface to the time of day. It +provides the in-kernel function gettime(). +

+ +

+Only the first clock attached is used. If no clock at all is found, +the system will panic if gettime() is called. +

+ +

See Also

+

+ltimer +

+ + + diff --git a/man/index.html b/man/index.html new file mode 100644 index 0000000..545dd80 --- /dev/null +++ b/man/index.html @@ -0,0 +1,50 @@ + + + +OS/161 Manual + + + + +

OS/161 2.0 Reference Manual

+

 

+ + + + + diff --git a/man/libc/Makefile b/man/libc/Makefile new file mode 100644 index 0000000..610c992 --- /dev/null +++ b/man/libc/Makefile @@ -0,0 +1,17 @@ +# Man pages for libraries + +TOP=../.. +.include "$(TOP)/mk/os161.config.mk" + +MANDIR=/man/libc +MANFILES=\ + __vprintf.html abort.html assert.html atoi.html bzero.html \ + calloc.html err.html exit.html free.html getchar.html getcwd.html \ + index.html malloc.html memcpy.html memmove.html memset.html \ + printf.html putchar.html puts.html random.html realloc.html \ + setjmp.html snprintf.html stdarg.html strcat.html strchr.html \ + strcmp.html strcpy.html strerror.html strlen.html strrchr.html \ + strtok.html strtok_r.html system.html time.html warn.html + +.include "$(TOP)/mk/os161.man.mk" + diff --git a/man/libc/__vprintf.html b/man/libc/__vprintf.html new file mode 100644 index 0000000..054c8b4 --- /dev/null +++ b/man/libc/__vprintf.html @@ -0,0 +1,97 @@ + + + +__vprintf + + + +

__vprintf

+

OS/161 Reference Manual

+ +

Name

+

+__vprintf - printf backend +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+__vprintf(void (*func)(void + *clientdata, + const char *str, + size_t len), + void *clientdata, + const char *format, + va_list) +

+ +

Description

+

+In OS/161, __vprintf is the back-end engine for +printf and printf-like functions. +Note that it is not portable - application code should use +snprintf or vsnprintf when implementing +their own printf-like functions. This documentation is provided for +use when extending OS/161 itself. +

+ +

+The format and subsequent arguments are treated as described +under printf. +

+ +

+The func argument is called to print text generated by the +formatting process. The clientdata argument is passed +straight through __vprintf to func. The str argument +to func points to some text that is to be printed; the len +argument is the length of that string, which should not be assumed to +be null-terminated. +

+ +

+The strings passed to func may be small; if printing is +expensive buffering is probably wanted. +

+ +

Return Values

+

+__vprintf returns the number of characters printed. +

+ + + diff --git a/man/libc/abort.html b/man/libc/abort.html new file mode 100644 index 0000000..d7534e3 --- /dev/null +++ b/man/libc/abort.html @@ -0,0 +1,68 @@ + + + +abort + + + +

abort

+

OS/161 Reference Manual

+ +

Name

+

+abort - abnormal program termination +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <abort.h>
+
+void
+abort(void); +

+ +

Description

+

+The abort function causes immediate abnormal program termination. +Cleanup is not performed. +

+ +

Return Values

+

+abort does not return. +

+ + + diff --git a/man/libc/assert.html b/man/libc/assert.html new file mode 100644 index 0000000..f5809aa --- /dev/null +++ b/man/libc/assert.html @@ -0,0 +1,74 @@ + + + +assert + + + +

assert

+

OS/161 Reference Manual

+ +

Name

+

+assert - check assumptions at run time +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <assert.h>
+
+assert(expression); +

+ +

Description

+

+assert checks that its argument evaluates to true. If this is not the +case, an error message is printed and abort is +called. +

+ +

+assert is a macro. If the macro NDEBUG is defined at +compile time, assertion tests are removed. +

+ +

Caution

+

+Avoid writing assert expressions with side effects, as compiling with +NDEBUG normally causes the side effects to disappear. +

+ + + diff --git a/man/libc/atoi.html b/man/libc/atoi.html new file mode 100644 index 0000000..ed5536d --- /dev/null +++ b/man/libc/atoi.html @@ -0,0 +1,73 @@ + + + +atoi + + + +

atoi

+

OS/161 Reference Manual

+ +

Name

+

+atoi - convert ascii to integer +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <stdlib.h>
+
+int
+atoi(const char *string); +

+ +

Description

+

+string, which should be a textual representation of an +integer, is converted to the machine representation of that integer. +Leading whitespace, if any, is skipped. Conversion stops when a +non-numeric character is found. +

+ +

Return Values

+

+atoi returns the number converted. If no digits at all were +found, it returns 0. +If too many digits are found (resulting in overflow) the behavior is +formally undefined. +

+ + + diff --git a/man/libc/bzero.html b/man/libc/bzero.html new file mode 100644 index 0000000..6acc735 --- /dev/null +++ b/man/libc/bzero.html @@ -0,0 +1,71 @@ + + + +bzero + + + +

bzero

+

OS/161 Reference Manual

+ +

Name

+

+bzero - zero out memory +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <string.h>
+
+void
+bzero(void *buf, size_t len); +

+ +

Description

+

+The region of memory pointed to by buf, of length +len, is zeroed out. +

+ +

Restrictions

+

+Zeroing the bytes of a floating point number does not necessarily +produce a floating point zero value. +Similarly, zeroing the bytes of a pointer does not necessarily produce +NULL. +

+ + + diff --git a/man/libc/calloc.html b/man/libc/calloc.html new file mode 100644 index 0000000..34e4e2f --- /dev/null +++ b/man/libc/calloc.html @@ -0,0 +1,84 @@ + + + +calloc + + + +

calloc

+

OS/161 Reference Manual

+ +

Name

+

+calloc - allocate and clear memory +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <stdlib.h>
+
+void *
+calloc(size_t number, size_t size); +

+ +

Description

+

+calloc allocates number*size bytes of +memory, zeros it, and returns a pointer to it. It is equivalent to +calling +malloc(number*size) +followed by bzero. +

+ +

+If the product number*size overflows the range of +size_t, calloc fails. +

+ +

Return Values

+

+calloc returns a pointer to the memory allocated. If memory +cannot be obtained, NULL is returned. +

+ +

See Also

+

+malloc, +realloc, +free +

+ + + diff --git a/man/libc/err.html b/man/libc/err.html new file mode 100644 index 0000000..dbe0893 --- /dev/null +++ b/man/libc/err.html @@ -0,0 +1,104 @@ + + + +err + + + +

err

+

OS/161 Reference Manual

+ +

Name

+

+err, errx, verr, verrx - print error messages +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <err.h>
+
+void
+err(int exitcode, +const char *format, ...);
+
+void
+errx(int exitcode, +const char *format, ...);
+
+void
+verr(int exitcode, +const char *format, va_list);
+
+void
+verrx(int exitcode, +const char *format, va_list);
+

+ +

Description

+

+The err, errx, verr, and verrx +functions print error messages to the standard error stream. +

+ +

+errx prints the name of the program, a colon, the text +generated by passing format and subsequent args through +printf, and a newline. Then, +exit is called and passed the supplied +exitcode. +

+ +

+err does the same thing, except that a colon and the error +string for the current error (obtained by calling +strerror on +errno) are printed prior to the +newline. +

+ +

+verrx and verr are the same as errx and err +respectively, except that the additional arguments for printf are +taken to have been already packaged up in a va_list by use of +the stdarg facility. +

+ +

See Also

+

+warn +

+ + + diff --git a/man/libc/execvp.html b/man/libc/execvp.html new file mode 100644 index 0000000..8e69ac2 --- /dev/null +++ b/man/libc/execvp.html @@ -0,0 +1,100 @@ + + + +execvp + + + +

execvp

+

OS/161 Reference Manual

+ +

Name

+

+execvp - execute a program found on the search path +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+execvp(const char *program, +char **args); +

+ +

Description

+

+execvp searches for program on the program search +path and execs it with execv if +found. If program is not found or a serious error occurs, it +returns. +

+ +

+If program contains a slash, no search is done; the specified +string is passed directly to execv. +

+ +

+The args argument should be prepared exactly as for +execv. +

+ +

+The search path is a colon-delimited list of directories retrieved by +calling getenv to retrieve the PATH +environment variable. Unless you implement execve and +environment variable passing, the value used is from a default +environment compiled into libc. This path searches the /bin, +/sbin, and /testbin directories. +

+ +

Return Values

+

+On success, execvp does not return; instead, the new program +begins executing. On failure, execvp returns -1, and sets +errno to a suitable error code for the error +condition encountered. +

+ +

Errors

+

+execvp can fail for any of the reasons execv can. +In addition, it produces ENOENT if the requested program is not +found. +

+ + + diff --git a/man/libc/exit.html b/man/libc/exit.html new file mode 100644 index 0000000..61fc5da --- /dev/null +++ b/man/libc/exit.html @@ -0,0 +1,69 @@ + + + +exit + + + +

exit

+

OS/161 Reference Manual

+ +

Name

+

+exit - terminate program +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <stdlib.h>
+
+int
+exit(int code); +

+ +

Description

+

+exit causes the program to exit. It calls internal cleanup +routines, and then performs the actual exit by calling +_exit. +

+ +

Return Values

+

+exit does not return. +

+ + + diff --git a/man/libc/free.html b/man/libc/free.html new file mode 100644 index 0000000..b3547f8 --- /dev/null +++ b/man/libc/free.html @@ -0,0 +1,104 @@ + + + +free + + + +

free

+

OS/161 Reference Manual

+ +

Name

+

+free - release/deallocate memory +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <stdlib.h>
+
+void
+free(void *ptr); +

+ +

Description

+

+free releases a block of memory previously allocated with +malloc, calloc, +or realloc. +

+ +

+Once free has been called, ptr is no longer valid and +attempts to dereference it result in undefined behavior. +(Pedantically, in fact, even using the value of +ptr may produce undefined behavior.) Passing ptr to +free a second or subsequent time (unless of course the same pointer +value is again returned from malloc) is also undefined and +particularly likely to provoke adverse behavior in most +implementations. +

+ +

+free(NULL) has no effect. +

+ +

+In practice it is desirable for implementations of free to +detect, to the extent practically possible, pointers that were not +previously allocated by one of the above functions or that are passed +to free multiple times. However, this can be difficult and +there is no useful standard mechanism for error reporting. +

+ +

+free does not necessarily unmap free memory or return it to +the operating system, but may do so if it chooses. +

+ +

Return Values

+

+free returns no value. +

+ +

See Also

+

+calloc, +malloc, +realloc +

+ + + diff --git a/man/libc/getchar.html b/man/libc/getchar.html new file mode 100644 index 0000000..34566b6 --- /dev/null +++ b/man/libc/getchar.html @@ -0,0 +1,76 @@ + + + +getchar + + + +

getchar

+

OS/161 Reference Manual

+ +

Name

+

+getchar - read character from standard input +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <stdio.h>
+
+int
+getchar(void); +

+ +

Description

+

+getchar reads a single character from standard input. The +character is converted to unsigned char before being returned. +EOF, which is negative, is thus not a possible successful return value. +

+ +

Return Values

+

+On success, getchar returns the character read. On error, or end of +file, EOF is returned. +

+ +

Errors

+

+Any of the errors associated with read +may occur. +

+ + + diff --git a/man/libc/getcwd.html b/man/libc/getcwd.html new file mode 100644 index 0000000..59dce44 --- /dev/null +++ b/man/libc/getcwd.html @@ -0,0 +1,100 @@ + + + +getcwd + + + +

getcwd

+

OS/161 Reference Manual

+ +

Name

+

+getcwd - get name of current working directory +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+char *
+getcwd(char *buf, size_t buflen); +

+ +

Description

+

+The name of the current directory is computed and stored in +buf, an area of size buflen. The resulting string is +0-terminated. +

+ +

+This call is a wrapper (for Unix compatibility) around the system call +__getcwd. +

+ +

+Note, however, that the BSD extension whereby space is allocated with +malloc if buf is NULL is not +supported. +

+ +

Return Values

+

+On success, getcwd returns buf. +On error, NULL is returned, and errno +is set according to the error encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other errors not +mentioned here. +

+ + + + + + + + + + +
 ENOENT A component of the pathname no longer exists.
EIOA hard I/O error occurred.
EFAULTbuf points to an invalid address.
+ + + diff --git a/man/libc/getenv.html b/man/libc/getenv.html new file mode 100644 index 0000000..d627b4d --- /dev/null +++ b/man/libc/getenv.html @@ -0,0 +1,82 @@ + + + +getenv + + + +

getenv

+

OS/161 Reference Manual

+ +

Name

+

+getenv - retrieve an environment variable +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <stdlib.h>
+
+char *
+getenv(const char *variable); +

+ +

Description

+

+getenv retrieves the value of the environment variable +variable from the current process environment. +Unless you implement execve and environment variable passing, +the environment used is a default environment compiled into libc. +

+ +

Return Values

+

+On success, getenv returns a pointer to the value of the +requested variable. +This pointer points to internal storage and the contents should not be +modified. +The contents will in turn be stable until/unless the process +environment is modified. +If the requested variable is not found, getenv returns +NULL. +

+ +

See Also

+

+execvp +

+ + + diff --git a/man/libc/index.html b/man/libc/index.html new file mode 100644 index 0000000..2d4bb93 --- /dev/null +++ b/man/libc/index.html @@ -0,0 +1,96 @@ + + + +OS/161 C Standard Library + + + + +

OS/161 C Standard Library (libc)

+ +

+Top | +Binaries | +Sysadmin binaries | +Test binaries | +System calls | +Device drivers | +Miscellaneous +

+
+ +
    +
  • __vprintf - printf backend +
  • abort - abnormal program termination +
  • assert - check assumptions at run time +
  • atoi - convert ascii to integer +
  • bzero - zero out memory +
  • calloc - allocate and clear memory +
  • err, errx - print error messages +
  • execvp - exec on the search path +
  • exit - terminate program +
  • free - release/deallocate memory +
  • getchar - read character from standard input +
  • getcwd - get name of current working directory +
  • getenv - get environment variable +
  • longjmp - non-local jump operations +
  • malloc - allocate memory +
  • memcmp - compare regions of memory +
  • memcpy - copy region of memory +
  • memmove - copy region of memory +
  • memset - initialize region of memory +
  • printf - print formatted output +
  • putchar - print character to standard output +
  • puts - print string to standard output +
  • random - pseudorandom number generation +
  • realloc - resize allocated memory +
  • setjmp - non-local jump operations +
  • snprintf - print formatted text to string +
  • stdarg - handle functions with variable arguments +
  • strcat - concatenate strings +
  • strchr - search string for character +
  • strcmp - compare strings +
  • strcpy - copy string +
  • strerror - get error message for error code +
  • strlen - determine length of string +
  • strrchr - search string for character +
  • strtok - tokenize string +
  • strtok_r - tokenize string reentrantly +
  • system - run command as subprocess +
  • time - get time of day +
  • verr, verrx - print error messages +
  • vprintf - print formatted output +
  • vsnprintf - print formatted text to string +
  • vwarn, vwarnx - print warning messages +
  • warn, warnx - print warning messages +
+ + + diff --git a/man/libc/malloc.html b/man/libc/malloc.html new file mode 100644 index 0000000..e131d6f --- /dev/null +++ b/man/libc/malloc.html @@ -0,0 +1,108 @@ + + + +malloc + + + +

malloc

+

OS/161 Reference Manual

+ +

Name

+

+malloc - allocate memory +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <stdlib.h>
+
+void *
+malloc(size_t size); +

+ +

Description

+

+malloc allocates size bytes of memory and returns a +pointer to it. The memory is not necessarily zero-filled. (To get +zero-filled memory, call bzero or +memset, or use +calloc.) +

+ +

+The pointer returned must be suitably aligned for use with any data +type. +

+ +

+When asked to allocate zero bytes, malloc may either always +return NULL, or may return distinct non-null pointers that do +not point to any storage. +

+ +

+While malloc may at its option allocate more than +size bytes to fill a request, code that calls malloc +may not depend on such behavior and must not perform any accesses +outside of the bounds defined by size. +

+ +

+It is legitimate for memory returned by malloc to not actually be +physically mapped until it is used. +If at the time it is used, no physical memory is available and there +is no space to swap something out to make room, the process may +potentially receive a fatal signal or be killed. +This behavior is often somewhat contentious; a full discussion of the +possible alternatives and their pros and cons is well beyond the scope +of this man page. +

+ +

Return Values

+

+malloc returns a pointer to the memory allocated. If memory +cannot be obtained, NULL is returned. +

+ +

See Also

+

+calloc, +realloc, +free +

+ + + diff --git a/man/libc/memcmp.html b/man/libc/memcmp.html new file mode 100644 index 0000000..d1d8150 --- /dev/null +++ b/man/libc/memcmp.html @@ -0,0 +1,81 @@ + + + +strcmp + + + +

strcmp

+

OS/161 Reference Manual

+ +

Name

+

+memcmp - compare memory blocks +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <string.h>
+
+int
+memcmp(const void *block1, +const void *block2, +size_t len); +

+ +

Description

+

+The two memory regions block1 and block2, both of +length len, are compared lexicographically. +

+ +

Return Values

+

+If block1 sorts before block2, -1 is returned. +

+

+If block1 sorts after block2, 1 is returned. +

+

+If block1 is the same as block2, 0 is returned. +

+ +

+The sort order used is derived from the natural ordering of +the numerical values of (unsigned) characters. +

+ + + diff --git a/man/libc/memcpy.html b/man/libc/memcpy.html new file mode 100644 index 0000000..5519a2b --- /dev/null +++ b/man/libc/memcpy.html @@ -0,0 +1,76 @@ + + + +memcpy + + + +

memcpy

+

OS/161 Reference Manual

+ +

Name

+

+memcpy - copy region of memory +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <string.h>
+
+void *
+memcpy(void *dest, +const void *src, size_t len); +

+ +

Description

+

+The block of memory beginning at src, of length len, +is copied to dest. dest must point to a region large +enough to hold it. +

+ +

+memcpy is not guaranteed to operate correctly if src +and dest overlap. Use memmove on +overlapping regions. +

+ +

Return Values

+

+memcpy returns dest. +

+ + + diff --git a/man/libc/memmove.html b/man/libc/memmove.html new file mode 100644 index 0000000..281ac9b --- /dev/null +++ b/man/libc/memmove.html @@ -0,0 +1,75 @@ + + + +memmove + + + +

memmove

+

OS/161 Reference Manual

+ +

Name

+

+memmove - copy region of memory +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <string.h>
+
+void *
+memmove(void *dest, +const void *src, size_t len); +

+ +

Description

+

+The block of memory beginning at src, of length len, +is copied to dest. dest must point to a region large +enough to hold it. +

+ +

+Unlike memcpy, memmove is guaranteed +to operate correctly if src and dest overlap. +

+ +

Return Values

+

+memmove returns dest. +

+ + + diff --git a/man/libc/memset.html b/man/libc/memset.html new file mode 100644 index 0000000..c2c73b1 --- /dev/null +++ b/man/libc/memset.html @@ -0,0 +1,82 @@ + + + +memset + + + +

memset

+

OS/161 Reference Manual

+ +

Name

+

+memset - initialize region of memory +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <string.h>
+
+void *
+memset(void *buf, +int chr, size_t len); +

+ +

Description

+

+The memory region pointed to by buf, of length len, +is initialized by setting each location of it to chr +(converted to unsigned char). +

+ +

+Beware of writing +

+   memset(buf, len, 0);
+
+(which does nothing at all) when you meant +
+   memset(buf, 0, len);
+
+instead. +

+ +

Return Values

+

+memset returns buf. +

+ + + diff --git a/man/libc/printf.html b/man/libc/printf.html new file mode 100644 index 0000000..e53c152 --- /dev/null +++ b/man/libc/printf.html @@ -0,0 +1,143 @@ + + + +printf + + + +

printf

+

OS/161 Reference Manual

+ +

Name

+

+printf - print formatted output +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <stdio.h>
+
+int
+printf(const char *format, ...); +

+ +

Description

+

+printf prints formatted text to standard output. The text is +generated from the format argument and subsequent arguments +according to the following rules. +

+ +

+Characters in format that are not the percent sign +(%) are printed verbatim. When a percent sign is encountered, +the next argument of the arguments following format is +retrieved and printed. The type of the argument expected, as well as +some simple formatting instructions, are derived from the characters +following the percent sign. +

+ +

+The following characters designate types to print. One of these +characters concludes the format sequence begun with a percent sign, +and also determines the type expected as an argument. +

+ + + + + + + + + + + +
+ % A percent sign is printed; no argument + is consumed.
c Character (char, passed as an integer value)
d Signed integer value printed in decimal
o Unsigned integer value printed in octal
p Pointer (void *)
s String (const char *)
u Unsigned integer value printed in decimal
x Unsigned integer value printed in hexadecimal
X Unsigned integer value printed in uppercase hex
+ +

+The following characters are modifiers; they can be found between the +percent sign and the type designator. +

+ + + + + + + + +
+ # Select an "alternate + format". On integer formats this + causes the C base prefix to be printed + along with the integer. On other + formats, this has no effect.
l Assume an integer argument is + long or unsigned + long instead of int or + unsigned int. If repeated, + the argument is taken to be long + long or unsigned long + long.
z Assume an integer argument is + ssize_t or size_t + instead of int or + unsigned int.
0-9 Digits are treated as a decimal number, + which is considered to be the field + width. The argument is printed + right-aligned in a field that many + characters wide.
0 If the field width has a leading 0, the + padding character for alignment is + made 0 (zero) instead of + space.
- If a field width is given, use it for + left alignment instead of right + alignment.
+ +

Restrictions

+

+Note that this is a limited printf implementation - it has no support +for precisions (".number" as a modifier), floating-point formats, +field widths passed as arguments, or the rarely-used plus and space +modifiers. +

+ +

Return Values

+

+printf returns the number of characters printed. +

+ + + diff --git a/man/libc/putchar.html b/man/libc/putchar.html new file mode 100644 index 0000000..2a166c9 --- /dev/null +++ b/man/libc/putchar.html @@ -0,0 +1,75 @@ + + + +putchar + + + +

putchar

+

OS/161 Reference Manual

+ +

Name

+

+putchar - print character to standard output +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <stdio.h>
+
+int
+putchar(int chr); +

+ +

Description

+

+putchar writes its argument character to standard output. +

+ +

Return Values

+

+putchar returns chr. On error, EOF is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+

+Any of the errors from write may +occur. +

+ + + diff --git a/man/libc/puts.html b/man/libc/puts.html new file mode 100644 index 0000000..3824dc7 --- /dev/null +++ b/man/libc/puts.html @@ -0,0 +1,76 @@ + + + +puts + + + +

puts

+

OS/161 Reference Manual

+ +

Name

+

+puts - print string to standard output +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <stdio.h>
+
+int
+puts(const char *string); +

+ +

Description

+

+The string string, and a following newline character, are +printed on the standard output. +

+ +

Return Values

+

+On success, puts returns a nonnegative integer. On error, -1 is +returned, and errno is set +according to the error encountered. +

+ +

Errors

+

+Any of the errors from write may +occur. +

+ + + diff --git a/man/libc/random.html b/man/libc/random.html new file mode 100644 index 0000000..484087a --- /dev/null +++ b/man/libc/random.html @@ -0,0 +1,89 @@ + + + +random + + + +

random

+

OS/161 Reference Manual

+ +

Name

+

+random - pseudorandom number generation +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <stdlib.h>
+
+long
+random(void);
+
+void
+srandom(unsigned long seed);
+

+ +

Description

+

+random returns a number between 0 and 0x7fffffff. This +number is selected using a rather complex generator which is believed +to generate randomness of an acceptable (though not cryptographic) +quality. Unlike with some generators, all bits of the values returned +are random. +

+ +

+srandom initializes the generator state based on the +passed-in seed. If srandom is not called, the +sequence of numbers returned by random is the same as if +srandom had been called with a seed of 1. +

+ +

+The symbolic constant RAND_MAX is provided to hold the +maximum value 0x7fffffff. +This is technically incorrect as the name RAND_MAX is +properly part of a different random number interface. +

+ +

+The implementation of random and srandom used in +OS/161 is software developed by the University of California, Berkeley +and its contributors. +

+ + + diff --git a/man/libc/realloc.html b/man/libc/realloc.html new file mode 100644 index 0000000..db51303 --- /dev/null +++ b/man/libc/realloc.html @@ -0,0 +1,104 @@ + + + +realloc + + + +

realloc

+

OS/161 Reference Manual

+ +

Name

+

+realloc - resize allocated memory +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <stdlib.h>
+
+void *
+realloc(void *ptr, +size_t newsize); +

+ +

Description

+

+realloc attempts to change the size of the memory block +pointed to by ptr to newsize, causing the block to +shrink or grow as necessary. If the size cannot be changed, a new +block is allocated and the contents (up to the lesser of the previous +size and newsize) are copied, then the old block is freed. +

+ +

+The size of NULL is treated as 0. If the size is increased, +any newly allocated space has undefined contents. If the size is +decreased, the space discarded may no longer be accessed. Otherwise +the contents of the memory block are preserved. +

+ +

+ptr must be NULL or have been previously returned by +malloc, calloc, or +realloc. +

+ +The alignment and other restrictions described for +malloc apply equally to realloc. +

+ +

Return Values

+

+realloc returns a pointer to the resized memory block. This +may not be the same pointer as ptr. If so, the old block is +invalidated and ptr becomes invalid. +

+ +

+If the operation cannot be performed at all, NULL is returned and +the original block pointed to by ptr is untouched +and remains valid. +

+ +

See Also

+

+calloc, +malloc, +free +

+ + + diff --git a/man/libc/setjmp.html b/man/libc/setjmp.html new file mode 100644 index 0000000..143bad2 --- /dev/null +++ b/man/libc/setjmp.html @@ -0,0 +1,85 @@ + + + +setjmp + + + +

setjmp

+

OS/161 Reference Manual

+ +

Name

+

+setjmp, longjmp - non-local jump operations +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <setjmp.h>
+
+int
+setjmp(jmp_buf jb);
+
+void
+longjmp(jmp_buf jb, +int returncode);
+

+ +

Description

+

+setjmp saves the current stack frame and processor state in +jb. A subsequent call to longjmp with the same +jb causes execution to jump to where setjmp was +called from. +

+ +

+If the stack frame that called setjmp returns before +longjmp is called, the results are undefined. +

+ +

Return Values

+

+When called, setjmp returns 0. When longjmp is +called, it does not itself return, but instead causes setjmp +to appear to return again, this time returning returncode. +

+ +

+If zero is passed as returncode, the value 1 is used instead. +

+ + + diff --git a/man/libc/snprintf.html b/man/libc/snprintf.html new file mode 100644 index 0000000..e6268f7 --- /dev/null +++ b/man/libc/snprintf.html @@ -0,0 +1,84 @@ + + + +snprintf + + + +

snprintf

+

OS/161 Reference Manual

+ +

Name

+

+snprintf - print formatted text to string +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+snprintf(char *buf, size_t buflen, +const char *format, ...);
+
+int
+vsnprintf(char *buf, size_t buflen, +const char *format, va_list);
+

+ +

Description

+

+snprintf performs printf-style +formatting on the string format and subsequent arguments. The +resulting string is placed in buf, which is a memory area at +least buflen bytes long. A null terminator is always added to +buf; the space for this is presumed to be counted in +buflen. +

+ +

+vsnprintf is the same as snprintf, except that the +subsequent arguments are presumed to have already been collected using +the stdarg facility. +

+ +

Return Values

+

+snprintf and vsnprintf return the number of +characters printed. +

+ + + diff --git a/man/libc/stdarg.html b/man/libc/stdarg.html new file mode 100644 index 0000000..b8d52b0 --- /dev/null +++ b/man/libc/stdarg.html @@ -0,0 +1,126 @@ + + + +stdarg + + + +

stdarg

+

OS/161 Reference Manual

+ +

Name

+

+stdarg - handle functions with variable arguments +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <stdarg.h>
+
+va_start(va_list ap, +start-argument);
+
+va_end(va_list ap);
+
+type
+va_arg(va_list ap, type);
+
+va_copy(va_list dest, +va_list src);
+

+ +

Description

+

+Functions where the number of arguments is not fixed at compile time +can be written using the stdarg facility. This provides a type, +va_list, and the macros listed above. These allow iterating +through the arguments. +

+ +

+va_start initializes a va_list ap to point +to the current function's arguments. The start-argument +argument should be the name of the last fixed parameter in the calling +sequence. +(There must be at least one fixed parameter.) +

+ +

+va_end cleans up a va_list once it is no longer +needed. While failure to use va_end may have no effect on +some architectures (in fact, in some cases va_end does +nothing at all) on other architectures it may be fatal. +

+ +

+va_arg retrieves the next argument, which is presumed to be +of type type. The function must have some way to determine +what types to expect, and how many arguments, as this information +cannot be extracted from the argument list itself. To rewind, use +va_end and then va_start again. +

+ +

+Remember that default C argument promotions occur when passing the +variable arguments. There is no run-time checking of any kind, and +little to no compile-time checking: if you use va_arg to +retrieve a type different from that which was passed, you will +silently get garbage for that and (usually) all subsequent arguments. +

+ +

+va_copy assigns a copy of src to +dest. Subsequent operations on either will not affect the +other. Both copies need to be cleaned up with va_end. +

+ +

Restrictions

+

+Because the va_list is not necessarily a simple type, but may +involve pointers to state maintained elsewhere, it is not necessarily +a simple value. Thus, assigning va_list objects to each other +with `=', memcpy, or the like, or passing them to functions, may not +give multiple independent objects. When in doubt, use +va_copy, or invoke va_start multiple times. +

+ +

Return Values

+

+va_start, va_end, and va_copy do not return +anything. va_arg returns the value of the requested argument. +

+ + + diff --git a/man/libc/strcat.html b/man/libc/strcat.html new file mode 100644 index 0000000..17b0a03 --- /dev/null +++ b/man/libc/strcat.html @@ -0,0 +1,80 @@ + + + +strcat + + + +

strcat

+

OS/161 Reference Manual

+ +

Name

+

+strcat - concatenate strings +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <string.h>
+
+char *
+strcat(char *dest, +const char *src); +

+ +

Description

+

+strcat appends the contents of the string src to the +string dest. +

+ +

Restrictions

+

+If dest does not point to enough space to hold both strings, +the resulting behavior is undefined. +

+ +

+If the memory areas pointed to by dest and src +overlap, the behavior is undefined. +

+ +

Return Values

+

+strcat returns dest. +

+ + + diff --git a/man/libc/strchr.html b/man/libc/strchr.html new file mode 100644 index 0000000..ad5233f --- /dev/null +++ b/man/libc/strchr.html @@ -0,0 +1,72 @@ + + + +strchr + + + +

strchr

+

OS/161 Reference Manual

+ +

Name

+

+strchr - search string for character +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <string.h>
+
+char *
+strchr(const char *string, +int chr); +

+ +

Description

+

+strchr searches string from the left for the first +instance of the character chr. +The characters found and chr are cast to and compared as the +type unsigned char. +

+ +

Return Values

+

+strchr returns a pointer to the character found. If the +character is not found, NULL is returned. +

+ + + diff --git a/man/libc/strcmp.html b/man/libc/strcmp.html new file mode 100644 index 0000000..3a4f424 --- /dev/null +++ b/man/libc/strcmp.html @@ -0,0 +1,80 @@ + + + +strcmp + + + +

strcmp

+

OS/161 Reference Manual

+ +

Name

+

+strcmp - compare strings +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <string.h>
+
+int
+strcmp(const char *str1, +const char *str2); +

+ +

Description

+

+The two strings str1 and str2 are compared +lexicographically. +

+ +

Return Values

+

+If str1 sorts before str2, -1 is returned. +

+

+If str1 sorts after str2, 1 is returned. +

+

+If str1 is the same as str2, 0 is returned. +

+ +

+The sort order used is derived from the natural ordering of +the numerical values of (unsigned) characters. +

+ + + diff --git a/man/libc/strcpy.html b/man/libc/strcpy.html new file mode 100644 index 0000000..b67a4c2 --- /dev/null +++ b/man/libc/strcpy.html @@ -0,0 +1,80 @@ + + + +strcpy + + + +

strcpy

+

OS/161 Reference Manual

+ +

Name

+

+strcpy - copy string +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <string.h>
+
+char *
+strcpy(char *dest, +const char *src); +

+ +

Description

+

+The contents of the string src are copied into +dest. +

+ +

Restrictions

+

+If dest does not point to enough space to hold the string, +the resulting behavior is undefined. +

+ +

+If the memory areas pointed to by dest and src +overlap, the behavior is undefined. +

+ +

Return Values

+

+strcpy returns dest. +

+ + + diff --git a/man/libc/strerror.html b/man/libc/strerror.html new file mode 100644 index 0000000..db95df7 --- /dev/null +++ b/man/libc/strerror.html @@ -0,0 +1,75 @@ + + + +strerror + + + +

strerror

+

OS/161 Reference Manual

+ +

Name

+

+strerror - get error message for error code +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <string.h>
+
+const char *
+strerror(int code); +

+ +

Description

+

+The error string for the error specified by code (see +errno for more information) is +retrieved. +

+ +

+It is not itself an error to request error strings for out-of-range +values of code, but the string returned under such +circumstances may not be very enlightening when printed. +

+ +

Return Values

+

+The error string is returned. +

+ + + diff --git a/man/libc/strlen.html b/man/libc/strlen.html new file mode 100644 index 0000000..b85929f --- /dev/null +++ b/man/libc/strlen.html @@ -0,0 +1,63 @@ + + + +strlen + + + +

strlen

+

OS/161 Reference Manual

+ +

Name

+

+strlen - determine length of string +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <string.h>
+
+size_t
+strlen(const char *string); +

+ +

Description

+

+strlen returns the length of the string string. The +length does not include the null terminator. +

+ + + diff --git a/man/libc/strrchr.html b/man/libc/strrchr.html new file mode 100644 index 0000000..4378e35 --- /dev/null +++ b/man/libc/strrchr.html @@ -0,0 +1,72 @@ + + + +strrchr + + + +

strrchr

+

OS/161 Reference Manual

+ +

Name

+

+strrchr - search string for character +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <string.h>
+
+char *
+strrchr(const char *string, +int chr); +

+ +

Description

+

+strrchr searches string from the right for the first +instance of the character chr. +The characters found and chr are cast to and compared as the +type unsigned char. +

+ +

Return Values

+

+strrchr returns a pointer to the character found. If the +character is not found, NULL is returned. +

+ + + diff --git a/man/libc/strtok.html b/man/libc/strtok.html new file mode 100644 index 0000000..1442712 --- /dev/null +++ b/man/libc/strtok.html @@ -0,0 +1,101 @@ + + + +strtok + + + +

strtok

+

OS/161 Reference Manual

+ +

Name

+

+strtok - tokenize string +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <string.h>
+
+char *
+strtok(char *string, +const char *separators); +

+ +

Description

+

+strtok splits up the string string into fields using +the characters found in separators as delimiters. The +delimiters found are discarded. Multiple delimiter characters in a row +are treated as a single delimiter. +

+ +

+When first called, strtok returns the first field of +string. To retrieve successive fields of string, +call strtok again repeatedly, passing NULL as the +first argument. When no more fields are left, NULL is +returned. If the string is empty or contains only delimiters, +NULL will be returned on the first call. +

+ +

Cautions

+

+Note that the state used to remember string across calls is +global. Thus, strtok cannot be used from more than one thread +at a time in a multithreaded program, nor can it be used in a +subroutine called from within a loop that itself uses +strtok. If these restrictions are problematic, use strtok_r. +

+ +

+The behavior if strtok is called again without passing a new +string after it has returned NULL is undefined. +

+ +

+The behavior if strtok is called with the first argument NULL +without having first passed a valid string is also undefined. +

+ +

Return Values

+

+strtok returns successive components of the passed-in string, +and NULL when no more remain. +

+ + + diff --git a/man/libc/strtok_r.html b/man/libc/strtok_r.html new file mode 100644 index 0000000..41a513e --- /dev/null +++ b/man/libc/strtok_r.html @@ -0,0 +1,81 @@ + + + +strtok_r + + + +

strtok_r

+

OS/161 Reference Manual

+ +

Name

+

+strtok_r - tokenize string reentrantly +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <string.h>
+
+char *
+strtok_r(char *string, +const char *separators, +char **context); +

+ +

Description

+

+strtok_r is a reentrant version of strtok. It behaves the same way, except that the +internal state is kept using the context parameter rather +than being global. +

+ +

+The value passed to the context parameter should be the +address of a char * whose value is preserved between +successive related calls to strtok_r. The char * need not be +initialized before the first call, and its value should not be +inspected. +

+ +

Return Values

+

+strtok_r returns successive components of the passed-in +string, and NULL when no more remain. +

+ + + diff --git a/man/libc/system.html b/man/libc/system.html new file mode 100644 index 0000000..24c67aa --- /dev/null +++ b/man/libc/system.html @@ -0,0 +1,91 @@ + + + +system + + + +

system

+

OS/161 Reference Manual

+ +

Name

+

+system - run command as subprocess +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <stdlib.h>
+
+int
+system(const char *command); +

+ +

Description

+

+The system routine executes command as if it were +typed into the shell. +

+ +

Return Values

+

+On success, system returns the exit status returned from +waitpid. +On error, -1 is returned, and errno +is set according to the error encountered. +

+ +

Errors

+

+Any of the errors from fork or +waitpid. Errors generated during +execv cannot readily be reported +back in detail. +

+ +

Restrictions

+

+In OS/161 there may be no shell and when there is the shell's behavior +and syntax is not specified. For this reason we make no assumptions +about the shell's operation, and assume system cannot +reliably use the shell to parse and execute command. +Instead, system does this itself, in a way which may not +necessarily be compatible with the shell as it finally appears. You +may want to change system to invoke the shell in a suitable +fashion when/if a shell is available. +

+ + + diff --git a/man/libc/time.html b/man/libc/time.html new file mode 100644 index 0000000..c09e0dc --- /dev/null +++ b/man/libc/time.html @@ -0,0 +1,88 @@ + + + +time + + + +

time

+

OS/161 Reference Manual

+ +

Name

+

+time - get time of day +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <time.h>
+
+time_t
+time(time_t *ptr); +

+ +

Description

+

+The current time (in seconds since midnight GMT on January 1, 1970) is +retrieved. If ptr is non-null, the time is stored through +ptr. The time is also returned. +

+ +

+time is a wrapper around the system call +__time, which returns nanoseconds +as well as seconds. +

+ +

Return Values

+

+time returns the time. On error, -1 is returned, and errno is +set to indicate the error. +

+ +

Errors

+

+The following error is the only way time should be capable of +failing. +

+ + + + +
 EFAULT ptr was an invalid non-NULL + address.
+ + + diff --git a/man/libc/warn.html b/man/libc/warn.html new file mode 100644 index 0000000..e2579d6 --- /dev/null +++ b/man/libc/warn.html @@ -0,0 +1,99 @@ + + + +warn + + + +

warn

+

OS/161 Reference Manual

+ +

Name

+

+warn, warnx, vwarn, vwarnx - print warning messages +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <err.h>
+
+void
+warn(const char *format, ...);
+
+void
+warnx(const char *format, ...);
+
+void
+vwarn(const char *format, va_list);
+
+void
+vwarnx(const char *format, va_list);
+

+ +

Description

+ +

+The warn, warnx, vwarn, and vwarnx +functions print warning messages to the standard error stream. +

+ +

+warnx prints the name of the program, a colon, the text +generated by passing format and subsequent args through +printf, and a newline. +

+ +

+warn prints the same thing, except that a colon and the error +string for the current error (obtained by calling +strerror on +errno) are printed prior to the +newline. +

+ +

+vwarnx and vwarn are the same as warnx and +warn respectively, except that the additional arguments for +printf are taken to have been already packaged up in a +va_list by use of the stdarg facility. +

+ +

See Also

+

+err +

+ + + diff --git a/man/man.css b/man/man.css new file mode 100644 index 0000000..ca11f9a --- /dev/null +++ b/man/man.css @@ -0,0 +1,93 @@ +/* + * Rather than use @import, it's better to put fonts in your html: + * + * + */ +@import url(http://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic); +@import url(http://fonts.googleapis.com/css?family=Droid+Sans+Mono); + +html { + background-color: #222; +} + +body { + font-family: 'Open Sans', sans-serif; + font-size: 11pt; + line-height: 100%; + color: #444; + background-color: #fff; + max-width: 45em; + margin: 0 auto; + padding: 2em 2em 4em 2em; +} + +p { + text-align: left; + line-height: 150%; +} + +tt, code, pre { + color: #444; + font-family: 'Droid Sans Mono', monospace; + font-size: 10pt; + line-height: 100%; +} + +em { + font-weight: regular; + font-style: italic; +} + +h4, h3 { + color: #36648b; +} + +a, a:link, a:visited, a:active { + color: #36648b; + text-decoration: underline; + font-weight: bold; +} + +a:hover { + color: #000; +} + +h2, h4 { + line-height: 1em; + margin: 0 0 2em 0; +} + +/* title */ +h2 { + font-size: 1.5em; + text-align: right; + float: right; +} + +/* manual */ +h4 { + font-size: inherit; + text-align: left; + float: left; +} + +/* section */ +h3 { + clear: both; + margin: 2em 0 0 0; + font-weight: bold; + font-size: 1.2em; +} + +table { + margin: 1em 0 1em 0; + border: none; +} + +td, th { + padding: 0.5ex 1ex; + border: none; +} + diff --git a/man/manindex.css b/man/manindex.css new file mode 100644 index 0000000..e58a3ec --- /dev/null +++ b/man/manindex.css @@ -0,0 +1,78 @@ +/* + * XXX: rather than use @import, better to put fonts in your html, instead: + * + * + */ +@import url(http://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic); +@import url(http://fonts.googleapis.com/css?family=Droid+Sans+Mono); + +html { + background-color: #222; +} + +body { + font-family: 'Open Sans', sans-serif; + font-size: 11pt; + line-height: 100%; + color: #444; + background-color: #fff; + max-width: 45em; + margin: 0 auto; + padding: 2em 2em 4em 2em; +} + +p { + line-height: 150%; +} + +em { + font-weight: regular; + font-style: italic; +} + +h4, h3 { + color: #36648b; +} + +a, a:link, a:visited, a:active { + color: #36648b; + text-decoration: underline; + font-weight: bold; +} + +a:hover { + color: #000; +} + +h2, h4 { + line-height: 1em; + margin: 0 0 2em 0; +} + +/* title */ +h2 { + font-size: 1.5em; + text-align: center; +} + +/* index */ +p[align=center] { + width: 80%; + margin: 0 auto; +} + +ul { + list-style-type: none; +} + +li { + line-height: 150%; +} + +li a:first-child { + display: inline-block; + min-width: 8em; +} + diff --git a/man/misc/Makefile b/man/misc/Makefile new file mode 100644 index 0000000..c88eaf7 --- /dev/null +++ b/man/misc/Makefile @@ -0,0 +1,10 @@ +# Man pages for miscellaneous stuff + +TOP=../.. +.include "$(TOP)/mk/os161.config.mk" + +MANDIR=/man/misc +MANFILES=index.html + +.include "$(TOP)/mk/os161.man.mk" + diff --git a/man/misc/index.html b/man/misc/index.html new file mode 100644 index 0000000..6257b83 --- /dev/null +++ b/man/misc/index.html @@ -0,0 +1,54 @@ + + + +OS/161 Miscellaneous Docs + + + + +

OS/161 Miscellaneous Docs

+ +

+Top | +Binaries | +Sysadmin binaries | +Test binaries | +System calls | +C standard library | +Device drivers +

+
+ +
    +
  • semfs - userland semaphore file system +
+ + + diff --git a/man/misc/semfs.html b/man/misc/semfs.html new file mode 100644 index 0000000..f619960 --- /dev/null +++ b/man/misc/semfs.html @@ -0,0 +1,87 @@ + + + +semfs + + + +

semfs

+

OS/161 Reference Manual

+ +

Name

+

+semfs - semaphore filesystem +

+ +

Synopsis

+

+options semfs +

+ +

Description

+

+semfs is a simple "fake" (memory-only) file system that provides +synchronization facilities to userland in the form of counting +semaphores. +There is one semfs instance, called "sem:", which is created and +mounted during system boot. +

+ +

+Semaphores in semfs appear as files in "sem:". To create a semaphore, +open such a file using O_CREAT. To destroy it, remove it with +remove(). +

+ +

+To use the semaphore, write one byte to increase the semaphore count +by one (the "V" operation) and write one byte to decrease the +semaphore count by one (the "P" operation). The count will not +decrease below zero; attempts to do so will block until other +concurrent write operations raise the count again. +You can also set the count explicitly using ftruncate(); this +is useful for initializing a semaphore to a nonzero value. Note that +no data is actually transferred by the read and write calls; it is +acceptable to pass NULL as the data pointer. +

+ +

+You can create as many semaphores as you want (until memory runs out +or the directory reaches 2^32 entries); however, semfs does not +support subdirectories, hard links of semaphores, or renaming. +

+ +

Files

+

+sem: +

+ + + diff --git a/man/sbin/Makefile b/man/sbin/Makefile new file mode 100644 index 0000000..5ac3a57 --- /dev/null +++ b/man/sbin/Makefile @@ -0,0 +1,10 @@ +# Man pages for /sbin programs + +TOP=../.. +.include "$(TOP)/mk/os161.config.mk" + +MANDIR=/man/sbin +MANFILES=dumpsfs.html halt.html index.html mksfs.html poweroff.html reboot.html + +.include "$(TOP)/mk/os161.man.mk" + diff --git a/man/sbin/dumpsfs.html b/man/sbin/dumpsfs.html new file mode 100644 index 0000000..fce9fb6 --- /dev/null +++ b/man/sbin/dumpsfs.html @@ -0,0 +1,102 @@ + + + +dumpsfs + + + +

dumpsfs

+

OS/161 Reference Manual

+ +

Name

+

+dumpsfs - dump information about an SFS filesystem +

+ +

Synopsis

+

+/sbin/dumpsfs raw-device
+host-dumpsfs disk-image-file +

+ +

Description

+

+dumpsfs dumps out selected information regarding the contents +and structure of the SFS filesystem on the device it is passed. +

+ +

+Like mksfs, it is also compiled for the +System/161 host OS, and in that form can access System/161's disk +image files. +

+ +

Requirements

+

+dumpsfs uses the following system calls: +

+

+ +

+Since the fstat system call is not normally part of the basic system +calls assignment, dumpsfs will usually still not function +after that assignment is completed. +The fstat call is typically part of a later assignment, usually the +file system assignment. +Consult your course materials for specific information. +

+ +

+The host version of dumpsfs, since it runs outside of OS/161, +should always work regardless of what you have and have not +implemented. +

+ +

+Note that you may wish to extend dumpsfs in the course of doing the +file system assignment. +

+ +

See Also

+

+mksfs, +sfsck +

+ + + diff --git a/man/sbin/halt.html b/man/sbin/halt.html new file mode 100644 index 0000000..1ed481a --- /dev/null +++ b/man/sbin/halt.html @@ -0,0 +1,82 @@ + + + +halt + + + +

halt

+

OS/161 Reference Manual

+ +

Name

+

+halt - halt system +

+ +

Synopsis

+

+/sbin/halt +

+ +

Description

+

+halt shuts the system down. A clean shutdown is performed, +flushing buffers to disk, unmounting filesystems, and so forth. +

+ +

+Once shutdown is complete, halt stops execution of the +operating system. What this entails depends on the platform. On +platforms with a hardware boot monitor, it normally returns to the +boot monitor. On software-based platforms, such as System/161, it +normally terminates the software simulation. On other platforms the +system will generally wait for a keystroke on the console and then +reboot. +

+ +

Requirements

+

+halt uses the reboot +system call. +

+ +

+halt will function properly even before you do any work on +OS/161. +

+ +

See Also

+

+/bin/sync
+reboot, poweroff +

+ + + diff --git a/man/sbin/index.html b/man/sbin/index.html new file mode 100644 index 0000000..d19d445 --- /dev/null +++ b/man/sbin/index.html @@ -0,0 +1,60 @@ + + + +OS/161 Sysadmin binaries + + + + +

OS/161 Sysadmin binaries (/sbin)

+ +

+Top | +Binaries | +Test binaries | +System calls | +C standard library | +Device drivers | +Miscellaneous +

+
+ +
    +
  • dumpsfs - dump information about an + SFS filesystem +
  • halt - halt system +
  • mksfs - create an SFS filesystem +
  • poweroff - halt system and power it off +
  • reboot - reboot system +
  • sfsck - check/repair an SFS filesystem +
+ + + diff --git a/man/sbin/mksfs.html b/man/sbin/mksfs.html new file mode 100644 index 0000000..8e4bc65 --- /dev/null +++ b/man/sbin/mksfs.html @@ -0,0 +1,113 @@ + + + +mksfs + + + +

mksfs

+

OS/161 Reference Manual

+ +

Name

+

+mksfs - create an SFS filesystem +

+ +

Synopsis

+

+/sbin/mksfs raw-device volname
+host-mksfs disk-image-file volname +

+ +

Description

+

+mksfs creates a new SFS filesystem on the specified device or +disk image. The volume name is set to volname. +

+ +

+If mksfs is used under OS/161, the first form should be used, +where raw-device is a raw device name (such as "lhd1raw:"). +Don't use a device that's already mounted. Don't use a device that's +being used for swap, either. +

+ +

+mksfs can also be used on the System/161 host OS, in which +case the second form should be used. The host-compiled version of +mksfs knows how to deal with the header on System/161 disk +images and does the right thing. +

+ +

+Note that as of this writing host-mksfs cannot create +System/161 disk image files. This is a bug and will hopefully be +addressed eventually. +

+ +

Requirements

+ +

+mksfs uses the following system calls: +

+

+ +

+mksfs should function properly under OS/161 once the file +system assignment is complete. +

+ +

+The host version of mksfs, since it runs outside of OS/161, +should always work regardless of what you have and have not +implemented. +

+ +

+You will likely need to make some changes to mksfs in the +course of doing the file system assignment. +

+ +

See Also

+

+dumpsfs, +sfsck +

+ + + diff --git a/man/sbin/poweroff.html b/man/sbin/poweroff.html new file mode 100644 index 0000000..72eefa0 --- /dev/null +++ b/man/sbin/poweroff.html @@ -0,0 +1,73 @@ + + + +poweroff + + + +

poweroff

+

OS/161 Reference Manual

+ +

Name

+

+poweroff - halt system and power it off +

+ +

Synopsis

+

+/sbin/poweroff +

+ +

Description

+

+poweroff shuts down the system and then turns the system +power off. On platforms where soft power-off is not supported, +poweroff functions the same way as halt. +

+ +

Requirements

+

+poweroff uses the reboot +system call. +

+ +

+poweroff will function properly even before you do any work +on OS/161. +

+ +

See Also

+

+/bin/sync
+halt, reboot +

+ + + diff --git a/man/sbin/reboot.html b/man/sbin/reboot.html new file mode 100644 index 0000000..17a53fb --- /dev/null +++ b/man/sbin/reboot.html @@ -0,0 +1,73 @@ + + + +reboot + + + +

reboot

+

OS/161 Reference Manual

+ +

Name

+

+reboot - reboot system +

+ +

Synopsis

+

+/sbin/reboot +

+ +

Description

+

+reboot shuts the system down and then attempts to restart +it. On platforms where reboot is not possible, it behaves the same way +as halt. +

+ +

Requirements

+

+reboot uses the reboot +system call. +

+ +

+reboot will function properly even before you do any work on +OS/161. +

+ +

See Also

+

+/bin/sync
+halt, poweroff +

+ + + diff --git a/man/sbin/sfsck.html b/man/sbin/sfsck.html new file mode 100644 index 0000000..dc33f8f --- /dev/null +++ b/man/sbin/sfsck.html @@ -0,0 +1,113 @@ + + + +sfsck + + + +

sfsck

+

OS/161 Reference Manual

+ +

Name

+

+sfsck - check/repair an SFS filesystem +

+ +

Synopsis

+

+/sbin/sfsck raw-device
+host-sfsck disk-image-file +

+ +

Description

+

+sfsck checks the SFS filesystem on the specified device for +correctness and consistency. Various possible errors and corrupt +states are detected and reported; some (but not all) can be corrected. +

+ +

+If sfsck is used under OS/161, the first form should be used, +where raw-device is a raw device name (such as "lhd1raw:"). +Don't use a device that's currently mounted. +

+ +

+sfsck can also be used on the System/161 host OS, in which +case the second form should be used. The host-compiled version of +sfsck knows how to deal with the header on System/161 disk +images and does the right thing. +

+ +

Requirements

+ +

+sfsck uses the following system calls: +

+

+ +

+sfsck should function properly under OS/161 once you have +implemented the basic system calls, sbrk in the VM system, +and fstat. +

+ +

+The host version of sfsck, since it runs outside of OS/161, +should always work regardless of what you have and have not +implemented. +

+ +

+You will likely need to make some changes to sfsck in the +course of doing the file system assignment. If you are implementing +crash recovery for your file system, be sure to update sfsck +to know about any extra on-disk structures you add. You will want to +be able to use it to cross-check your recovery code... and so will the +course staff. +

+ +

See Also

+

+dumpsfs, +mksfs +

+ + + diff --git a/man/syscall/Makefile b/man/syscall/Makefile new file mode 100644 index 0000000..36c9cdd --- /dev/null +++ b/man/syscall/Makefile @@ -0,0 +1,16 @@ +# Man pages for system calls + +TOP=../.. +.include "$(TOP)/mk/os161.config.mk" + +MANDIR=/man/syscall +MANFILES=\ + __getcwd.html __time.html _exit.html chdir.html close.html dup2.html \ + errno.html execv.html fork.html fstat.html fsync.html ftruncate.html \ + getdirentry.html getpid.html index.html ioctl.html link.html \ + lseek.html lstat.html mkdir.html open.html pipe.html read.html \ + readlink.html reboot.html remove.html rename.html rmdir.html \ + sbrk.html stat.html symlink.html sync.html waitpid.html write.html + +.include "$(TOP)/mk/os161.man.mk" + diff --git a/man/syscall/__getcwd.html b/man/syscall/__getcwd.html new file mode 100644 index 0000000..1932980 --- /dev/null +++ b/man/syscall/__getcwd.html @@ -0,0 +1,109 @@ + + + +__getcwd + + + +

__getcwd

+

OS/161 Reference Manual

+ +

Name

+

+__getcwd - get name of current working directory (backend) +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+__getcwd(char *buf, +size_t buflen); +

+ +

Description

+

+The name of the current directory is computed and stored in +buf, an area of size buflen. The length of data +actually stored, which must be non-negative, is returned. +

+ +

+Note: this call behaves like read - the name +stored in buf is not 0-terminated. +

+ +

+This function is not meant to be called except by the C library; +application programmers should use getcwd +instead. +

+ +

+__getcwd (like all system calls) should be atomic. In +practice, because of complications associated with locking both up and +down trees, it often isn't quite. +Note that the kernel is not obliged to (and generally cannot) make the +__getcwd call atomic with respect to other threads in the same +process accessing the transfer buffer during the operation. +

+ +

Return Values

+

+On success, __getcwd returns the length of the data returned. +On error, -1 is returned, and errno is set +according to the error encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + +
 ENOENTA component of the pathname no + longer exists.
EIO A hard I/O error occurred.
EFAULT buf points to an invalid + address.
+

+ + + diff --git a/man/syscall/__time.html b/man/syscall/__time.html new file mode 100644 index 0000000..ae86798 --- /dev/null +++ b/man/syscall/__time.html @@ -0,0 +1,89 @@ + + + +__time + + + +

__time

+

OS/161 Reference Manual

+ +

Name

+

+__time - get time of day +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <time.h>
+
+int
+__time(time_t *seconds, +uint32_t *nanoseconds); +

+ +

Description

+

+The current time (in seconds and nanoseconds since midnight GMT on +January 1, 1970) is retrieved. If seconds and/or +nanoseconds are non-null, the corresponding components of the +time are stored through those pointers. +

+ +

Return Values

+

+__time returns 0 on success. On error, -1 is returned, and +errno is set to indicate the error. +

+ +

Errors

+

+The following error is the only way __time should be capable of failing. + + + + + +
 EFAULTseconds or nanoseconds + was an invalid non-NULL address.
+

+ +

See Also

+

+time
+

+ + + diff --git a/man/syscall/_exit.html b/man/syscall/_exit.html new file mode 100644 index 0000000..870341b --- /dev/null +++ b/man/syscall/_exit.html @@ -0,0 +1,78 @@ + + + +_exit + + + +

_exit

+

OS/161 Reference Manual

+ +

Name

+

+_exit - terminate process +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+void,
+_exit(int exitcode); +

+ +

Description

+

+Cause the current process to exit. The exit code exitcode is +reported back to other process(es) via the +waitpid() call. The process id of the exiting +process should not be reused until all processes expected to collect +the exit code with waitpid have done so. +

+ +

+Traditionally exit codes are only seven bits wide (values 0-127); +values outside this range were truncated. Portable code should not +rely on being able to use exit codes outside this range. The +definitions in OS/161 support a much wider range. +

+ +

Return Values

+

+_exit does not return. +

+ + + diff --git a/man/syscall/chdir.html b/man/syscall/chdir.html new file mode 100644 index 0000000..91bcac6 --- /dev/null +++ b/man/syscall/chdir.html @@ -0,0 +1,97 @@ + + + +chdir + + + +

chdir

+

OS/161 Reference Manual

+ +

Name

+

+chdir - change current directory +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+chdir(const char *pathname); +

+ +

Description

+

+The current directory of the current process is set to the directory +named by pathname. +

+ +

+chdir (like all system calls) should be atomic. +Note that the kernel is not obliged to (and generally cannot) make the +chdir call atomic with respect to other threads in the same +process accessing the pathname string during the operation. +

+ +

Return Values

+

+On success, chdir returns 0. On error, -1 is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other errors not +mentioned here. + + + + + + + + + +
 ENODEVThe device prefix of pathname did + not exist.
ENOTDIR A non-final component of pathname + was not a directory.
ENOTDIR pathname did not refer to a + directory.
ENOENT pathname did not exist.
EIO A hard I/O error occurred.
EFAULT pathname was an invalid pointer.
+

+ + + diff --git a/man/syscall/close.html b/man/syscall/close.html new file mode 100644 index 0000000..9f16429 --- /dev/null +++ b/man/syscall/close.html @@ -0,0 +1,96 @@ + + + +close + + + +

close

+

OS/161 Reference Manual

+ +

Name

+

+close - close file +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+close(int fd); +

+ +

Description

+

+The file handle fd is closed. The same file handle may then +be returned again from open, +dup2, pipe, or similar +calls. +

+ +

+Other file handles are not affected in any way, even if they are +attached to the same file. +

+ +

+According to POSIX, even if the underlying operation fails, the file +is closed anyway and the file handle becomes invalid. +

+ +

Return Values

+

+On success, close returns 0. On error, -1 is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + +
 EBADFfd is not a valid file handle.
EIO A hard I/O error occurred.
+

+ + + diff --git a/man/syscall/dup2.html b/man/syscall/dup2.html new file mode 100644 index 0000000..8392a86 --- /dev/null +++ b/man/syscall/dup2.html @@ -0,0 +1,134 @@ + + + +dup2 + + + +

dup2

+

OS/161 Reference Manual

+ +

Name

+

+dup2 - clone file handles +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+dup2(int oldfd, int newfd); +

+ +

Description

+

+dup2 clones the file handle oldfd onto the file +handle newfd. If newfd names an already-open file, +that file is closed. +

+ +

+The two handles refer to the same "open" of the file -- that is, +they are references to the same object and share the same seek +pointer. Note that this is different from opening the same file +twice. +

+ +

+dup2 is most commonly used to relocate opened files onto +STDIN_FILENO, STDOUT_FILENO, and/or +STDERR_FILENO. +

+ +

+Both filehandles must be non-negative, and, if applicable, smaller +than the maximum allowed file handle number. +

+ +

+The call (like all system calls) should be atomic; for single-threaded +processes this is trivial. +Multithreaded processes should never e.g. see an intermediate state +where newfd has been closed but oldfd has not yet +been cloned onto it. +Similarly, if two threads attempt e.g. dup2(3, 4) and +dup2(4, 3) simultaneously, the results must be equivalent to +one of the calls completing before the other starts. +

+ +

+Using dup2 to clone a file handle onto itself has no effect. +

+ +

+(The "2" in "dup2" arises from the existence of an older and less +powerful Unix system call "dup".) +

+ +

Return Values

+

+dup2 returns newfd. On error, -1 is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+ +

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not mentioned +here. + + + + + + + + +
 EBADFoldfd is not a valid file + handle, or newfd is a value + that cannot be a valid file + handle.
EMFILE The process's file table was full, or a + process-specific limit on open files + was reached.
ENFILE The system's file table was full, + if such a thing is possible, or a + global limit on open files was + reached.
+

+ + + diff --git a/man/syscall/errno.html b/man/syscall/errno.html new file mode 100644 index 0000000..feccf91 --- /dev/null +++ b/man/syscall/errno.html @@ -0,0 +1,435 @@ + + + +errno + + + +

errno

+

OS/161 Reference Manual

+ +

Name

+

+errno - error code reporting +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <errno.h>
+
+extern int errno; +

+ +

Description

+

+When system calls, and sometimes other functions, fail, a code +representing or describing the error condition is placed in the global +variable errno. +

+ +

+When an operation succeeds, errno is not explicitly changed; +however, operations that succeed are also not required to preserve the +pre-existing value of errno. +In general one must first check whether the operation failed, and only +then interrogate errno. +

+ +

+A handful of functions in Standard C and POSIX are explicitly defined +to preserve errno on success. These are typically functions +with not-entirely-satisfactory interfaces where the only reliable way +to detect failure is to clear errno to zero beforehand and +check it afterwards. The most common/notable example (not currently +available in OS/161's library) is strtol. +

+ +

+errno may be a macro. In a multithreaded process it is almost +invariably a macro. However, it is always an lvalue, that is, it may +be assigned to. +

+ +

+Each numeric code has a symbolic name and a textual expansion. The +symbolic names are used in source code; the textual expansions are +printed out when errors are reported to users. +

+ +

+The textual expansions can be retrieved with +strerror or printed with +err or warn. +

+ +

Symbolic names

+

+The following symbolic errors are defined in the OS/161 base system. +You may add more at your pleasure; but be sure to read the notes in +the file kern/errno.h that defines them. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 ENOSYSFunction not implemented: the action requested required + functionality not yet implemented. This is also the error + produced by attempting to make nonexistent system + calls.
ENOMEMOut of memory: a memory allocation failed. This normally + means that a process has used up all the memory available to + it. (This may be due to limits or because it has used up all + the memory available to the system.) It may also mean that + memory allocation within the kernel has failed.
EAGAINOperation would block: some resource is temporarily + unavailable, or a non-blocking I/O operation (if such things + exist) could not be completed without waiting. Historically, + the message was "Try again later"; in 4.4BSD EAGAIN and the + old EWOULDBLOCK error code were folded together.
EINTRInterrupted system call: handling of a system call was + interrupted by the delivery of a signal. (If you have + signals.)
EFAULTBad memory reference: a pointer passed as an argument was + not valid. Within the kernel, the copyin family of + functions produces this error when given an invalid + pointer.
ENAMETOOLONGString too long: a string passed as an argument was too + long to process.
EINVALInvalid argument: an argument passed to a command or system + call was badly formed, invalid, or nonsensical, in a way for + which no more specific error code is defined.
EPERMOperation not permitted: the requested operation is + restricted to privileged users, or, in some cases, prohibited + entirely. Note that "permission denied" is not EPERM.
EACCESPermission denied: the current process's credentials do not + allow the desired form of access to the target object + according to its permission settings. Note that "permission + denied" is not EPERM.
EMPROCToo many processes: the current user ID has reached its + limit of simultaneous running processes. In Unix, this is + spelled EPROCLIM.
ENPROCToo many processes on system: the system process table is + full. (Void where impossible or prohibited by law.)
ENOEXECFile is not executable: an + execv operation was + attempted but the kernel was unable to run the requested + program.
E2BIGArgument list too long: the space taken up by the + argv[] strings (and environment strings, where + applicable) passed to a newly started program is larger than + the system allows. The limit on this space is given by the + symbol ARG_MAX.
ESRCHNo such process: the supplied process ID does not name any + of the currently running processes.
ECHILDNo child processes: the current process has no exited child + processes whose exit status has not yet been collected with waitpid.
ENOTDIRNot a directory: a directory was expected and a + non-directory filesystem object was found.
EISDIRIs a directory: a non-directory was expected and a + directory was found.
ENOENTNo such file or directory: the requested filesystem object + does/did not exist.
ELOOPToo many levels of symbolic links: pathname lookup crossed + more than the maximum allowed number of symbolic links. + Usually means a link points to itself, or a family of links + has been arranged into a loop. (If you have symbolic + links.)
ENOTEMPTYDirectory not empty: a directory must be empty of + everything (except . and ..) before it may + be removed.
EEXISTFile exists: a filesystem object that was expected not to + exist did in fact already exist.
EMLINKToo many hard links: the maximum number of hard links to + the target file already exist.
EXDEVCross-device link: an attempt was made to instruct one + filesystem to handle files on another filesystem.
ENODEVNo such device: the requested device or device driver does + not exist.
ENXIODevice not available: the requested device exists but is + not available (is not mounted, is powered off, etc.)
EBUSYDevice busy: the requested object cannot be used (or, + perhaps, released) because something else is using + it.
EMFILEToo many open files: the process file table is full, so the + process cannot open more files.
ENFILEToo many open files in system: a system-wide limit of some + sort, if any exists, on the number of open files has been + reached. Void where not possible.
EBADFBad file number: a file operation was requested on an + illegal file handle, or a file handle that was not open. Or, a + write operation was attempted on a file handle that was open + only for read or vice-versa.
EIOCTLInvalid or inappropriate ioctl: an operation requested via + the ioctl system call was + not defined or could not be performed on the indicated + object. In Unix, for historical reasons, this is spelled + ENOTTY, with the historic message "Not a + typewriter".
EIOInput/output error: a hardware-level error occured on a + device. Media errors on disks fall into this + category.
ESPIPEIllegal seek: a seek operation was attempted on a + sequential object where seeking makes no sense, like a + pipe or terminal.
EPIPEBroken pipe: a write was made to a pipe or socket object + with nobody to read it.
EROFSRead-only file system: an attempt was made to modify a + filesystem that was mounted read-only. (If you have read-only + mounts.)
ENOSPCNo space left on device: the target filesystem is + full.
EDQUOTDisc(sic) quota + exceeded: the current user ID's quota (of space or + number of files) on the target filesystem has been used up. + (If you have disk quotas.)
EFBIGFile too large: an attempt was made to exceed the target + filesystem's maximum file size, or a per-user limit on maximum + file size was reached, if such a thing exists.
EFTYPEInvalid file type or format: the file provided was the + wrong kind of file or contained invalid syntax.
EDOMArgument out of range: the (numeric) argument provided was + outside the values upon which the operation is defined. For + example, attempting to evaluate the logarithm of + zero produces this error. It is sometimes also used for + non-numeric arguments where the idea of being "out of range" + still makes sense.
ERANGEResult out of range: the result of an operation did not fit + in the space provided or could not be represented. Usually + used with numeric values. String values that don't fit usually + result in ENAMETOOLONG, or in its specific case, + E2BIG.
EILSEQInvalid multibyte character sequence: the input string + contained a byte sequence whose value is undefined or whose + use is restricted. Only applicable when a multibyte character + set is in use, and if someone has added locale + support.
ENOTSOCKNot a socket: the file handle in question does not refer to + a socket, but a socket was expected.
EISSOCKIs a socket: the file handle in question refers to a + socket, but a socket was not expected. In Unix this is spelled + EOPNOTSUPP, and prints as "Operation not supported on + socket".
EISCONNSocket is already connected: given the protocol in use, the + operation requires a socket that has not yet been connected, + but the socket provided is in fact connected.
ENOTCONNSocket is not connected: given the protocol in use, the + operation requires a connected socket, but no connection has + yet been made.
ESHUTDOWNSocket has been shut down: the operation requires a running + socket, but the socket provided has been closed + down.
EPFNOSUPPORTProtocol family not supported: the requested protocol + family (PF_INET, PF_LOCAL, etc.) is not supported by the + system.
ESOCKTNOSUPPORTSocket type not supported: the requested socket type + (SOCK_STREAM, SOCK_DGRAM, etc.) is not supported by the + system.
EPROTONOSUPPORTProtocol not supported: the protocol requested for a socket + was not one supported by the system.
EPROTOTYPEProtocol wrong type for socket: the protocol requested for + a socket was not one supported by the requested socket type + and protocol family.
EAFNOSUPPORTAddress family not supported by protocol family: the + address family named in a struct sockaddr (AF_INET, AF_LOCAL, + etc.) is not supported by the protocol family used to create + the socket (PF_INET, PF_LOCAL, etc.). In practice each + protocol family has exactly one address family and the values + of AF_* and PF_* are often, if incorrectly, used + interchangeably. If you run into this error in real life, it + usually means you didn't initialize your sockaddr structures + correctly.
ENOPROTOOPTProtocol option not available: the protocol option that was + requested is not supported or cannot be activated.
EADDRINUSEAddress already in use: the requested socket address is + already in use by another socket somewhere on the + system.
EADDRNOTAVAILCannot assign requested address: the requested socket + address is unavailable. Usually caused by attempting to bind a + socket to the IP address of another machine.
ENETDOWNNetwork is down: the network or subnet needed is + offline.
ENETUNREACHNetwork is unreachable: the network or subnet needed cannot + be reached from here, possibly due to routing problems on the + network, possibly due to local configuration + trouble.
EHOSTDOWNHost is down: the specific machine requested is + offline.
EHOSTUNREACHHost is unreachable: the specific machine requested cannot + be reached from here.
ECONNREFUSEDConnection refused: the remote machine is not listening for + connections on the requested port.
ETIMEDOUTConnection timed out: there was no response from the remote + machine. It may be down, it may not be listening, or it may + not be receiving our packets at all.
ECONNRESETConnection reset by peer: the connection was abandoned by + the remote host. Usually seen on already-open connections + after the remote machine reboots and thereby loses its network + state. Sometimes also caused by defective network devices + between the local and remote hosts.
EMSGSIZEMessage too large: an internal protocol length limit was + exceeded.
ENOTSUPThreads operation not supported: a special error code + defined by the POSIX threads standard, which is a "special" + interface.
+

+ + + diff --git a/man/syscall/execv.html b/man/syscall/execv.html new file mode 100644 index 0000000..741db9a --- /dev/null +++ b/man/syscall/execv.html @@ -0,0 +1,171 @@ + + + +execv + + + +

execv

+

OS/161 Reference Manual

+ +

Name

+

+execv - execute a program +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+execv(const char *program, +char **args); +
+int
+execve(const char *program, +char **args, +char **environ); +

+ +

Description

+

+execv replaces the currently executing program with a newly +loaded program image. This occurs within one process; the process id +is unchanged. +

+ +

+The pathname of the program to run is passed as program. The +args argument is an array of 0-terminated strings. The array +itself should be terminated by a NULL pointer. +

+ +

+The argument strings should be copied into the new process as the new +process's argv[] array. In the new process, +argv[argc] must be NULL. +

+ +

+By convention, argv[0] in new processes contains the name +that was used to invoke the program. This is not necessarily the same +as program, and furthermore is only a convention and should +not be enforced by the kernel. +

+ +

+The process file table and current working directory are not modified +by execv. +

+ +

+The execve call is the same as execv except that a +NULL-terminated list of environment strings (of the form +var=value) is also passed through. In Unix, execv is +a small wrapper for execve that supplies the current process +environment. In OS/161, execv is the primary exec call and +execve is not supported or needed unless you put in extra +work to implement it. +

+ +

+The maximum total size of the argv (and environment, if any) data is +given by the system constant ARG_MAX. This comes set to 64K +by default. You may change this limit, but don't reduce it without +asking your course staff. The fact that argv blocks can be large is +part of the design problem; while it's possible to set the limit to 4K +and still have most things work, you are probably supposed to put at +least some thought into engineering a real solution. (One problem to +consider is that after the system has been up a while and system +memory starts to become fragmented, you still need to be able to +allocate enough memory to handle exec. Another is to make sure the +system doesn't choke if too many processes are trying to exec at +once. There are lots of ways to tackle this; be creative.) +

+ +

+Whether the size of the pointers appearing in the argv array +count towards the ARG_MAX limit is implementation-defined. +Either way it should be possible to pass a lot of small arguments +without bumping into some other limit on the number of pointers. +

+ +

Return Values

+

+On success, execv does not return; instead, the new program +begins executing. On failure, execv returns -1, and sets +errno to a suitable error code for the error +condition encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other errors not +mentioned here. + + + + + + + + + + + + + + + + + + + + + + +
 ENODEVThe device prefix of program did + not exist.
ENOTDIRA non-final component of program + was not a directory.
ENOENTprogram did not exist.
EISDIRprogram is a directory.
ENOEXECprogram is not in a recognizable + executable file format, was for the + wrong platform, or contained invalid + fields.
ENOMEMInsufficient virtual memory is available.
E2BIGThe total size of the argument strings + exceeeds ARG_MAX.
EIOA hard I/O error occurred.
EFAULTOne of the arguments is an invalid + pointer.
+

+ + + diff --git a/man/syscall/fork.html b/man/syscall/fork.html new file mode 100644 index 0000000..7cbe83a --- /dev/null +++ b/man/syscall/fork.html @@ -0,0 +1,112 @@ + + + +fork + + + +

fork

+

OS/161 Reference Manual

+ +

Name

+

+fork - copy the current process +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+pid_t
+fork(void); +

+ +

Description

+

+fork duplicates the currently running process. The two copies +are identical, except that one (the "new" one, or "child"), has a new, +unique process id, and in the other (the "parent") the process id is +unchanged. +

+ +

+The process id must be greater than 0. +

+ +

+The two processes do not share memory or open file tables; this state +is copied into the new process, and subsequent modification in one +process does not affect the other. +

+ +

+However, the file handle objects the file tables point to are shared, +so, for instance, calls to lseek in one process can affect the other. +

+ +

Return Values

+

+On success, fork returns twice, once in the parent process +and once in the child process. In the child process, 0 is returned. In +the parent process, the process id of the new child process is +returned. +

+ +

+On error, no new process is created. fork, only returns once, +returning -1, and errno is set according to the +error encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other errors not +mentioned here. + + + + + + + +
 EMPROCThe current user already has too + many processes.
ENPROC There are already too many + processes on the system.
ENOMEM Sufficient virtual memory for the new + process was not available.
+

+ + + diff --git a/man/syscall/fstat.html b/man/syscall/fstat.html new file mode 100644 index 0000000..f20e3a1 --- /dev/null +++ b/man/syscall/fstat.html @@ -0,0 +1,99 @@ + + + +fstat + + + +

fstat

+

OS/161 Reference Manual

+ +

Name

+

+fstat - get file state information +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <sys/stat.h>
+
+int
+fstat(int fd, +struct stat *statbuf); +

+ +

Description

+

+fstat retrieves status information about the file referred to +by the file handle fd and stores it in the stat structure +pointed to by statbuf. +

+ +

+The call (like all system calls) should be atomic; that is, the +information retrieved should come from a single point in time. +

+ +

Return Values

+

+On success, fstat returns 0. On error, -1 is returned, and errno is set according to the error encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + +
 EBADFfd is not a valid file + handle.
EIO A hard I/O error occurred.
EFAULT statbuf points to an + invalid address.
+

+ +

See Also

+

+lstat, +stat +

+ + + diff --git a/man/syscall/fsync.html b/man/syscall/fsync.html new file mode 100644 index 0000000..454897f --- /dev/null +++ b/man/syscall/fsync.html @@ -0,0 +1,90 @@ + + + +fsync + + + +

fsync

+

OS/161 Reference Manual

+ +

Name

+

+fsync - flush filesystem data for a specific file to disk +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+fsync(int fd); +

+ +

Description

+

+The fsync function forces a write of dirty filesystem buffers +and other dirty filesystem state associated with the object referred +to by fd to be written to disk. +

+ +

+fsync should not return until the writes are complete. +

+ +

Return Values

+

+On success, fsync returns 0. On error, -1 is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + +
 EBADFfd is not a valid file + handle.
EIO A hard I/O error occurred.
+

+ + + diff --git a/man/syscall/ftruncate.html b/man/syscall/ftruncate.html new file mode 100644 index 0000000..f2af14a --- /dev/null +++ b/man/syscall/ftruncate.html @@ -0,0 +1,99 @@ + + + +ftruncate + + + +

ftruncate

+

OS/161 Reference Manual

+ +

Name

+

+ftruncate - set size of a file +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+ftruncate(int fd, off_t filesize); +

+ +

Description

+

+ftruncate forcibly sets the size of the file referred to by +fd to filesize. If this expands the file, the new +data appears as if it is zero-filled. (On file systems that support +sparse files, the new space does not need to be physically allocated.) +If the action shrinks the file, the excess data is discarded. +

+ +

+The file must be open for write. +

+ +

+ftruncate must be atomic. For recoverable file systems, this +includes after crashing and running recovery. +

+ +

Return Values

+

+On success, ftruncate returns 0. On error, -1 is returned, +and errno is set according to the error +encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + +
 EBADFfd is not a valid file handle, or + it is not open for writing.
EIO A hard I/O error occurred.
EFAULT buf points to an invalid + address.
+

+ + + diff --git a/man/syscall/getdirentry.html b/man/syscall/getdirentry.html new file mode 100644 index 0000000..f123dce --- /dev/null +++ b/man/syscall/getdirentry.html @@ -0,0 +1,125 @@ + + + +getdirentry + + + +

getdirentry

+

OS/161 Reference Manual

+ +

Name

+

+getdirentry - read filename from directory +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+getdirentry(int fd, char *buf, +size_t buflen); +

+ +

Description

+

+getdirentry retrieves the next filename from a directory +referred to by the file handle filehandle. The name is stored +in buf, an area of size buflen. The length of of the +name actually found is returned. +

+ +

+Note: this call behaves like read() - the name stored in buf +is not null-terminated. +

+ +

+Which filename is the "next" is chosen based on the seek pointer +associated with the file handle. The meaning of the seek pointer on a +directory is defined by the filesystem in use and should not be +interpreted - the only ways in which lseek +should be used are with SEEK_SET and an offset previously returned by +lseek, or with any of SEEK_SET, SEEK_CUR, or SEEK_EOF with an offset +of 0. +

+ +

+getdirentry (like all system calls) should be atomic. In this +case this means that each getdirentry call should return a +name that was in the directory at the point in time when the call +happened relative to other calls. getdirentry should never +return names that have only been partially written or that have been +partially erased. +Note that the kernel is not obliged to (and generally cannot) make the +getdirentry call atomic with respect to other threads in the same +process accessing the transfer buffer during the operation. +

+ +

+In general it is desirable for directory iteration to be stable; that +is, opening a directory and reading it should yield a consistent +snapshot of the directory state. Implementing this is a nuisance in +general, and is worse in OS/161 since the system call we have can only +return one name at a time. Therefore, it isn't required by default. +(However, always check your course materials for the official word, +just in case.) +

+ +

Return Values

+

+On success, getdirentry returns the length of the name +transferred. On error, -1 is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+ + + + + + + + +
 EBADFfd is not a valid file + handle.
ENOTDIR fd does not refer to a + directory.
EIO A hard I/O error occurred.
EFAULT buf points to an invalid + address.
+ + + diff --git a/man/syscall/getpid.html b/man/syscall/getpid.html new file mode 100644 index 0000000..77f7aa0 --- /dev/null +++ b/man/syscall/getpid.html @@ -0,0 +1,67 @@ + + + +getpid + + + +

getpid

+

OS/161 Reference Manual

+ +

Name

+

+getpid - get process id +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+pid_t
+getpid(void); +

+ +

Description

+

+getpid returns the process id of the current process. +

+ +

Errors

+

+getpid does not fail. +

+ + + diff --git a/man/syscall/index.html b/man/syscall/index.html new file mode 100644 index 0000000..9a6325e --- /dev/null +++ b/man/syscall/index.html @@ -0,0 +1,91 @@ + + + +OS/161 System calls + + + + +

OS/161 System calls

+ +

+Top | +Binaries | +Sysadmin binaries | +Test binaries | +C standard library | +Device drivers | +Miscellaneous +

+
+ +
    +
  • errno - error code reporting +
+ +
    +
  • _exit - terminate process +
  • chdir - change current directory +
  • close - close file +
  • dup2 - clone file handles +
  • execv - execute a program +
  • fork - copy the current process +
  • fstat - get file state information +
  • fsync - flush filesystem data for a + specific file to disk +
  • ftruncate - set size of a file +
  • __getcwd - get name of current working + directory (backend) +
  • getdirentry - read filename from directory +
  • getpid - get process id +
  • ioctl - miscellaneous device I/O operations +
  • link - create hard link to a file +
  • lseek - change current position in file +
  • lstat - get file state information +
  • mkdir - create directory +
  • open - open a file +
  • pipe - create pipe object +
  • read - read data from file +
  • readlink - fetch symbolic link contents +
  • reboot - reboot or halt system +
  • remove - delete (unlink) a file +
  • rename - rename or move a file +
  • rmdir - remove directory +
  • sbrk - set process break (allocate memory) +
  • stat - get file state information +
  • symlink - create symbolic link +
  • sync - flush filesystem data to disk +
  • __time - get time of day +
  • waitpid - wait for a process to exit +
  • write - write data to file +
+ + + diff --git a/man/syscall/ioctl.html b/man/syscall/ioctl.html new file mode 100644 index 0000000..a23b8b4 --- /dev/null +++ b/man/syscall/ioctl.html @@ -0,0 +1,106 @@ + + + +ioctl + + + +

ioctl

+

OS/161 Reference Manual

+ +

Name

+

+ioctl - miscellaneous device I/O operations +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <sys/ioctl.h>
+
+int
+ioctl(int fd, int code, +void *data); +

+ +

Description

+

+ioctl performs an object-specific operation code on +the object referred to by the file handle fd. The +data argument may point to supplemental data required or +returned by the operation. The size of buffer required, if any, and +other such matters are operation-specific. +

+ +

+Traditionally, ioctl is a catchall function for performing operations +that don't fit neatly into any other model. +

+ +

+The ioctl codes are defined in <kern/ioctl.h>, which should be +included via <sys/ioctl.h> by user-level code. As of this +writing, the base OS/161 system defines no ioctls. However, it may +prove useful to implement some, particularly in connection with some +less conventional possible projects. +

+ +

Return Values

+

+On success, ioctl returns 0. On error, -1 is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + +
 EBADFfd was not a valid file + handle.
EIOCTL code was an invalid ioctl for the + object referenced.
EFAULT data was required by the + operation requested, but was an + invalid pointer.
+

+ + + diff --git a/man/syscall/link.html b/man/syscall/link.html new file mode 100644 index 0000000..dc87376 --- /dev/null +++ b/man/syscall/link.html @@ -0,0 +1,106 @@ + + + +link + + + +

link

+

OS/161 Reference Manual

+ +

Name

+

+link - create hard link to a file +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+link(const char *oldname, +const char *newname); +

+ +

Description

+

+link creates a new name, newname, for the file +referred to by oldname. Henceforth, both names are equally +valid ways to refer to the same file. The file is only deleted when +all names are removed. This is a "hard link". +

+ +

+The creation of the new name is atomic. The two names must be on the +same filesystem. Directories may not be hard-linked. +

+ +

Return Values

+

+On success, link returns 0. On error, -1 is returned, and errno is set according to the error encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + + + + + + + + + +
 ENODEVThe device prefix of one of the names did + not exist.
ENOTDIR A non-final component of one of the names + was not a directory.
ENOENT A non-final component of newname + did not exist.
ENOENT oldname does not exist.
EEXIST newname already exists.
EISDIR oldname is a directory.
EXDEV The two names are on different + filesystems.
EMLINK There are already too many links to + oldname.
ENOSPC The filesystem involved is full.
EIO A hard I/O error occurred.
EFAULT One of the arguments was an + invalid pointer.
+

+ + + diff --git a/man/syscall/lseek.html b/man/syscall/lseek.html new file mode 100644 index 0000000..0c3c407 --- /dev/null +++ b/man/syscall/lseek.html @@ -0,0 +1,135 @@ + + + +lseek + + + +

lseek

+

OS/161 Reference Manual

+ +

Name

+

+lseek - change current position in file +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+off_t
+lseek(int fd, off_t pos, +int whence); +

+ +

Description

+

+lseek alters the current seek position of the file handle +filehandle, seeking to a new position based on pos +and whence. +

+ +

+If whence is +

    +
  • SEEK_SET, the new position is pos. +
  • SEEK_CUR, the new position is the current position plus pos. +
  • SEEK_END, the new position is the position of end-of-file + plus pos. +
  • anything else, lseek fails. +
+Note that pos is a signed quantity. +

+ +

+It is not meaningful to seek on certain objects, such as the console +device. All seeks on these objects fail. +

+ +

+Seek positions less than zero are invalid. Seek positions beyond EOF +are legal, at least on regular files. +

+ +

+As discussed under getdirentry, seek +positions on directories are defined by the file system and should not +be interpreted. +

+ +

+Note that each distinct open of a file should have an independent seek +pointer. +

+ +

+lseek (like all system calls) should be atomic. In this case +this means that multiple threads or processes sharing the same seek +pointer should be able to update it without seeing or generating +invalid intermediate states. There is no provision for making pairs of +lseek and read or write calls atomic. The +pread and pwrite calls in Unix were invented to +address this issue. (These are not in OS/161 by default but are easy +to implement.) +

+ +

Return Values

+

+On success, lseek returns the new position. On error, -1 is +returned, and errno is set according to the +error encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + + +
 EBADFfd is not a valid file + handle.
ESPIPE fd refers to an object + which does not support seeking.
EINVAL whence is invalid.
EINVAL The resulting seek position would + be negative.
+

+ + + diff --git a/man/syscall/lstat.html b/man/syscall/lstat.html new file mode 100644 index 0000000..6cb7377 --- /dev/null +++ b/man/syscall/lstat.html @@ -0,0 +1,112 @@ + + + +lstat + + + +

lstat

+

OS/161 Reference Manual

+ +

Name

+

+lstat - get file state information +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <sys/stat.h>
+
+int
+lstat(const char *pathname, +struct stat *statbuf); +

+ +

Description

+

+lstat retrieves status information about the file referred to by +pathname and stores it in the stat structure pointed to +by statbuf. +

+ +

+If pathname refers to a symbolic link, information about the +link is retrieved rather than about the object the link points to. +

+ +

+The call (like all system calls) should be atomic; that is, the +information retrieved should come from a single point in time. +

+ +

Return Values

+

+On success, lstat returns 0. On error, -1 is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + + + + + + + +
 ENODEVThe device prefix of filename did + not exist.
ENOTDIRA non-final component of pathname + was not a directory.
ENOENTThe named file does not exist.
EIOA hard I/O error occurred.
EFAULTstatbuf points to an invalid + address.
+

+ +

See Also

+

+fstat, +stat +

+ + + diff --git a/man/syscall/mkdir.html b/man/syscall/mkdir.html new file mode 100644 index 0000000..262ce4c --- /dev/null +++ b/man/syscall/mkdir.html @@ -0,0 +1,106 @@ + + + +mkdir + + + +

mkdir

+

OS/161 Reference Manual

+ +

Name

+

+mkdir - create directory +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <sys/stat.h>
+
+int
+mkdir(const char *pathname, +mode_t mode); +

+ +

Description

+

+mkdir creates a directory named name, where +name is the last filename component in pathname. All +the directories named in the prefix portion of pathname must +exist and must in fact be directories, not ordinary files. The name +name must not already exist. The new directory must be +created atomically. +

+ +

+The mode argument gives the file permissions to use and can +be ignored in OS/161. +

+ +

Return Values

+

+On success, mkdir returns 0. On error, -1 is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + + + + + + +
 ENODEVThe device prefix of pathname did + not exist.
ENOTDIR A non-final component of pathname + was not a directory.
ENOENT A non-final component of pathname + did not exist.
EEXIST An object by the name pathname + already exists.
ENOSPC The filesystem the directory was to be + created on is full.
EIO A hard I/O error occurred.
EFAULT pathname was an invalid + pointer.
EINVAL mode was invalid.
+

+ + + diff --git a/man/syscall/open.html b/man/syscall/open.html new file mode 100644 index 0000000..7abc154 --- /dev/null +++ b/man/syscall/open.html @@ -0,0 +1,176 @@ + + + +open + + + +

open

+

OS/161 Reference Manual

+ +

Name

+

+open - open a file +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+#include <fcntl.h>
+
+int
+open(const char *filename, +int flags);
+int
+open(const char *filename, int flags, +mode_t mode);
+

+ +

Description

+

+open opens the file, device, or other kernel object named by +the pathname filename. The flags argument specifies +how to open the file. The optional mode argument provides the +file permissions to use and is only meaningful in Unix, or if you +choose to implement Unix-style security later on. it can be ignored in +OS/161. +

+ +

+The flags argument should consist of one of + + + + + +
 O_RDONLY Open for reading only.
O_WRONLY Open for writing only.
O_RDWR Open for reading and writing.
+

+ +

+It may also have any of the following flags OR'd in: + + + + + + + +
 O_CREATCreate the file if it doesn't exist.
O_EXCL Fail if the file already exists.
O_TRUNC Truncate the file to length 0 upon open.
O_APPEND Open the file in append mode.
+O_EXCL is only meaningful if O_CREAT is also used. +

+ +

+O_APPEND causes all writes to the file to occur at the end of file, no +matter what gets written to the file by whoever else, including +concurrently. (This functionality may be optional; consult your +course's assignments.) +

+ +

+open returns a file handle suitable for passing to +read, +write, +close, +etc. This file handle must be greater than or equal to zero. Note +that file handles 0 (STDIN_FILENO), 1 (STDOUT_FILENO), and 2 +(STDERR_FILENO) are used in special ways and are typically assumed by +user-level code to always be open. +

+ +

+If you are implementing symbolic links, there are some additional +points to take note of. If filename refers to a symbolic +link, that link does not point to an existing object, and O_CREAT is +specified, a new file is created at the name the link points +to. However, if in this case both O_CREAT and O_EXCL are +specified, open fails with EEXIST. These semantics are a +nuisance to implement but important for correct functioning. +

+ +

+open (like all system calls) should be atomic. It is +important for the handling of O_EXCL in the destination directory to +be atomic. Note, however, that in practice looking up directories that +contain .. is usually not quite atomic. +

+ +

Return Values

+

+On success, open returns a nonnegative file handle. On error, +-1 is returned, and errno is set according to +the error encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + + + + + + + + + + + +
 ENODEVThe device prefix of filename did + not exist.
ENOTDIR A non-final component of filename + was not a directory.
ENOENT A non-final component of filename + did not exist.
ENOENT The named file does not exist, and O_CREAT + was not specified.
EEXIST The named file exists, and O_EXCL was + specified.
EISDIR The named object is a directory, and it + was to be opened for writing.
EMFILE The process's file table was full, or a + process-specific limit on open files + was reached.
ENFILE The system file table is full, if such a + thing exists, or a system-wide limit + on open files was reached.
ENXIO The named object is a block device with no + filesystem mounted on it.
ENOSPC The file was to be created, and the + filesystem involved is full.
EINVAL flags contained invalid + values.
EIO A hard I/O error occurred.
EFAULT filename was an invalid + pointer.
+

+ + + diff --git a/man/syscall/pipe.html b/man/syscall/pipe.html new file mode 100644 index 0000000..ace022b --- /dev/null +++ b/man/syscall/pipe.html @@ -0,0 +1,120 @@ + + + +pipe + + + +

pipe

+

OS/161 Reference Manual

+ +

Name

+

+pipe - create pipe object +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+pipe(int *fds); +

+ +

Description

+

+The pipe call creates an anonymous pipe object in the system, +and binds it to two file handles in the current process, one for the +read end and one for the write end. (Pipes are unidirectional.) +

+ +

+Data written on the write end may be read from the read end. Once all +references to the write end are closed, and all remaining data is +read, further reads return EOF. If all references to the read end are +closed before the write end is closed, further writes generate EPIPE. +The pipe object itself is destroyed when all references to both ends +are closed. +

+ +

+fds is a pointer to space for two integers. A file handle for +the read end of the pipe is stored in fds[0], and a file +handle for the write end is stored in fds[1]. +

+ +

+pipe is most often used in conjunction with dup2 and fork to send the +standard output of one process to the standard input of another. +

+ +

+In POSIX, pipe I/O of data blocks smaller than a standard constant +PIPE_BUF is guaranteed to be atomic. If you implement pipes, you need +not necessarily implement POSIX semantics, but you should decide what +sort of atomicity guarantees you wish to make and specify them +carefully. +

+ +

Return Values

+

+On success, pipe returns 0. On error, -1 is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + +
 EMFILEThe process's file table was full, or a + process-specific limit on open files + was reached.
ENFILE The system file table is full, if such a + thing exists, or a system-wide limit + on open files was reached.
EFAULT fds was an invalid + pointer.
+

+ + + diff --git a/man/syscall/read.html b/man/syscall/read.html new file mode 100644 index 0000000..e605841 --- /dev/null +++ b/man/syscall/read.html @@ -0,0 +1,115 @@ + + + +read + + + +

read

+

OS/161 Reference Manual

+ +

Name

+

+read - read data from file +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+ssize_t
+read(int fd, void *buf, +size_t buflen); +

+ +

Description

+

+read reads up to buflen bytes from the file +specified by fd, at the location in the file specified by the +current seek position of the file, and stores them in the space +pointed to by buf. The file must be open for reading. +

+ +

+The current seek position of the file is advanced by the number of +bytes read. +

+ +

+Each read (or write) operation is atomic +relative to other I/O to the same file. +Note that the kernel is not obliged to (and generally cannot) make the +read atomic with respect to other threads in the same process +accessing the I/O buffer during the read. +

+ +

Return Values

+

+The count of bytes read is returned. This count should be +positive. A return value of 0 should be construed as signifying +end-of-file. On error, read returns -1 and sets +errno to a suitable error code for the error +condition encountered. +

+ +

+Note that in some cases, particularly on devices, fewer than +buflen (but greater than zero) bytes may be returned. This +depends on circumstances and does not necessarily signify +end-of-file. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + + + +
 EBADFfd is not a valid file descriptor, or was + not opened for reading.
EFAULTPart or all of the address space pointed to by + buf is invalid.
EIOA hardware I/O error occurred reading the + data.
+

+ + + diff --git a/man/syscall/readlink.html b/man/syscall/readlink.html new file mode 100644 index 0000000..bb3cd31 --- /dev/null +++ b/man/syscall/readlink.html @@ -0,0 +1,104 @@ + + + +readlink + + + +

readlink

+

OS/161 Reference Manual

+ +

Name

+

+readlink - fetch symbolic link contents +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+readlink(const char *path, char *buf, +size_t len); +

+ +

Description

+

+readlink retrieves the contents of the symbolic link named by +path and places them in the buffer buf. At most +len bytes are written. +

+ +

+readlink does not include a null terminator in buf. +

+ +

+The call (like all system calls) should be atomic. +Note that the kernel is not obliged to (and generally cannot) make the +read atomic with respect to other threads in the same process +accessing the buffer during the operation. +

+ +

Return Values

+

+readlink returns the number of characters transferred. If an +error occurs, -1 is returned, and errno is set +according to the error encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + + + + +
 ENODEVThe device prefix of filename did + not exist.
ENOTDIR A non-final component of path + was not a directory.
ENOENT The named file does not exist.
EINVAL The named file is not a symlink.
EIO A hard I/O error occurred.
EFAULT buf or path points to an + invalid address.
+

+ + + diff --git a/man/syscall/reboot.html b/man/syscall/reboot.html new file mode 100644 index 0000000..611640d --- /dev/null +++ b/man/syscall/reboot.html @@ -0,0 +1,93 @@ + + + +reboot + + + +

reboot

+

OS/161 Reference Manual

+ +

Name

+

+reboot - reboot or halt system +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+reboot(int code); +

+ +

Description

+

+reboot reboots or shuts down the system. The specific action +depends on the code passed: + + + + + +
 RB_REBOOT The system is rebooted.
RB_HALT The system is halted.
RB_POWEROFF The system is powered off.
+

+ +

Return Values

+

+On success, reboot does not return. On error, -1 is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + +
 EINVALcode was not a valid + value.
EPERM The current process does not have + sufficient privilege to halt the + system.
+

+ + + diff --git a/man/syscall/remove.html b/man/syscall/remove.html new file mode 100644 index 0000000..3e7cc37 --- /dev/null +++ b/man/syscall/remove.html @@ -0,0 +1,107 @@ + + + +remove + + + +

remove

+

OS/161 Reference Manual

+ +

Name

+

+remove - delete (unlink) a file +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+remove(const char *pathname); +

+ +

Description

+

+The name of the file referred to by pathname is removed from +the filesystem. The actual file itself is not removed until no further +references to it exist, whether those references are on disk or in +memory. +

+ +

+It is an error for pathname to not specify an existing file +or to refer to a directory. +

+ +

+The call (like all system calls) should be atomic. Other processes +should not be able to see a half-removed file. If implementing a +recoverable filesystem, recovery must yield a volume where the +remove either has been fully completed or has not been done +at all. +

+ +

Return Values

+

+On success, remove returns 0. On error, -1 is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + + + + +
 ENODEVThe device prefix of filename did + not exist.
ENOTDIR A non-final component of pathname + was not a directory.
EISDIR pathname referred to a + directory.
ENOENT The target file did not exist.
EIO A hard I/O error occurred.
EFAULT pathname was an invalid + pointer.
+

+ + + diff --git a/man/syscall/rename.html b/man/syscall/rename.html new file mode 100644 index 0000000..6c4277f --- /dev/null +++ b/man/syscall/rename.html @@ -0,0 +1,155 @@ + + + +rename + + + +

rename

+

OS/161 Reference Manual

+ +

Name

+

+rename - rename or move a file +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+rename(const char *oldname, +const char *newname); +

+ +

Description

+

+The file (or other object) referenced by oldname is given the +name newname, and the name oldname is removed. If +newname already exists, it is removed as well. (The semantics +for removing files and directories described under +remove and rmdir +must be honored.) +

+ +

+If newname exists, it must be a directory if and only if +oldname also is. +

+ +

+If components of the path prefix of newname do not exist or +are not directories, rename fails. Additionally, oldname and +newname must refer to names on the same filesystem. +

+ +

+If oldname and newname are the same file, rename +succeeds and the state of the filesystem is not altered. This is true +even if they are not in the same directory. (POSIX says so. This is +widely considered a bug in POSIX.) +

+ +

+Rename must be atomic; no other process on the system should be able +to see the filesystem in a state where both (or neither) +oldname and newname name the file. Additionally, if +the system crashes, at least one name for the file must remain. +(If you are implementing a file system with crash recovery, a crash +during rename must, after recovery, produce a volume where the rename +has either occurred or not occurred; no intermediate states may be +exposed.) +

+ +

+If oldname is a directory, newname must not refer to +a subdirectory of oldname, as this would create a (detached) +cycle in the directory tree. +

+ +

+Renaming (or overwriting) the . or .. entries in +directories is prohibited. +

+ +

Return Values

+

+On success, rename returns 0. On error, -1 is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other errors not +mentioned here. + + + + + + + + + + + + + + + + + +
 ENODEVThe device prefix of one of the names did + not exist.
ENOTDIR A non-final component of one of the names + was not a directory.
ENOENT A non-final component of newname + did not exist.
ENOENT oldname does not exist.
ENOTDIR oldname is a directory, and + newname is not.
EISDIR oldname is not a directory, and + newname is.
ENOTEMPTYnewname is a directory, and it is + not empty.
EXDEV The two names are on different + filesystems.
EINVAL newname is a subdirectory of + oldname.
EINVAL An attempt was made to rename a + . or .. entry.
ENOSPC The filesystem involved is full.
EIO A hard I/O error occurred.
EFAULT One of the arguments was an + invalid pointer.
+

+ +

+As with rmdir, attempts to rename with newname equal to +.. may generate either EINVAL or ENOTEMPTY. +

+ + + diff --git a/man/syscall/rmdir.html b/man/syscall/rmdir.html new file mode 100644 index 0000000..3ef5e58 --- /dev/null +++ b/man/syscall/rmdir.html @@ -0,0 +1,133 @@ + + + +rmdir + + + +

rmdir

+

OS/161 Reference Manual

+ +

Name

+

+rmdir - remove directory +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+rmdir(const char *pathname); +

+ +

Description

+

+rmdir removes the directory named by pathname. The directory +(and all the components in its path prefix) must exist. The directory +must be empty, except for the . and .. entries, and +may not be the root directory of the filesystem. +

+ +

+It is invalid to attempt to remove the . or .. +entries in a directory. What rmdir actually removes is a name in some +(other, containing) directory; removing the . or .. +names would make a mess. It is not invalid for a process to +remove its own current directory, but it does not work to do so by +calling rmdir("."). +

+ +

+It is impossible in any event to remove a directory named with +.., because it is impossible to name a directory with +.. unless it is not empty. +

+ +

+If a directory is in use (e.g. being read by ls, or is some +process's current directory, etc.) when it is removed, all further +accesses to it should be rejected (with ENOENT). Like a file deleted +while in use, it should only be fully removed when all remaining +references to it are dropped. +

+ +

+The removal must be atomic, both with respect to other running +processes, and (if implementing a recoverable file system) with +respect to crash recovery. +

+ +

Return Values

+

+On success, rmdir returns 0. On error, -1 is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other errors not +mentioned here. + + + + + + + + + + + + +
 ENODEVThe device prefix of filename did + not exist.
ENOTDIR A non-final component of pathname + was not a directory.
ENOTDIR pathname referred to an + object that was not a directory.
ENOENT The target directory did not + exist.
EINVAL An attempt was made to remove a + . or .. entry.
ENOTEMPTYThe target directory was not + empty.
EIO A hard I/O error occurred.
EFAULT pathname was an invalid + pointer.
+

+ +

+Attempts to remove .. may generate either EINVAL or +ENOTEMPTY. +

+ + + diff --git a/man/syscall/sbrk.html b/man/syscall/sbrk.html new file mode 100644 index 0000000..57c3a53 --- /dev/null +++ b/man/syscall/sbrk.html @@ -0,0 +1,144 @@ + + + +sbrk + + + +

sbrk

+

OS/161 Reference Manual

+ +

Name

+

+sbrk - set process break (allocate memory) +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+void *
+sbrk(intptr_t amount); +

+ +

Description

+

+The "break" is the end address of a process's heap region. The +sbrk call adjusts the "break" by the amount amount. +It returns the old "break". Thus, to determine the current "break", +call sbrk(0). +

+ +

+The heap region is initially empty, so at process startup, the +beginning of the heap region is the same as the end and may thus be +retrieved using sbrk(0). +

+ +

+In OS/161, the initial "break" must be page-aligned, and sbrk +only need support values of amount that result in +page-aligned "break" addresses. Other values of amount may be +rejected. This may simplify the implementation. You may place the +heap wherever you like in a process's address space (though obviously +not on top of something else) and it need not appear at the same +location in every process. +

+ +

+Traditionally, the initial "break" is specifically defined to be the +end of the BSS (uninitialized data) region, and traditionally any +amount, page-aligned or not, may legally be used with +sbrk. +

+ +

+Ordinarily, user-level code should call +malloc for memory allocation. The +sbrk interface is intended only to be the back-end interface +for malloc. Mixing calls to malloc and sbrk +will likely confuse malloc and produces undefined behavior. +

+ +

+While one can lower the "break" by passing negative values of +amount, one may not set the end of the heap to an address +lower than the beginning of the heap. Attempts to do so must be +rejected. +

+ +

+The call (like all system calls) should be atomic. In this case, that +means that if you have a multithreaded process, simultaneous calls to +sbrk from different threads should not interfere with each +other and should update the "break" state atomically. +

+ +

Return Values

+

+On success, sbrk returns the previous value of the "break". +On error, ((void *)-1) is returned, and errno +is set according to the error encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + +
 ENOMEMSufficient virtual memory to satisfy the + request was not available, or the + process has reached the limit of the + memory it is allowed to allocate.
EINVALThe request would move the "break" below + its initial value.
+

+ +

Restrictions

+

+While you can return pages that happen to be at the end of the heap to +the system, there is no way to use the sbrk interface to +return unused pages in the middle of the heap. If you wish to do this, +you will need to design a new or supplemental interface. +

+ + + diff --git a/man/syscall/stat.html b/man/syscall/stat.html new file mode 100644 index 0000000..3800455 --- /dev/null +++ b/man/syscall/stat.html @@ -0,0 +1,103 @@ + + + +stat + + + +

stat

+

OS/161 Reference Manual

+ +

Name

+

+stat - get file state information +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <sys/stat.h>
+
+int
+stat(const char *pathname, +struct stat *statbuf); +

+ +

Description

+

+stat retrieves status information about the file referred to +by pathname and stores it in the stat structure pointed to by +statbuf. +

+ +

+The call (like all system calls) should be atomic; that is, the +information retrieved should come from a single point in time. +

+ +

Return Values

+

+On success, stat returns 0. On error, -1 is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + + + +
 ENODEVThe device prefix of filename did + not exist.
ENOTDIR A non-final component of pathname + was not a directory.
ENOENT The named file does not exist.
EIO A hard I/O error occurred.
EFAULT statbuf points to an invalid + address.
+

+ +

See Also

+

+fstat, +lstat +

+ + + diff --git a/man/syscall/symlink.html b/man/syscall/symlink.html new file mode 100644 index 0000000..5de10d0 --- /dev/null +++ b/man/syscall/symlink.html @@ -0,0 +1,107 @@ + + + +symlink + + + +

symlink

+

OS/161 Reference Manual

+ +

Name

+

+symlink - create symbolic link +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+int
+symlink(const char *oldname, +const char *linkname); +

+ +

Description

+

+symlink creates a symbolic link. The symlink itself is named +linkname, and it points to oldname. +

+ +

+oldname need not exist or be on the same filesystem. +

+ +

+The call (like all system calls) must be atomic; that is, the symlink +should either be created or not created, and no other process should +see an intermediate state (such as, for example, a blank symlink whose +name hasn't been written out yet...) For recoverable file systems, +this includes after crash recovery. +

+ +

Return Values

+

+On success, symlink returns 0. On error, -1 is returned, and +errno is set according to the error +encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + + + + + +
 ENODEVThe device prefix of filename did + not exist.
ENOTDIR A non-final component of linkname + was not a directory.
ENOENT A non-final component of linkname + did not exist.
EEXIST linkname already exists.
ENOSPC The filesystem that was to hold the link + is full.
EIO A hard I/O error occurred.
EFAULT linkname or oldname was + an invalid pointer.
+

+ + + diff --git a/man/syscall/sync.html b/man/syscall/sync.html new file mode 100644 index 0000000..fb26d66 --- /dev/null +++ b/man/syscall/sync.html @@ -0,0 +1,73 @@ + + + +sync + + + +

sync

+

OS/161 Reference Manual

+ +

Name

+

+sync - flush filesystem data to disk +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+void
+sync(void); +

+ +

Description

+

+The sync function forces a write of all dirty filesystem +buffers and dirty filesystem state to disk. +

+ +

Return Values

+

+No value is returned, and sync does not fail. +

+ +

Errors

+

+None. +

+ + + diff --git a/man/syscall/waitpid.html b/man/syscall/waitpid.html new file mode 100644 index 0000000..18d2a6b --- /dev/null +++ b/man/syscall/waitpid.html @@ -0,0 +1,204 @@ + + + +waitpid + + + +

waitpid

+

OS/161 Reference Manual

+ +

Name

+

+waitpid - wait for a process to exit +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <sys/wait.h>
+
+pid_t
+waitpid(pid_t pid, int *status, +int options); +

+ +

Description

+

+Wait for the process specified by pid to exit, and return an +encoded exit status in the integer pointed to by status. If +that process has exited already, waitpid returns +immediately. If that process does not exist, waitpid fails. +

+ +

+It is explicitly allowed for status to be NULL, in +which case waitpid operates normally but the status value is not +produced. +

+ +

+A process moves from "has exited already" to "does not exist" when +every process that is expected to collect its exit status with +waitpid has done so. +

+ +

+In the standard Unix model of processes, the only process that is +expected to collect another process's exit status is its parent. +(If you feel this is restrictive, you might try to extend the model or +define a new one; however, this is not recommended. The only other +model that really makes much sense is to let any process wait for any +other process; but then you need to check for and reject combinations +that would cause deadlock.) +

+ +

+There are several semi-standard and messy/ugly ways in Unix for a +process to indicate that it doesn't want to collect the exit status of +a child it forks and therefore shouldn't be expected to. You do not +need to implement any of these, but you might find it convenient for +your own purposes to provide this functionality. +

+ +

+If a parent process exits before one or more of its children, it can +no longer be expected collect their exit status. There are several +ways to handle this case in practice, of which the traditional Unix +method is only one. This is something you should design. +

+ +

+The options argument should be 0. You are not required to +implement any options. (However, your system should check to make sure +that requests for options you do not support are rejected.) +

+ +

+If you desire, you may implement the Unix option WNOHANG; this causes +waitpid, when called for a process that has not yet exited, to return +0 immediately instead of waiting. +

+ +

+The Unix option WUNTRACED, to ask for reporting of processes that stop +as well as exit, is also defined in the header files, but implementing +this feature is not required or necessary unless you are implementing +job control. +

+ +

+You may also make up your own options if you find them helpful. +However, please, document anything you make up. +

+ +

+The encoding of the exit status is comparable to Unix and is defined +by the flags found in <kern/wait.h>. (Userlevel code should +include <sys/wait.h> to get these definitions.) A process can +exit by calling _exit() or it can exit by +receiving a fatal signal. In the former case the +_MKWAIT_EXIT() macro should be used with the user-supplied +exit code value to prepare the exit status; in the latter, the +_MKWAIT_SIG() macro (or _MKWAIT_CORE() if a core +file was generated) should be used with the signal number. The result +encoding also allows notification of processes that have stopped; this +would be used in connection with job control and with +ptrace-based debugging if you were to implement those things. +

+ +

+The _MKWAIT flags are not standard and should be considered +part of the implementation. +

+ +

+To read the wait status, use the macros WIFEXITED(), +WIFSIGNALED(), and/or WIFSTOPPED() to find out what +happened, and then WEXITSTATUS(), WTERMSIG(), or +WSTOPSIG() respectively to get the exit code or signal +number. If WIFSIGNALED() is true, WCOREDUMP() can be +used to check if a core file was generated. This is the same as Unix, +although the value encoding is different from the historic Unix +format. +

+ +

Return Values

+

+waitpid returns the process id whose exit status is reported in +status. In OS/161, this is always the value of pid. +

+ +

+(In Unix, but not by default OS/161, you can wait for any of several +processes by passing magic values of pid, so this return +value can actually be useful.) +

+ +

+If you implement WNOHANG, and WNOHANG is given, and the process +specified by pid has not yet exited, waitpid returns 0. +

+ +

+On error, -1 is returned, and errno is set to a +suitable error code for the error condition encountered. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + + + + + +
 EINVALThe options argument requested invalid or + unsupported options.
ECHILDThe pid argument named a process + that was not a child of the current + process.
ESRCHThe pid argument named a + nonexistent process.
EFAULTThe status argument was an + invalid pointer.
+

+ + + diff --git a/man/syscall/write.html b/man/syscall/write.html new file mode 100644 index 0000000..aaf3736 --- /dev/null +++ b/man/syscall/write.html @@ -0,0 +1,120 @@ + + + +write + + + +

write

+

OS/161 Reference Manual

+ +

Name

+

+write - write data to file +

+ +

Library

+

+Standard C Library (libc, -lc) +

+ +

Synopsis

+

+#include <unistd.h>
+
+ssize_t
+write(int fd, const void *buf, +size_t nbytes); +

+ +

Description

+

+write writes up to buflen bytes to the file +specified by fd, at the location in the file specified by the +current seek position of the file, taking the data from the space +pointed to by buf. The file must be open for writing. +

+ +

+The current seek position of the file is advanced by the number of +bytes written. +

+ +

+Each write (or read) operation is atomic +relative to other I/O to the same file. +Note that the kernel is not obliged to (and generally cannot) make the +write atomic with respect to other threads in the same process +accessing the I/O buffer during the write. +

+ +

Return Values

+

+The count of bytes written is returned. This count should be +positive. A return value of 0 means that nothing could be written, +but that no error occurred; this only occurs at end-of-file on +fixed-size objects. On error, write returns -1 and sets +errno to a suitable error code for the error +condition encountered. +

+ +

+Note that in some cases, particularly on devices, fewer than +buflen (but greater than zero) bytes may be written. This +depends on circumstances and does not necessarily signify +end-of-file. In most cases, one should loop to make sure that all +output has actually been written. +

+ +

Errors

+

+The following error codes should be returned under the conditions +given. Other error codes may be returned for other cases not +mentioned here. + + + + + + + + + + + +
 EBADFfd is not a valid file descriptor, or was + not opened for writing.
EFAULTPart or all of the address space pointed to by + buf is invalid.
ENOSPCThere is no free space remaining on the filesystem + containing the file.
EIOA hardware I/O error occurred writing + the data.
+

+ + + diff --git a/man/testbin/Makefile b/man/testbin/Makefile new file mode 100644 index 0000000..1ed40bf --- /dev/null +++ b/man/testbin/Makefile @@ -0,0 +1,17 @@ +# Man pages for /testbin programs + +TOP=../.. +.include "$(TOP)/mk/os161.config.mk" + +MANDIR=/man/testbin +MANFILES=\ + add.html argtest.html badcall.html bigfile.html conman.html \ + crash.html ctest.html dirseek.html dirtest.html f_test.html \ + farm.html faulter.html filetest.html forkbomb.html forktest.html \ + guzzle.html hash.html hog.html huge.html index.html kitchen.html \ + malloctest.html matmult.html palin.html randcall.html rmdirtest.html \ + rmtest.html sink.html sort.html sty.html tail.html tictac.html \ + triplehuge.html triplemat.html triplesort.html userthreads.html + +.include "$(TOP)/mk/os161.man.mk" + diff --git a/man/testbin/add.html b/man/testbin/add.html new file mode 100644 index 0000000..b95e9aa --- /dev/null +++ b/man/testbin/add.html @@ -0,0 +1,67 @@ + + + +add + + + +

add

+

OS/161 Reference Manual

+ +

Name

+

+add - add two numbers +

+ +

Synopsis

+

+/testbin/add n1 n2 +

+ +

Description

+

+add prints the sum of the two numbers passed as arguments. +

+ +

Requirements

+

+add uses the following system calls: +

+

+ +

+add should work properly once the basic system calls are complete. +

+ + + diff --git a/man/testbin/argtest.html b/man/testbin/argtest.html new file mode 100644 index 0000000..71b2572 --- /dev/null +++ b/man/testbin/argtest.html @@ -0,0 +1,68 @@ + + + +argtest + + + +

argtest

+

OS/161 Reference Manual

+ +

Name

+

+argtest - display arguments passed through execv +

+ +

Synopsis

+

+/testbin/argtest args +

+ +

Description

+

+argtest prints its arguments. This is likely to be helpful +for testing execv during the basic system calls assignment. +

+ +

Requirements

+

+argtest uses the following system calls: +

+

+ +

+Argument passing should work once the basic system calls are complete. +

+ + + diff --git a/man/testbin/badcall.html b/man/testbin/badcall.html new file mode 100644 index 0000000..1d43dd3 --- /dev/null +++ b/man/testbin/badcall.html @@ -0,0 +1,101 @@ + + + +badcall + + + +

badcall

+

OS/161 Reference Manual

+ +

Name

+

+badcall - make invalid system calls +

+ +

Synopsis

+

+/testbin/badcall [test...] +

+ +

Description

+

+badcall contains a variety of tests for system call error +conditions and error handling. The tests are grouped by system call; +all available tests for a particular system call are run when that +system call is selected. +

+ +

+None of the tests should crash the system. If you kill processes when +system calls fail with EFAULT (a valid thing to do) badcall +itself may get killed. Otherwise, badcall should not get +killed either. +

+ +

+Tests may be selected on the command line; if so, all the tests +selected on the command line will be run in order. If nothing is +selected on the command line, a menu is printed and tests are prompted +for. +

+ +

+The tests for the individual syscalls are specified with the letters +`a' through `y'. A single-digit number may also be specified; this +tests all the system calls that are supposed to work once the +corresponding assignment is completed. `*' may be used to test +everything. Use `!' to quit. +

+ +

Requirements

+

+badcall can test every system call. It requires +read and +write itself to work properly, and +some of the tests may use syscalls other than the ones being tested. +

+ +

+At the completion of each assignment, the system should pass the tests +for the syscalls associated with that (and previous) assignments. At +no time should anything badcall does crash the system. +

+ +

+Ideally, your course staff will have updated the copy of +badcall you received with OS/161 to reflect the system calls +required in each of the assignments in your course. In practice, this +will probably not be the case. It is likely a better idea to test each +system call explicitly than rely on the per-assignment lists. +

+ + + diff --git a/man/testbin/bigexec.html b/man/testbin/bigexec.html new file mode 100644 index 0000000..79da6ab --- /dev/null +++ b/man/testbin/bigexec.html @@ -0,0 +1,80 @@ + + + +bigexec + + + +

bigexec

+

OS/161 Reference Manual

+ +

Name

+

+bigexec - test exec with large argv blocks +

+ +

Synopsis

+

+/testbin/bigexec +

+ +

Description

+

+bigexec tests a number of different possible ways to call +execv with large or largish argv +blocks. +

+ +

+Note that bigexec works by execing itself with various +arguments. +To start the test, run it without arguments. +Passing it other arguments will likely confuse it. +

+ +

Requirements

+

+bigexec uses the following system calls: +

+

+ +

+bigexec should work once you have implemented the basic +system calls, including of course execv. +(But it depends on little other than execv, making it useful in the +early stages.) +

+ + + diff --git a/man/testbin/bigfile.html b/man/testbin/bigfile.html new file mode 100644 index 0000000..939378e --- /dev/null +++ b/man/testbin/bigfile.html @@ -0,0 +1,79 @@ + + + +bigfile + + + +

bigfile

+

OS/161 Reference Manual

+ +

Name

+

+bigfile - create a large file in small chunks +

+ +

Synopsis

+

+/testbin/bigfile filename size
+/testbin/bigfile filename + size/chunksize
+

+ +

Description

+

+bigfile creates a file of the specified size in chunks of the +specified chunk size. +The default chunk size is 10, which is excessively small. +The largest chunk size supported is 8192. +The file size is rounded up to an integral number of chunks. +Very small chunk sizes are not fully honored. +

+ +

Requirements

+

+bigfile uses the following system calls: +

+

+ +

+bigfile should run on emufs once the basic system calls are +complete, and should run on SFS once the file system assignment is +complete. Sufficiently small files should work on SFS even before +that point. +

+ + + diff --git a/man/testbin/bigfork.html b/man/testbin/bigfork.html new file mode 100644 index 0000000..7154edb --- /dev/null +++ b/man/testbin/bigfork.html @@ -0,0 +1,88 @@ + + + +bigfork + + + +

bigfork

+

OS/161 Reference Manual

+ +

Name

+

+bigfork - large forking test +

+ +

Synopsis

+

+/testbin/bigfork +

+ +

Description

+

+bigfork is a combination of +the forktest +and parallelvm tests. +It forks geometrically like forktest, but more times (it goes six +deep instead of four) and in between each it does some aimless matrix +operations similar to those in parallelvm. +It was written to try to come up with a test that generates lots of +processes (like parallelvm) but works better as a benchmark than +parallelvm does. +It is only modestly successful; multiple runs of bigfork still +typically give a moderately high variance; but as multiple runs of +parallelvm typically exhibit a huge variance it's a step forward. +

+ +

+It uses about 4M of memory, which is bigger than parallelvm but +comparable to some of the other VM stress tests. +When run in-core it also offers a limited ability to test the +multiprocessor scalability of your VM system. +

+ +

Requirements

+

+bigfork uses the following system calls: +

+

+ +

+bigfork should run correctly to completion once the VM +assignment is complete. +

+ + + diff --git a/man/testbin/bigseek.html b/man/testbin/bigseek.html new file mode 100644 index 0000000..c275627 --- /dev/null +++ b/man/testbin/bigseek.html @@ -0,0 +1,80 @@ + + + +bigseek + + + +

bigseek

+

OS/161 Reference Manual

+ +

Name

+

+bigseek - test 64-bit seek positions +

+ +

Synopsis

+

+/testbin/bigseek +

+ +

Description

+

+bigseek tests manipulation of seek pointers past +231. +It is somewhat limited in what it can do, because neither SFS nor +emufs supports files larger than 232 bytes; but it can +still seek around and check that the resulting seek position is +reported correctly. +

+ +

Requirements

+

+bigseek uses the following system calls: +

+

+ +

+bigseek should work once you have implemented the basic +system calls. +Until you implement remove, it will not be able to delete its test +file; this is merely untidy, not a problem. +

+ + + diff --git a/man/testbin/bloat.html b/man/testbin/bloat.html new file mode 100644 index 0000000..97bfed6 --- /dev/null +++ b/man/testbin/bloat.html @@ -0,0 +1,108 @@ + + + +bloat + + + +

bloat

+

OS/161 Reference Manual

+ +

Name

+

+bloat - waste memory +

+ +

Synopsis

+

+/testbin/bloat +[-a allocs] +[-b bias] +[-p touchpages] +

+ +

Description

+

+bloat allocates all available memory one page at a time until +it runs out. +Unlike other tests that do this, it has been gimmicked up so that it +runs in a fairly reasonable amount of time even when swapping. +

+ +

+It runs in cycles; every cycle it allocates allocs pages, one +at a time, by calling sbrk (not +malloc), then touches touchpages +pages. +It chooses the pages it touches as follows: +

+
    +
  • +1 in 1000 pages are chosen uniformly from the entire allocated space. +

  • +
  • +The rest are taken from the middle 1% of the space; note that this +range shifts upwards as more pages are allocated. +

  • +
  • +It rolls bias dice to pick pages from the middle 1%. +The more dice, the tighter the distribution it picks and the +faster it runs. +

  • +
+

+The default settings are 4 allocs, 8 touchpages +and a bias of 8. +This gives reasonable performance with reasonable amounts of memory on +the solution set. +There are enough things affecting the speed that you may want to +experiment with the settings when testing on your own VM system. +

+ +

Requirements

+

+bloat uses the following system calls: +

+

+ +

+bloat should work once you have implemented your VM system +and added the sbrk system call. +It may not run fast by default, but it should always be faster than +sbrktest 10 or the notoriously glacial +malloctest 3. +

+ + + diff --git a/man/testbin/conman.html b/man/testbin/conman.html new file mode 100644 index 0000000..a0e1698 --- /dev/null +++ b/man/testbin/conman.html @@ -0,0 +1,68 @@ + + + +conman + + + +

conman

+

OS/161 Reference Manual

+ +

Name

+

+conman - echo typed characters +

+ +

Synopsis

+

+/testbin/conman +

+ +

Description

+

+conman echos characters typed on standard input until `q' is pressed. +

+ +

Requirements

+

+conman uses the following system calls: +

+

+ +

+conman should work once the basic system call assignment is complete. +

+ + + diff --git a/man/testbin/crash.html b/man/testbin/crash.html new file mode 100644 index 0000000..59e2fa9 --- /dev/null +++ b/man/testbin/crash.html @@ -0,0 +1,90 @@ + + + +crash + + + +

crash

+

OS/161 Reference Manual

+ +

Name

+

+crash - commit various exceptions +

+ +

Synopsis

+

+/testbin/crash [operation] +

+ +

Description

+

+crash will perform any one of fourteen illegal processor +operations, any one of which should get it killed without causing the +whole system to crash. +

+ +

+The operations are coded a through n and may be +chosen on the command line. If no operation is chosen, a menu is +displayed and a choice solicited. +

+ +

Restrictions

+

+Test f, which writes into the process's own code segment, +will only cause a processor exception if you implement read-only code +segments. Since this is not required, it is not required that test +f pass. +

+ +

+However, using test f must not under any circumstances +corrupt the code in the copy of crash on disk! +

+ +

Requirements

+

+crash uses the following system calls: +

+

+ +

+crash should operate properly once the basic system call +assignment is complete. +

+ + + diff --git a/man/testbin/ctest.html b/man/testbin/ctest.html new file mode 100644 index 0000000..59adbc3 --- /dev/null +++ b/man/testbin/ctest.html @@ -0,0 +1,80 @@ + + + +ctest + + + +

ctest

+

OS/161 Reference Manual

+ +

Name

+

+ctest - cyclic stride-oriented VM test +

+ +

Synopsis

+

+/testbin/ctest [stride] +

+ +

Description

+

+ctest creates a 1-megabyte array of pointers and sets it up +as a circular linked list, then traverses the linked list. The linked +list is set up so each entry points to the one stride entries +away. +

+ +

+The stride argument should be odd, so all elements in the +list are accessed. +

+ +

+The default stride is 477. +

+ +

Requirements

+

+ctest uses the following system calls: +

+

+ +

+ctest should function properly once the VM assignment is +complete. +

+ + + diff --git a/man/testbin/dirconc.html b/man/testbin/dirconc.html new file mode 100644 index 0000000..01225de --- /dev/null +++ b/man/testbin/dirconc.html @@ -0,0 +1,90 @@ + + + +dirconc + + + +

dirconc

+

OS/161 Reference Manual

+ +

Name

+

+dirconc - concurrent file system test +

+ +

Synopsis

+

+/testbin/dirconc path [randomseed] +

+ +

Description

+

+dirconc does random directory operations from many processes +concurrently. This is a fairly difficult stress test as it exercises +cross-directory rename. Quite a number of real-world systems have +failed to handle it or larger/longer builds of it. +

+ +

+It does its work in a subdirectory of path, so you can run it +against whatever filesystem you prefer. +

+ +

+If your system survives a dirconc run, be sure to check the +integrity of the filesystem as well. It's not uncommon for +dirconc to provoke filesystem corruption. +

+ +

Requirements

+

+dirconc uses the following system calls: +

+

+ +

+dirconc should work properly on SFS once the file system +assignment is complete. It won't do much of interest on emufs, +however. +

+ + + diff --git a/man/testbin/dirseek.html b/man/testbin/dirseek.html new file mode 100644 index 0000000..fc163dc --- /dev/null +++ b/man/testbin/dirseek.html @@ -0,0 +1,79 @@ + + + +dirseek + + + +

dirseek

+

OS/161 Reference Manual

+ +

Name

+

+dirseek - seek on directories test +

+ +

Synopsis

+

+/testbin/dirseek +

+ +

Description

+

+dirseek creates a test directory, creates some files in it, +and lists the directory repeatedly, seeking in a variety of ways (some +legal, some not). +

+ +

Requirements

+

+dirseek uses the following system calls: +

+

+ +

+dirseek should run (on SFS filesystems) when the file system +assignment is complete. It will not run on emufs, because emufs does +not support mkdir or rmdir. +

+ + + diff --git a/man/testbin/dirtest.html b/man/testbin/dirtest.html new file mode 100644 index 0000000..3f8a83d --- /dev/null +++ b/man/testbin/dirtest.html @@ -0,0 +1,71 @@ + + + +dirtest + + + +

dirtest

+

OS/161 Reference Manual

+ +

Name

+

+dirtest - simple subdirectories test +

+ +

Synopsis

+

+/testbin/dirtest +

+ +

Description

+

+dirtest creates and then removes a series of nested directories. +

+ +

Requirements

+

+dirtest uses the following system calls: +

+

+ +

+dirtest should run (on SFS filesystems) when the file system +assignment is complete. It will not run on emufs, because emufs does +not support rmdir. +

+ + + diff --git a/man/testbin/f_test.html b/man/testbin/f_test.html new file mode 100644 index 0000000..ff6ef2d --- /dev/null +++ b/man/testbin/f_test.html @@ -0,0 +1,92 @@ + + + +f_test + + + +

f_test

+

OS/161 Reference Manual

+ +

Name

+

+f_test - basic concurrent filesystem test +

+ +

Synopsis

+

+/testbin/f_test [1|2|3] +

+ +

Description

+

+f_test consists of three tests, 1-3, that can be specified on +the command line. If nothing is specified, all three tests are run. +

+ +

+Test 1 writes a large file (a bit over 270k) and reads it back. +

+ +

+Test 2 creates and removes a directory tree, rather like +dirtest. +

+ +

+Test 3 spawns three subprocesses that simultaneously read and write +the same file. +

+ +

Requirements

+

+f_test uses the following system calls: +

+

+ +

+f_test should run correctly once the file system assignment +is complete. +

+ + + diff --git a/man/testbin/factorial.html b/man/testbin/factorial.html new file mode 100644 index 0000000..74ed96a --- /dev/null +++ b/man/testbin/factorial.html @@ -0,0 +1,89 @@ + + + +factorial + + + +

factorial

+

OS/161 Reference Manual

+ +

Name

+

+factorial - compute factorials using execv +

+ +

Synopsis

+

+/testbin/factorial N +

+ +

Description

+

+factorial computes N!, for integer values +N. +It does the computation (in bignums) by recursively calling +execv on itself and is thus useful +for stressing your exec implementation. +

+ +

+Note that factorial does not make exec calls with +large argv blocks; getting to numbers large enough that the +size is interesting requires prohibitively many iterations and is +exceedingly slow. +

+ +

Requirements

+

+factorial uses the following system calls: +

+

+ +

+factorial should work once you have implemented the basic +system calls, including of course execv. +(But it depends on little other than execv, making it useful in the +early stages.) +

+ +

Restrictions

+

+Be aware that until you do the VM assignment and replace dumbvm, +running a lot of execs will run the system out of memory very +rapidly. +

+ + + diff --git a/man/testbin/farm.html b/man/testbin/farm.html new file mode 100644 index 0000000..3bcd7a0 --- /dev/null +++ b/man/testbin/farm.html @@ -0,0 +1,90 @@ + + + +farm + + + +

farm

+

OS/161 Reference Manual

+ +

Name

+

+farm - run some hogs and cats +

+ +

Synopsis

+

+/testbin/farm +

+ +

Description

+

+farm runs three copies of hog and one +copy of /bin/cat. +

+ +

+The cat process reads and prints the file catfile, +which you should create in advance. +

+ +

Requirements

+

+farm uses the following system calls: +

+

+ +

+The cat subprocess spawned by farm uses these +additional system calls: +

+

+ +

+farm is only likely to be useful for testing the scheduler. +

+ +

Bugs

+

+farm does not wait for its child processes to finish. +

+ + + diff --git a/man/testbin/faulter.html b/man/testbin/faulter.html new file mode 100644 index 0000000..5832429 --- /dev/null +++ b/man/testbin/faulter.html @@ -0,0 +1,70 @@ + + + +faulter + + + +

faulter

+

OS/161 Reference Manual

+ +

Name

+

+faulter - commit address fault +

+ +

Synopsis

+

+/testbin/faulter +

+ +

Description

+

+faulter accesses an invalid memory address, thus crashing. It +should be killed and not crash the entire system. +

+ +

Requirements

+

+faulter uses the following system calls: +

+

+ +

+faulter should work properly, that is, get killed with an +address fault, once the basic system calls assignment is complete. It +should continue to work once the VM system is done. +

+ + + diff --git a/man/testbin/filetest.html b/man/testbin/filetest.html new file mode 100644 index 0000000..a320486 --- /dev/null +++ b/man/testbin/filetest.html @@ -0,0 +1,79 @@ + + + +filetest + + + +

filetest

+

OS/161 Reference Manual

+ +

Name

+

+filetest - basic filesystem test +

+ +

Synopsis

+

+/testbin/filetest filename +

+ +

Description

+

+filetest tests the filesystem by opening, writing to, and +reading from a user-specified file. +

+ +

Requirements

+

+filetest uses the following system calls: +

+

+ +

+filetest should run correctly on SFS filesystems with the +OS/161 system as shipped. It should continue to work once the file +system assignment is complete. +

+ +

+It will not work in full on emufs, because emufs does not support +remove(). +

+ + + diff --git a/man/testbin/forkbomb.html b/man/testbin/forkbomb.html new file mode 100644 index 0000000..47a1835 --- /dev/null +++ b/man/testbin/forkbomb.html @@ -0,0 +1,96 @@ + + + +forkbomb + + + +

forkbomb

+

OS/161 Reference Manual

+ +

Name

+

+forkbomb - create hundreds of processes +

+ +

Synopsis

+

+/testbin/forkbomb +

+ +

Description

+

+forkbomb does +

+   while (1) fork();
+
+doing a bit of additional checking similar to that done by +forktest. +

+ +

+ +DO NOT RUN THIS ON A REAL SYSTEM - IT WILL GRIND TO A HALT AND +PEOPLE WILL COME AFTER YOU WIELDING BASEBALL BATS AND/OR THE AD +BOARD*. WE WARNED YOU. + +

+ +

+* The Administrative Board of Harvard +College handles formal disciplinary action. +

+ +

Requirements

+

+forkbomb uses the following system calls: +

+

+ +

+We don't expect your system to withstand this without grinding to +a halt, but once your basic system calls are complete it shouldn't +crash. Likewise for after your virtual memory system is complete. +

+ +

+Note that this may turn out to be hard to achieve in practice. Don't +spend much time fixing problems forkbomb triggers that won't +arise under more normal operation. (If in doubt, consult your course +staff.) +

+ + + diff --git a/man/testbin/forktest.html b/man/testbin/forktest.html new file mode 100644 index 0000000..be0d710 --- /dev/null +++ b/man/testbin/forktest.html @@ -0,0 +1,72 @@ + + + +forktest + + + +

forktest

+

OS/161 Reference Manual

+ +

Name

+

+forktest - test fork system call +

+ +

Synopsis

+

+/testbin/forktest +

+ +

Description

+

+forktest forks a few times and tries to make sure each fork +has its own data and stack. +

+ +

Requirements

+

+forktest uses the following system calls: +

+

+ +

+forktest should run successfully once the basic system calls +are complete (if given enough memory) and should continue to run +successfully when the VM assignment is completed. +

+ + + diff --git a/man/testbin/frack.html b/man/testbin/frack.html new file mode 100644 index 0000000..05dd740 --- /dev/null +++ b/man/testbin/frack.html @@ -0,0 +1,160 @@ + + + +frack + + + +

frack

+

OS/161 Reference Manual

+ +

Name

+

+frack - file system crack +

+ +

Synopsis

+

+/testbin/frack list
+/testbin/frack do workload [arg]
+/testbin/frack check workload [arg]
+

+ +

Description

+

+frack is a general-purpose file system checker. +It has a number of workloads built into it (currently 58, some of +which are families of related workloads), each of which can be run in +either do mode or check mode. +

+ +

+In do mode, frack executes the chosen workload +against the file system. +

+ +

+In check mode, frack executes the chosen workload +against an internal model of a file system, and builds a +representation of all the successive states the file system reaches. +Then it inspects the file system it is run on and matches its state +against this representation. +It finds the closest matching state, and then prints out the +discrepancies it finds between that state and what it sees. +

+ +

+Note that the check mode expects that the do mode +was run on an empty (newly formatted) file system volume. +Otherwise, any other stuff on the volume will appear as a discrepancy +and may cause the state matching algorithm to fail. +

+ +

+The intended use is for testing file system recovery: run a workload +in do mode, crash during the workload (e.g. using the +System/161 doom counter), run file system recovery, then run the same +workload in check mode. +Ideally, the check mode run will find the resulting on-disk +state after recovery to exactly match some valid state the workload +reached. +In practice, some forms of discrepancy are often considered +acceptable; your course staff should give you guidance on what you are +and are not required to handle. +

+ +

+Note that you probably want to get your recovery code to the point +where it reliably produces a valid, self-consistent volume that +sfsck accepts before worrying about +whether the frack check phase passes. +

+ +

+frack can also be used for testing the general correctness of +a file system, such as by running the do mode of a workload +to completion and then immediately (or after shutting down cleanly and +rebooting) running in check mode. +

+ +

+Use frack list to see the available workloads. +Some workloads take arguments; size arguments should be one +of the keywords small, medium, or large, +reflecting the size of the test file(s). +Seed arguments are integer random seeds from 0 to +231-1. +

+ +

+Some workloads contain an explicit sync; generally these are +meant to be crashed after, not before (or during) the sync call. +

+ +

Requirements

+

+frack uses the following system calls: +

+but note that it is intended to be able to exercise all the +file-system-related calls and its exact requirements are +workload-dependent. +

+ +

+frack is most useful for testing file system recovery, by +intentionally crashing during workload runs. +But it is also useful for checking general correctness of a file +system. +

+ +

Bugs

+

+Currently, none of the specific workloads are documented. +

+ + + diff --git a/man/testbin/guzzle.html b/man/testbin/guzzle.html new file mode 100644 index 0000000..7233855 --- /dev/null +++ b/man/testbin/guzzle.html @@ -0,0 +1,70 @@ + + + +guzzle + + + +

guzzle

+

OS/161 Reference Manual

+ +

Name

+

+guzzle - waste cpu +

+ +

Synopsis

+

+/testbin/guzzle [character] +

+ +

Description

+

+guzzle burns cpu and periodically prints a character. The +default character is a plus sign (+). It differs from +hog chiefly in the printing and in that it runs +longer. +

+ +

Requirements

+

+guzzle uses the following system calls: +

+

+ +

+It is only likely to be useful for testing the scheduler. +

+ + + diff --git a/man/testbin/hash.html b/man/testbin/hash.html new file mode 100644 index 0000000..1747a9a --- /dev/null +++ b/man/testbin/hash.html @@ -0,0 +1,84 @@ + + + +hash + + + +

hash

+

OS/161 Reference Manual

+ +

Name

+

+hash - compute a simple hash function of a file +

+ +

Synopsis

+

+/testbin/hash file
+host-hash file +

+ +

Description

+

+hash takes a file and computes a hash value for it by adding +all the bytes in the file together modulo a prime. +

+ +

+hash is by default also compiled for the System/161 host OS +so you can cross-check the answers you get. +

+ +

Requirements

+

+hash uses the following system calls: +

+

+ +

+Once the basic system calls are complete, hash should work on any file +the system supports. However, it will probably of most use for testing +while working on the file system. +

+ +

Bugs

+

+hash uses a silly hash algorithm. +

+ + + diff --git a/man/testbin/hog.html b/man/testbin/hog.html new file mode 100644 index 0000000..c933dec --- /dev/null +++ b/man/testbin/hog.html @@ -0,0 +1,65 @@ + + + +hog + + + +

hog

+

OS/161 Reference Manual

+ +

Name

+

+hog - waste cpu +

+ +

Synopsis

+

+/testbin/hog +

+ +

Description

+

+hog does nothing but burn cpu. It is not substantially different from +guzzle. +

+ +

Requirements

+

+hog uses only the _exit +system call. +

+ +

+It is only likely to be useful for testing the scheduler. +

+ + + diff --git a/man/testbin/huge.html b/man/testbin/huge.html new file mode 100644 index 0000000..61cef9f --- /dev/null +++ b/man/testbin/huge.html @@ -0,0 +1,72 @@ + + + +huge + + + +

huge

+

OS/161 Reference Manual

+ +

Name

+

+huge - very large VM test +

+ +

Synopsis

+

+/testbin/huge +

+ +

Description

+

+huge creates an 8 megabyte data array and manipulates it. It +will hopefully help show up bugs in the VM system. +

+ +

+It does not in fact do anything useful even if it completes successfully. +

+ +

Requirements

+

+huge uses the following system calls: +

+

+ +

+huge should run properly once the VM assignment is complete. +

+ + + diff --git a/man/testbin/index.html b/man/testbin/index.html new file mode 100644 index 0000000..b0d1d9e --- /dev/null +++ b/man/testbin/index.html @@ -0,0 +1,110 @@ + + + +OS/161 Test binaries + + + + +

OS/161 Test binaries (/testbin)

+ +

+Top | +Binaries | +Sysadmin binaries | +System calls | +C standard library | +Device drivers | +Miscellaneous +

+
+ +
    +
  • add - add two numbers +
  • argtest - display arguments passed through execv +
  • badcall - make invalid system calls +
  • bigexec - test exec with large argv blocks +
  • bigfile - create a large file in small chunks +
  • bigfork - large forking test +
  • bigseek - test 64-bit seek positions +
  • bloat - waste memory +
  • conman - echo typed characters +
  • crash - commit various exceptions +
  • ctest - cyclic stride-oriented VM test +
  • dirconc - concurrent directory operations test +
  • dirseek - seek on directories test +
  • dirtest - simple subdirectories test +
  • f_test - basic concurrent filesystem test +
  • factorial - compute factorials using execv +
  • farm - run some hogs and cats +
  • faulter - commit address fault +
  • filetest - basic filesystem test +
  • forkbomb - create hundreds of processes +
  • forktest - test fork system call +
  • frack - file system crack +
  • guzzle - waste cpu +
  • hash - compute a simple hash function of a file +
  • hog - waste cpu +
  • huge - very large VM test +
  • kitchen - run some sinks +
  • malloctest - some simple tests for + userlevel malloc +
  • matmult - baseline VM stress test +
  • multiexec - run many exec calls at once +
  • palin - simple VM test +
  • parallelvm - concurrent VM test +
  • poisondisk - write known "poison" + values to a disk image +
  • psort - concurrent file system test +
  • quinthuge - very very large VM test +
  • quintmat - very large VM test +
  • quintsort - very large VM test +
  • randcall - make randomized system calls +
  • redirect - test I/O redirection +
  • rmdirtest - test removing in-use directories +
  • rmtest - test removing open files +
  • sbrktest - program for testing sbrk +
  • schedpong - scheduler pong +
  • sink - accept and throw away console input +
  • sort - large quicksort-based VM test +
  • sparsefile - generate a sparse file +
  • sty - run some hogs +
  • tail - print part of a file +
  • tictac - tic-tac-toe game +
  • triplehuge - very very large VM test +
  • triplemat - very large VM test +
  • triplesort - very large VM test +
  • usemtest - test for user-level (semfs) semaphores +
  • userthreads - simple user-level threads test +
  • zero - test if VM system zeros memory +
+ + + diff --git a/man/testbin/kitchen.html b/man/testbin/kitchen.html new file mode 100644 index 0000000..f3ebbc1 --- /dev/null +++ b/man/testbin/kitchen.html @@ -0,0 +1,80 @@ + + + +kitchen + + + +

kitchen

+

OS/161 Reference Manual

+ +

Name

+

+kitchen - run some sinks +

+ +

Synopsis

+

+/testbin/kitchen +

+ +

Description

+

+Runs four copies of sink. It may be useful for +testing concurrent access to the console device. It may also be useful +for testing job control, if you choose to pursue job control. +

+ +

Requirements

+

+kitchen uses the following system calls: +

+ +Additionally, the subprocesses it spawns use the +read system call. +

+ +

+kitchen should function correctly once the basic system calls are +complete. +

+ +

Bugs

+

+kitchen does not wait for its child processes to exit. +

+ + + diff --git a/man/testbin/malloctest.html b/man/testbin/malloctest.html new file mode 100644 index 0000000..582c15f --- /dev/null +++ b/man/testbin/malloctest.html @@ -0,0 +1,116 @@ + + + +malloctest + + + +

malloctest

+

OS/161 Reference Manual

+ +

Name

+

+malloctest - some simple tests for userlevel malloc +

+ +

Synopsis

+

+/testbin/malloctest [test...] +

+ +

Description

+

+malloctest contains 7 tests, 1-7. These may be run +interactively or from the command line. +

+ +

+Test 1 checks if all the bytes we ask for actually get allocated. +

+ +

+Test 2 checks if malloc gracefully handles failing requests. +This test assumes that malloc will eventually fail if one +keeps allocating enough memory, instead of promising memory it can't +deliver and then (perhaps) killing processes when it runs out. More +detail regarding this condition can be found in comments in the source +code. +

+ +

+Test 3 also checks if malloc gracefully handles failing +requests, and thus has the same restrictions as test 2. +

+ +

+Test 4 attempts to check if malloc coalesces the free list +properly. This test is only meant for first-fit, next-fit, or +best-fit allocators; anything else will most likely confuse it. +Running test 4 after other tests may confuse it as well. +

+ +

+Tests 5-7 are a randomized stress test. Test 5 uses pseudorandom seed +0. Test 6 seeds the random generator from the +random: device. Test 7 prompts you for a +specific seed. +

+ +

Requirements

+

+malloctest uses the following system calls: +

+

+ +

+Your system should pass all the malloctest tests, subject to +the conditions described above, once you have implemented +sbrk. +

+ +

Bugs

+

+Because OS/161 ships with a userlevel malloc implementation +now, rather than making you write one, this test is not very useful. +

+ +

+Because the userlevel malloc OS/161 ships with is quite dumb, +test 3 can be amazingly slow. +

+ + + diff --git a/man/testbin/matmult.html b/man/testbin/matmult.html new file mode 100644 index 0000000..5483085 --- /dev/null +++ b/man/testbin/matmult.html @@ -0,0 +1,76 @@ + + + +matmult + + + +

matmult

+

OS/161 Reference Manual

+ +

Name

+

+matmult - baseline VM stress test +

+ +

Synopsis

+

+/testbin/matmult +

+ +

Description

+

+matmult multiplies two large matrices together and checks the +result. Hopefully this will help detect bugs in the VM system. +

+ +

+The version for OS/161 has been gimmicked to be less efficient +space-wise than normal matrix multiplication. This allows it to both +take up an interesting amount of memory and run in a non-boring amount +of time. +

+ +

Requirements

+

+matmult uses the following system calls: +

+

+ +

+matmult should run correctly once the VM system assignment is +complete. +

+ + + diff --git a/man/testbin/multiexec.html b/man/testbin/multiexec.html new file mode 100644 index 0000000..fcb46fa --- /dev/null +++ b/man/testbin/multiexec.html @@ -0,0 +1,116 @@ + + + +multiexec + + + +

multiexec

+

OS/161 Reference Manual

+ +

Name

+

+multiexec - run many exec calls at once +

+ +

Synopsis

+

+/testbin/multiexec [-j nprocs] + [prog [arg ...]] +

+ +

Description

+

+multiexec forks several subprocesses and then uses user-level +semaphores to cause them to all enter +execv at as close as possible to the +same time. +This is useful for seeing what happens if having too many argv buffers +in use at once causes the kernel to run into problems, or to test the +efficacy of measures to mitigate those problems. +

+ +

+The default number of subprocesses is 12. +The default program each subprocess runs is pwd. +Other larger programs can be run by giving the program name and +arguments on multiexec's command line. +

+ +

Requirements

+

+multiexec uses the following system calls: +

+

+ +

+multiexec should work once you have implemented the basic +system calls. +Exactly what the requirements are for handling large multiexec +invocations is up to your course staff, although probably at a minimum +your kernel shouldn't crash. +

+ +

+Until you implement remove, which is typically not part of the basic +system calls assignment, multiexec will not be able to clean +up after itself. +This is untidy but not a problem. +

+ +

Bugs

+

+multiexec has a compiled-in limit of 64 words in the argv +array to be passed to its subprocesses. +Also, there should be an easy way to pass a very large argv. +In the meantime, perhaps try having multiexec run +bigexec. +

+ +

Restrictions

+

+Be aware that until you do the VM assignment and replace dumbvm, +running a lot of execs will run the system out of memory very +rapidly. +

+ + + diff --git a/man/testbin/palin.html b/man/testbin/palin.html new file mode 100644 index 0000000..0dcfebc --- /dev/null +++ b/man/testbin/palin.html @@ -0,0 +1,76 @@ + + + +palin + + + +

palin

+

OS/161 Reference Manual

+ +

Name

+

+palin - simple VM test +

+ +

Synopsis

+

+/testbin/palin +

+ +

Description

+

+palin checks a long string contained within itself for being +palindromic. The check should pass. +

+ +

+The string is not actually all that long and this test does not stress +the VM in any real sense of the word. However, it might be a useful +test early on in the debugging phase. +

+ +

Requirements

+

+palin uses the following system calls: +

+

+ +

+palin should run correctly once the basic system calls are +complete, and should continue to run correctly once the VM system +assignment is complete. +

+ + + diff --git a/man/testbin/parallelvm.html b/man/testbin/parallelvm.html new file mode 100644 index 0000000..c592b9e --- /dev/null +++ b/man/testbin/parallelvm.html @@ -0,0 +1,115 @@ + + + +parallelvm + + + +

parallelvm

+

OS/161 Reference Manual

+ +

Name

+

+parallelvm - concurrent VM system test +

+ +

Synopsis

+

+/testbin/parallelvm [-w] +

+ +

Description

+

+parallelvm runs a fairly large number (24) of fairly small +processes in parallel to stress your VM system. The processes perform +aimless matrix operations. +

+ +

+Before attempting parallevm make sure the zero test +passes; parallelvm will fail with wrong answers if its BSS +doesn't start out zeroed. Also, it may be helpful to get it running +successfully purely in RAM before cutting back the memory size so it +swaps. +

+ +

+If your VM system's fork is particularly slow, you will probably find +that the early processes exit before the later ones finish forking. +This reduces the total memory load and can easily cause +parallelvm to run completely in RAM without needing to swap; +this in turn makes it a much less effective stress test. +

+ +

+For this reason, the -w option can be used to make all the +subprocesses sync up before starting to compute. +They use user-level semaphores for coordination. +

+ +

+If benchmarking, always use -w. +

+ +

Requirements

+

+parallelvm uses the following system calls: +

+

+ +

+Adding the -w option also uses: +

+

+ +

+parallelvm should run properly once your VM system is complete. +

+ +

+Until the remove system call has been implemented, which is +typically not part of the basic system calls assignment, +parallelvm -w will be unable to clean up its semaphores. +This is merely untidy and not a real problem. +

+ + + diff --git a/man/testbin/poisondisk.html b/man/testbin/poisondisk.html new file mode 100644 index 0000000..0c22e75 --- /dev/null +++ b/man/testbin/poisondisk.html @@ -0,0 +1,98 @@ + + + +poisondisk + + + +

poisondisk

+

OS/161 Reference Manual

+ +

Name

+

+poisondisk - write known "poison" values to a disk image +

+ +

Synopsis

+

+/testbin/poisondisk disk-device
+hostbin/host-poisondisk disk-image +

+ +

Description

+

+poisondisk writes known poison values to a disk image. +This allows (mostly) reliable detection of reads from uninitialized +disk blocks: they produce the poison value. +(Otherwise, uninitialized disk blocks tend to be zeroed; this is much +harder to detect and much harder to distinguish from an intentional +condition.) +

+ +

+poisondisk will overwrite any data already on the disk, so +run it prior to running mksfs when +creating a new volume. +

+ +

+A host version of poisondisk is build (like with the SFS tools) so it +can be run outside OS/161. +This version understands System/161 disk image headers and will only +overwrite System/161 disk images. +

+ +

+The poison value is 0xa9. +

+ +

Requirements

+

+poisondisk uses the following system calls: +

+

+ +

+poisondisk will work once you have implemented the system +calls it uses (including fstat, which is typically not part of the +basic system calls assignment), but is only really useful for working +on the file system. +

+ + + diff --git a/man/testbin/psort.html b/man/testbin/psort.html new file mode 100644 index 0000000..ee5d306 --- /dev/null +++ b/man/testbin/psort.html @@ -0,0 +1,127 @@ + + + +psort + + + +

psort

+

OS/161 Reference Manual

+ +

Name

+

+psort - concurrent file system test +

+ +

Synopsis

+

+/testbin/psort [-p numprocs] +[-k numkeys] [-r | -s randomseed] +

+ +

Description

+

+psort does an on-disk parallelizing sort of a large number of +randomly generated integers. +It is loosely based on some real parallel sort benchmarks. +

+ +

+Be aware of its size vs. the size of your buffer cache, and adjust its +size as needed. Running it so it fits entirely in cache and running it +so it overflows the cache are both valid stress tests, but have quite +different characteristics. +

+ +

Options

+
    +
  • -k Set the number of integers. Default is 131072. +
  • -p Set the number of processes. Default is 4. +
  • -r Get a random seed from the random: device. +
  • -s randomseed Choose an explicit random seed. +
+

+The memory footprint depends on the number of processes and the +per-process work buffer size (which can be changed at compile time); +the file system footprint depends on the number of integers. +Specifically, the memory footprint is the number of processes (default +4) times the buffer size (default 384K), and the file size is the +number of integers (default 131,072) multiplied by the size of an +integer (here 4) multiplied by the maximum number of copies of the +data that appear at once, which is 3, so 1.5 MB. +

+ +

+Note that the parent psort process does not serve as one of the worker +processes; it also has a work buffer, but doesn't use it. +Also note that it forks several (six) sets of subprocesses in the +course of execution. +A virtual memory system that doesn't support the zerofilled page +optimization will both use 1/n more memory for the extra work buffer +and also incur a fairly large cost copying it in every fork. +Also, because of the large number of forks the amount of RAM required +to run psort using dumbvm is likely prohibitive. +

+ +

Requirements

+

+psort uses the following system calls: +

+It also execs cat. +

+ +

+psort should be able to run properly on SFS filesystems once +the basic system calls are implemented. However, you may need to +adjust its workload size depending on the level of large-file support +you have in SFS. +

+ +

+psort will mostly run on emufs, but there isn't really much +point in that. +

+ + + diff --git a/man/testbin/quinthuge.html b/man/testbin/quinthuge.html new file mode 100644 index 0000000..b641dac --- /dev/null +++ b/man/testbin/quinthuge.html @@ -0,0 +1,70 @@ + + + +quinthuge + + + +

quinthuge

+

OS/161 Reference Manual

+ +

Name

+

+quinthuge - very very large VM test +

+ +

Synopsis

+

+/testbin/quinthuge +

+ +

Description

+

+quinthuge runs five copies of huge at once. +

+ +

Requirements

+

+quinthuge uses the following system calls: +

+

+ +

+quinthuge should run properly once the VM assignment is complete. +

+ + + diff --git a/man/testbin/quintmat.html b/man/testbin/quintmat.html new file mode 100644 index 0000000..91f38fa --- /dev/null +++ b/man/testbin/quintmat.html @@ -0,0 +1,71 @@ + + + +quintmat + + + +

quintmat

+

OS/161 Reference Manual

+ +

Name

+

+quintmat - very large VM test +

+ +

Synopsis

+

+/testbin/quintmat +

+ +

Description

+

+quintmat runs five copies of +matmult at once. +

+ +

Requirements

+

+quintmat uses the following system calls: +

+

+ +

+quintmat should run properly once the VM assignment is complete. +

+ + + diff --git a/man/testbin/quintsort.html b/man/testbin/quintsort.html new file mode 100644 index 0000000..a83ba0b --- /dev/null +++ b/man/testbin/quintsort.html @@ -0,0 +1,70 @@ + + + +quintsort + + + +

quintsort

+

OS/161 Reference Manual

+ +

Name

+

+quintsort - very large VM test +

+ +

Synopsis

+

+/testbin/quintsort +

+ +

Description

+

+quintsort runs five copies of sort at once. +

+ +

Requirements

+

+quintsort uses the following system calls: +

+

+ +

+quintsort should run properly once the VM assignment is complete. +

+ + + diff --git a/man/testbin/randcall.html b/man/testbin/randcall.html new file mode 100644 index 0000000..d163320 --- /dev/null +++ b/man/testbin/randcall.html @@ -0,0 +1,102 @@ + + + +randcall + + + +

randcall

+

OS/161 Reference Manual

+ +

Name

+

+randcall - make randomized system calls +

+ +

Synopsis

+

+/testbin/randcall [-f] [-c count] +[-r seed] callset +

+ +

Description

+

+randcall makes randomized system calls, that is, system calls with +completely random arguments. The callset determines which +list of system calls it uses; it is either "all", which does +everything, or a number that identifies one of the assignments, in +which case it exercises all the system calls that are supposed to be +working when that assignment is complete. (If the lists compiled into +randcall are wrong, contact your course staff.) +

+ +

+Ordinarily, in case some of these calls cause process termination, +randcall forks before making each call. This can be slow, so the -f +option can be used to suppress this behavior. +

+ +

+The -c count option tells randcall to make +count iterations through the list of calls it's using. (It +always goes through the list sequentially.) The default count is 100. +

+ +

+The -r seed option allows one to set the +pseudorandom seed used by randcall to generate the call +arguments. The default seed is 0. +

+ +

+randcall prints what it's doing, so if it blows up you should +be able to see what happened. +

+ +

+The system calls that do not take arguments are not on any of the call +lists. Neither is reboot, to prevent +accidental system shutdown. +

+ +

Requirements

+

+randcall should never under any circumstances crash the +kernel, no matter what call list is in use. +

+ +

Bugs

+

+There should be an option to seed the random generator from +random:. +

+ + + diff --git a/man/testbin/redirect.html b/man/testbin/redirect.html new file mode 100644 index 0000000..db57527 --- /dev/null +++ b/man/testbin/redirect.html @@ -0,0 +1,95 @@ + + + +redirect + + + +

redirect

+

OS/161 Reference Manual

+ +

Name

+

+redirect - test I/O redirection +

+ +

Synopsis

+

+/testbin/redirect +

+ +

Description

+

+redirect does a simple test of I/O redirection like a Unix +shell might do. +It first creates an input test file, then invokes +cat to copy it, with standard input and +standard output suitably redirected. +Then it checks that the copy happened correctly, and removes the test +files. +

+ +

+The specifications of Unix system calls are such that this program +should take no extra work to support once basic tests show that the +pieces are working. +

+ +

Requirements

+

+redirect uses the following system calls: +

+

+ +

+redirect should work once you have implemented the basic +system calls, including fork, exec, and wait. +

+ +

+Note that until you implement remove (which is typically not part of +the basic system calls assignment), and in any case on emufs, the test +files will not get removed. +This is not important, just untidy. +

+ + + diff --git a/man/testbin/rmdirtest.html b/man/testbin/rmdirtest.html new file mode 100644 index 0000000..dfe8c8a --- /dev/null +++ b/man/testbin/rmdirtest.html @@ -0,0 +1,85 @@ + + + +rmdirtest + + + +

rmdirtest

+

OS/161 Reference Manual

+ +

Name

+

+rmdirtest - test removing in-use directories +

+ +

Synopsis

+

+/testbin/rmdirtest +

+ +

Description

+

+rmdirtest creates a test directory, goes into it, removes it, +and attempts to do various operations on it. It tries to check that +the right things happen, although some cases are beyond its ability to +test directly (such as whether storage is leaked). +

+ +

+Note that while it is not legal to remove the . +entry in a directory, it is perfectly legal to remove a +directory by name that happens to be some process's (or your own) +current working directory. +

+ +

Requirements

+

+rmdirtest uses the following system calls: +

+

+ +

+rmdirtest should run correctly once the file system +assignment is complete. +

+ + + diff --git a/man/testbin/rmtest.html b/man/testbin/rmtest.html new file mode 100644 index 0000000..8830907 --- /dev/null +++ b/man/testbin/rmtest.html @@ -0,0 +1,93 @@ + + + +rmtest + + + +

rmtest

+

OS/161 Reference Manual

+ +

Name

+

+rmtest - test removing open files +

+ +

Synopsis

+

+/testbin/rmtest +

+ +

Description

+

+rmtest deletes a file while it's open and then attempts to do +further I/O to it, and tries to check that the right things happen. +

+ +

Requirements

+

+rmtest uses the following system calls: +

+

+ +

+rmtest also spawns a copy of +/bin/rm, which uses these system calls: +

+

+ +

+rmtest should run correctly once the file system assignment +is complete. +

+ +

Bugs

+

+There's no particular reason it should use /bin/rm instead of +calling remove itself. But I guess +it makes life more exciting. +

+ + + diff --git a/man/testbin/sbrktest.html b/man/testbin/sbrktest.html new file mode 100644 index 0000000..b87b09d --- /dev/null +++ b/man/testbin/sbrktest.html @@ -0,0 +1,134 @@ + + + +sbrktest + + + +

sbrktest

+

OS/161 Reference Manual

+ +

Name

+

+sbrktest - program for testing sbrk +

+ +

Synopsis

+

+/testbin/sbrktest [test-number ...] +

+ +

Description

+

+sbrktest contains a number of tests for memory allocation, +using the sbrk low-level interface +directly instead of via malloc. +It is similar to malloctest in general +layout and approach, but concentrates on kernel-level memory +allocation rather than the behavior of C malloc. +

+ +

+There are 21 tests: + + + + + + + + + + + + + + + + + + + + + + +
1Allocate one page.
2Allocate and free one page.
3Allocate and free several pages.
4Allocate several pages and free them one + at a time.
5Check the heap end. + This test crashes intentionally.
6Allocate and check the heap end. + This test crashes intentionally.
7Allocate and free and check the heap end. + This test crashes intentionally.
8Allocate several, free some, then check + the heap end. + This test crashes intentionally.
9Allocate all memory in a big chunk.
10Allocate all memory one page at a time.
11Allocate a lot and intentionally leak + it.
12Fork and then allocate.
13Allocate and then fork.
14Allocate and then fork and free.
15Allocate, fork, allocate more, and + free.
16Small stress test.
17Randomized small stress test.
18Small stress test with specific seed.
19Large stress test.
20Randomized large stress test.
21Large stress test with specific seed.
+

+ +

+One or more tests may be run specifically by giving the numbers on the +command line; otherwise, sbrktest prints the list and prompts +for a test number to run. +

+ +

+Note that the tests that crash intentionally should crash the +sbrktest program with an illegal memory access +(SIGSEGV) -- they should not crash your kernel. +

+ +

+The tests that attempt to allocate all available memory may be slow, +depending on the per-process limits you place on memory allocation (if +any) relative to the amount of available physical RAM. +

+ +

Requirements

+

+sbrktest uses the following system calls: +

+

+ +

+sbrktest should work properly once you have implemented the +sbrk system call and a virtual memory system that supports dynamic +memory allocation. +It will not work with dumbvm. +

+ + + diff --git a/man/testbin/schedpong.html b/man/testbin/schedpong.html new file mode 100644 index 0000000..a69b1a8 --- /dev/null +++ b/man/testbin/schedpong.html @@ -0,0 +1,149 @@ + + + +schedpong + + + +

schedpong

+

OS/161 Reference Manual

+ +

Name

+

+schedpong - scheduler pong +

+ +

Synopsis

+

+/testbin/schedpong [options...] +

+ +

Description

+

+schedpong forks a number of processes that do different kinds +of work. +This can be used to evaluate the behavior of your scheduler under +different conditions. +

+ +

+There are three kinds of jobs in schedpong: +

    +
  • Thinkers
  • +
  • Grinders
  • +
  • Pong groups
  • +
+

+ +

+A thinker job is one CPU-bound process: it loops computing and doesn't +sleep for I/O or use much memory. +

+ +

+A grinder job is one memory-bound process: it loops accessing lots of +memory, similar to the various VM stress tests. +

+ +

+A pong group job is a family of I/O-bound processes. +An arbitrary number of processes play scheduler pong using the user +semaphores (semfs), each process signalling the next. +

+ +

+By choosing different numbers of thinkers, pong groups, and grinders, +and adjusting the pong group size, one can evaluate how well a +scheduler does under different conditions. +In general schedulers should be favoring the pong groups in order to +minimize the response latency of the semaphore ponging, but without +starving the thinkers. +Adding grinders to the mix lets your deal with what happens when you +also have swapping going on, which is a complicated situation not +handled well by textbook algorithms. +

+ +

+Note that you need to have a real VM system (not dumbvm) to use +grinders. +With dumbvm you may also need to configure a fair amount of memory to +get all the intended processes to fork successfully. +

+ +

+Options: +

+
-t N
Configure N thinkers. (default 2)
+
-g N
Configure N grinders. (default 0)
+
-p N
Configure N pong groups. (default 1)
+
-s N
Set the pong group size to N. (default 6)
+
+

+ +

Requirements

+

+schedpong uses the following system calls: +

+Only the grinder jobs use sbrk, and remove is only used for cleaning +up. +

+ +

+However, note that schedpong relies heavily on the user semaphores; +if they do not work (owing e.g. to bugs in open/read/write) schedpong +will not work either. +Make sure usemtest runs (at least up to the +"shoot" test, even if that part doesn't) before spending time on +schedpong. +

+ +

+schedpong without grinders should work once you have +implemented the basic system calls and they work reliably +(particularly fork). +schedpong with grinders should work once you have implemented +the sbrk system call and a virtual memory system that supports dynamic +memory allocation. +

+ + + diff --git a/man/testbin/sink.html b/man/testbin/sink.html new file mode 100644 index 0000000..8265c8e --- /dev/null +++ b/man/testbin/sink.html @@ -0,0 +1,71 @@ + + + +sink + + + +

sink

+

OS/161 Reference Manual

+ +

Name

+

+sink - accept and throw away console input +

+ +

Synopsis

+

+/testbin/sink +

+ +

Description

+

+sink reads characters from standard input and throws them +away. It is perhaps of some use for testing standard input or console +devices. +

+ +

Requirements

+

+sink uses the following system calls: +

+

+ +

+sink should function properly once the basic system calls are +complete. +

+ + + diff --git a/man/testbin/sort.html b/man/testbin/sort.html new file mode 100644 index 0000000..59a2443 --- /dev/null +++ b/man/testbin/sort.html @@ -0,0 +1,70 @@ + + + +sort + + + +

sort

+

OS/161 Reference Manual

+ +

Name

+

+sort - large quicksort-based VM test +

+ +

Synopsis

+

+/testbin/sort +

+ +

Description

+

+sort creates an array of 147456 random integers and then +sorts it using quicksort. This will hopefully help show up bugs in the +VM system. +

+ +

Requirements

+

+sort uses the following system calls: +

+

+ +

+sort should run correctly to completion once the VM +assignment is complete. +

+ + + diff --git a/man/testbin/sparsefile.html b/man/testbin/sparsefile.html new file mode 100644 index 0000000..982c0a2 --- /dev/null +++ b/man/testbin/sparsefile.html @@ -0,0 +1,77 @@ + + + +sparsefile + + + +

sparsefile

+

OS/161 Reference Manual

+ +

Name

+

+sparsefile - generate a sparse file +

+ +

Synopsis

+

+/testbin/sparsefile filename size +

+ +

Description

+

+sparsefile generates a sparse file (a file where most of the +file is unallocated space) of the requested size by writing +one byte to the end of it. +The resulting file should use one block for data, and depending on the +size (and the file system implementation) some small number of blocks +for metadata. +

+ +

Requirements

+

+sparsefile uses the following system calls: +

+

+ +

+sparsefile will work once you have implemented the basic +system calls, but will be most useful when working on the file +system. +

+ + + diff --git a/man/testbin/sty.html b/man/testbin/sty.html new file mode 100644 index 0000000..38aa8da --- /dev/null +++ b/man/testbin/sty.html @@ -0,0 +1,74 @@ + + + +sty + + + +

sty

+

OS/161 Reference Manual

+ +

Name

+

+sty - run some hogs +

+ +

Synopsis

+

+/testbin/sty +

+ +

Description

+

+sty runs six copies of hog. +

+ +

Requirements

+

+sty uses the following system calls: +

+

+ +

+sty is only likely to be useful for testing the scheduler... if then. +

+ +

Bugs

+

+sty does not wait for its child processes to finish. +

+ + + diff --git a/man/testbin/tail.html b/man/testbin/tail.html new file mode 100644 index 0000000..ebb311d --- /dev/null +++ b/man/testbin/tail.html @@ -0,0 +1,79 @@ + + + +tail + + + +

tail

+

OS/161 Reference Manual

+ +

Name

+

+tail - print part of a file +

+ +

Synopsis

+

+/testbin/tail file location +

+ +

Description

+

+tail prints the contents of a file starting at offset +location within it, skipping the beginning. +

+ +

+It is somewhat similar in concept to the Unix tail command, but is not +compatible, which is why it lives in testbin. +

+ +

Requirements

+

+tail uses the following system calls: +

+

+ +

+tail should work once the basic system calls are complete, +but will probably be most useful as a debugging tool while working on +the file system. +

+ + + diff --git a/man/testbin/tictac.html b/man/testbin/tictac.html new file mode 100644 index 0000000..a9d4a42 --- /dev/null +++ b/man/testbin/tictac.html @@ -0,0 +1,69 @@ + + + +tictac + + + +

tictac

+

OS/161 Reference Manual

+ +

Name

+

+tictac - tic-tac-toe game +

+ +

Synopsis

+

+/testbin/tictac +

+ +

Description

+

+tictac implements a simple version of tic-tac-toe. +

+ +

Requirements

+

+tictac uses the following system calls: +

+

+ +

+tictac should function correctly once the basic system calls +are complete. +

+ + + diff --git a/man/testbin/triplehuge.html b/man/testbin/triplehuge.html new file mode 100644 index 0000000..1b3c6a6 --- /dev/null +++ b/man/testbin/triplehuge.html @@ -0,0 +1,70 @@ + + + +triplehuge + + + +

triplehuge

+

OS/161 Reference Manual

+ +

Name

+

+triplehuge - very very large VM test +

+ +

Synopsis

+

+/testbin/triplehuge +

+ +

Description

+

+triplehuge runs three copies of huge at once. +

+ +

Requirements

+

+triplehuge uses the following system calls: +

+

+ +

+triplehuge should run properly once the VM assignment is complete. +

+ + + diff --git a/man/testbin/triplemat.html b/man/testbin/triplemat.html new file mode 100644 index 0000000..a9eb512 --- /dev/null +++ b/man/testbin/triplemat.html @@ -0,0 +1,71 @@ + + + +triplemat + + + +

triplemat

+

OS/161 Reference Manual

+ +

Name

+

+triplemat - very large VM test +

+ +

Synopsis

+

+/testbin/triplemat +

+ +

Description

+

+triplemat runs three copies of +matmult at once. +

+ +

Requirements

+

+triplemat uses the following system calls: +

+

+ +

+triplemat should run properly once the VM assignment is complete. +

+ + + diff --git a/man/testbin/triplesort.html b/man/testbin/triplesort.html new file mode 100644 index 0000000..05df30f --- /dev/null +++ b/man/testbin/triplesort.html @@ -0,0 +1,70 @@ + + + +triplesort + + + +

triplesort

+

OS/161 Reference Manual

+ +

Name

+

+triplesort - very large VM test +

+ +

Synopsis

+

+/testbin/triplesort +

+ +

Description

+

+triplesort runs three copies of sort at once. +

+ +

Requirements

+

+triplesort uses the following system calls: +

+

+ +

+triplesort should run properly once the VM assignment is complete. +

+ + + diff --git a/man/testbin/usemtest.html b/man/testbin/usemtest.html new file mode 100644 index 0000000..a68079a --- /dev/null +++ b/man/testbin/usemtest.html @@ -0,0 +1,87 @@ + + + +usemtest + + + +

usemtest

+

OS/161 Reference Manual

+ +

Name

+

+usemtest - test semfs (sem:) semaphores +

+ +

Synopsis

+

+/testbin/usemtest +

+ +

Description

+

+usemtest forks some subprocesses and uses the semfs +semaphores to do coordinated printing. It is somewhat similar to the +sy1 in-kernel test for the in-kernel semaphores. +

+ +

+The first parts of the test open each semaphore separately in each +process, so locking issues in the filetable and open-file code should +not keep it from running. +The last part opens the semaphores once and inherits the file +descriptors through fork; it is likely to hang (including sometimes in +fork) if the filetable and open-file locking is not just so. +

+ +

Requirements

+

+usemtest uses the following system calls: +

+

+ +

+usemtest should run successfully once the basic system calls +are complete. +Until you implement the remove() system call the semaphores +from the test will be left lying around afterwards, but this should +not keep it from running. +

+ + + diff --git a/man/testbin/userthreads.html b/man/testbin/userthreads.html new file mode 100644 index 0000000..2f8fa7a --- /dev/null +++ b/man/testbin/userthreads.html @@ -0,0 +1,75 @@ + + + +userthreads + + + +

userthreads

+

OS/161 Reference Manual

+ +

Name

+

+userthreads - simple user-level threads test +

+ +

Synopsis

+

+/testbin/userthreads +

+ +

Description

+

+userthreads does simple console I/O from two threads in the same +process. +

+ +

Requirements

+

+userthreads uses the following system calls: +

+ +It also assumes the existence of a function threadfork(), +which takes the address of a function to start a new thread at, and +makes certain other assumptions about thread semantics. See the source +file. +

+ +

+If implementing user-level threads, part of your responsibility is to +update the userthreads test to work with the threads package you +write. +

+ + + diff --git a/man/testbin/zero.html b/man/testbin/zero.html new file mode 100644 index 0000000..f479eee --- /dev/null +++ b/man/testbin/zero.html @@ -0,0 +1,78 @@ + + + +zero + + + +

zero

+

OS/161 Reference Manual

+ +

Name

+

+zero - test if VM system zeros memory +

+ +

Synopsis

+

+/testbin/zero +

+ +

Description

+

+zero checks if your VM system zeros memory like it's supposed +to. It checks both the BSS segment ("uninitialized data"), which is +supposed to be zeroed at program load time, and if you have +implemented sbrk, it also checks that newly allocated pages +acquired with sbrk are zeroed. +

+ +

+Failure to zero pages can cause other tests to blow up in complicated +ways that are often much harder to diagnose. +

+ +

Requirements

+

+zero uses the following system calls: +

+

+ +

+zero should run properly once the basic system calls are +implemented. +

+ + + diff --git a/mk/fixdepends.sh b/mk/fixdepends.sh new file mode 100755 index 0000000..2c6bda6 --- /dev/null +++ b/mk/fixdepends.sh @@ -0,0 +1,83 @@ +#!/bin/sh +# fixdepends.sh - munge gcc -M output +# usage: gcc -M foo.c | fixdepends.sh INSTALLTOP host|native > .depend +# (where INSTALLTOP is $(INSTALLTOP) from the build makefiles) + +if [ $# != 2 ]; then + echo "$0: Usage: $0 INSTALLTOP host|native" 1>&2 + exit 1 +fi + +INSTALLTOP="$1" +MODE="$2" + +case "$MODE" in + host|native) ;; + *) echo "$0: invalid mode $MODE; should be host or native" 1>&2 + exit 1 + ;; +esac + +awk ' + # Any blank lines appear between object files. + /^$/ { + printit(); + next; + } + # A line beginning with a space is a second or subsequent line of + # depends. + /^ / { + for (i=1;i<=NF;i++) { + if ($i != "\\") { + deps[++ndeps] = $i; + } + } + next; + } + # Any other line begins a new object file. + { + # Print the object file we already have, if any. + printit(); + # Trim the colon after the object file name. + object = $1; + sub(":$", "", object); + # If in host mode, change .o to .ho. + if (mode == "host") { + sub("\\.o$", ".ho", object); + } + # Anything else on the line is a depend. + for (i=2;i<=NF;i++) { + if ($i != "\\") { + deps[++ndeps] = $i; + } + } + next; + } + END { + # Print the object file we have, if any, so as to not lose the + # last one. + printit(); + } + function printit() { + if (ndeps == 0) { + # We have no object file in progress, so do nothing. + return; + } + # Insert MYBUILDDIR before the object file name. + printf "$(MYBUILDDIR)/%s: \\\n", object; + for (i=1;i<=ndeps;i++) { + printf " %s", deps[i]; + # Lines before the last need continuation. + if (i < ndeps) { + printf " \\"; + } + printf "\n"; + } + # We no longer have anything to print. + ndeps = 0; + object = "/WRONG"; + } + # Afterwards run sed to substitute INSTALLTOP. +' "mode=$MODE" | sed ' + s,'"$INSTALLTOP"',$(INSTALLTOP), +' diff --git a/mk/installheaders.sh b/mk/installheaders.sh new file mode 100755 index 0000000..24dc3fd --- /dev/null +++ b/mk/installheaders.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# installheaders.sh - install header files +# usage: installheaders.sh srcdir destdir +# srcdir/*.h is copied to destdir, if different. +# + +if [ $# != 2 ]; then + echo "$0: Usage: $0 srcdir destdir" 1>&2 + exit 1 +fi + +for H in "$1"/*.h; do + BH=`basename "$H"` + if diff "$H" "$2/$BH" >/dev/null 2>&1; then + : + else + echo cp "$H" "$2/$BH" + cp "$H" "$2/$BH" + fi +done diff --git a/mk/os161.baserules.mk b/mk/os161.baserules.mk new file mode 100644 index 0000000..4f080ba --- /dev/null +++ b/mk/os161.baserules.mk @@ -0,0 +1,78 @@ +# +# OS/161 build environment: some very basic rules. +# +# Individual program makefiles should use os161.prog.mk or +# os161.lib.mk instead of including this file directly. +# +# The variable MKDIRS is used to generate rules for creating +# (mostly installation) directories via os161.mkdirs.mk. + +# Process this file only once even if included repeatedly +.if !defined(_BASERULES_MK_) +_BASERULES_MK_=# empty + + +# +# Establish that all these (basic) rules exist and depend on the +# local (non-subdir) version. +# +.for _T_ in all depend install install-staging clean distclean tags +$(_T_): ; +$(_T_): $(_T_)-local +.PHONY: $(_T_) $(_T_)-local +.endfor + +# distclean implies clean +distclean: clean-local + + +# +# Some other derived rules. +# + +# cleandir is the same as distclean (cleandir is the old BSD name) +cleandir: distclean-local + +# "stage" is a good short name for install-staging +stage: install-staging-local + +# dependall means depend then compile, but it's important to run a +# new make after depending so the new depends take effect. +dependall-local: depend-local + $(MAKE) all-local +dependall: dependall-local + +# build means depend, compile, and install-staging; it also needs a +# new make after depending. It could use the same one for compile +# and install-staging, but that turns out to be awkward. +build-local: dependall-local + $(MAKE) install-staging-local +build: build-local + +# rebuild cleans first +rebuild: clean-local .WAIT build-local + +# fullrebuild does distclean +fullrebuild: distclean-local .WAIT build-local + +# implement BUILDSYMLINKS +.if "$(BUILDSYMLINKS)" == "yes" +.if !exists(build) +all depend: buildlink +.endif +buildlink: + ln -s $(MYBUILDDIR) build +clean: remove-buildlink +remove-buildlink: + rm -f build +.PHONY: buildlink remove-buildlink +.endif + +.PHONY: cleandir stage dependall build rebuild fullrebuild +.PHONY: dependall-local build-local + +.endif # _BASERULES_MK_ + +.include "$(TOP)/mk/os161.mkdirs.mk" + +# End. diff --git a/mk/os161.compile.mk b/mk/os161.compile.mk new file mode 100644 index 0000000..ab87e3d --- /dev/null +++ b/mk/os161.compile.mk @@ -0,0 +1,75 @@ +# +# OS/161 build environment: compile source files. +# +# Usage: use os161.prog.mk or os161.lib.mk +# +# Variables controlling this file: +# +# SRCS .c and .S files to compile. +# +# Provides: +# +# OBJS .o files from compilation. +# + +# Objects list starts empty. It is added to below. +OBJS= + +clean-local: cleancompile +cleancompile: + rm -f $(MYBUILDDIR)/*.[oa] + +distclean-local: distcleancompile +distcleancompile: + rm -f $(MYBUILDDIR)/.depend + +# +# Depend: generate dependency information. +# Use gcc's -M argument for this. +# +# Note that we use -M rather than -MM, to get both system headers +# and program-local headers. This is because we *are* the system and +# we might well change those system headers. +# +# The fixdepends script transforms the results by substituting some +# make variables back into them; this way the depend files are +# independent of (at least some of) the build configuration. It also +# allows for placing the .o files in the build directory. +# +depend-local: $(MYBUILDDIR) .WAIT predepend .WAIT dependcompile +dependcompile: + $(CC) $(CFLAGS) $(MORECFLAGS) -M $(SRCS) |\ + $(TOP)/mk/fixdepends.sh '$(INSTALLTOP)' native \ + > $(MYBUILDDIR)/.deptmp + mv -f $(MYBUILDDIR)/.deptmp $(MYBUILDDIR)/.depend + +.-include "$(MYBUILDDIR)/.depend" + +predepend: +.PHONY: predepend + +tags: tagscompile +tagscompile: + ctags -wtd $(SRCS) *.h + +# +# Compile rules. +# We can use the same rules for .c and .S because gcc knows how to handle +# .S files. +# +# Make it so typing "make foo.o" does the right thing. +# +.for _S_ in $(SRCS:M*.[cS]) +OBJS+=$(MYBUILDDIR)/$(_S_:T:R).o +$(MYBUILDDIR)/$(_S_:T:R).o: $(_S_) + $(CC) $(CFLAGS) $(MORECFLAGS) -c $(_S_) -o $(.TARGET) + +$(_S_:T:R).o: $(MYBUILDDIR)/$(_S_:T:R).o +.PHONY: $(_S_:T:R).o +.endfor + +# Make non-file rules PHONY. +.PHONY: clean-local cleancompile distclean-local distcleancompile +.PHONY: depend-local dependcompile tags tagscompile + +# End. diff --git a/mk/os161.config-mips.mk b/mk/os161.config-mips.mk new file mode 100644 index 0000000..a48c8f1 --- /dev/null +++ b/mk/os161.config-mips.mk @@ -0,0 +1,32 @@ +# +# OS/161 build environment extra definitions for MIPS. +# This is included by os161.config.mk. +# + + +# +# The MIPS toolchain for OS/161 is an ELF toolchain that by default +# generates SVR4 ELF ABI complaint code. This means that by default +# all code is PIC (position-independent code), which is all very well +# but not something we need or want in the kernel. So we use -fno-pic +# to turn this behavior off. +# +# We turn it off for userland too because we don't support shared +# libraries. Before trying to implement shared libraries, these +# options need to be taken out of CFLAGS. +# +# It turns out you also need -mno-abicalls to turn it off completely. +# + +CFLAGS+=-mno-abicalls -fno-pic +KCFLAGS+=-mno-abicalls -fno-pic + +# +# Extra stuff required for the kernel. +# +# -ffixed-23 reserves register 23 (s7) to hold curthread. This register +# number must match the curthread definition in mips/thread.h and the +# code in trap.S. +# +KCFLAGS+=-ffixed-23 +KLDFLAGS+= diff --git a/mk/os161.config.mk b/mk/os161.config.mk new file mode 100644 index 0000000..ad246e7 --- /dev/null +++ b/mk/os161.config.mk @@ -0,0 +1,485 @@ +# +# OS/161 build environment base definitions +# +# Proper usage: +# TOP=../.. # or however many levels needed +# .include "$(TOP)/mk/os161.config.mk" +# +# This file takes care of including $(TOP)/defs.mk and sets defaults +# for things that can be defined there. +# +# It and defs.mk collaboratively set various make variables that +# control the build environment. +# +############################################################ +# +# These build variables are meant to be user-settable: +# +# (Locations.) +# +# OSTREE The root directory you run OS/161 in. +# Default is ~/os161/root. +# +# WORKDIR Top of a tree to use for compiling. +# Default is $(TOP)/build. +# +# BUILDSYMLINKS If set to "yes", symlinks in each directory +# will be made to point into $(BUILDTOP). +# Default is "yes". +# +# By default the system will be built within the source tree and +# installed to ~/os161/root. It is expected this will be sufficient +# for most uses. If your root directory is somewhere else, set OSTREE +# in defs.mk. If you're running on a large computing cluster with +# networked home directories, setting WORKDIR to point somewhere on a +# local disk will probably make your builds quite a bit faster, at the +# cost of having to recompile if you switch to a different machine. +# If you want the source tree to be completely read-only, which is +# occasionally useful for tracking down build glitches, you can set +# WORKDIR and also set BUILDSYMLINKS to no. +# +# (Platform.) +# +# PLATFORM The type of system we're building for. +# Should always be set by defs.mk. +# +# MACHINE The processor type we're building for. +# Should always be set by defs.mk. +# +# The target machine type is set when you configure the source tree. +# If you change it, be sure to make distclean and recompile everything. +# Not all possible combinations of PLATFORM and MACHINE are allowed. +# See the logic at the bottom of this file for a list of supported +# combinations. If you are trying to port OS/161 to a new machine, the +# first step is to update that list. +# +# (Compilation.) +# +# DEBUG Compiler option for debug vs. optimize. +# Default: -O2 +# +# WARNINGS Compiler options for warnings. +# Default: -Wall -Wextra -Wwrite-strings +# -Wmissing-prototypes +# +# WERROR Compiler option to make warnings fatal. +# Default: -Werror +# +# Since debugging of user-level programs is not supported in OS/161 +# (and not really supportable without a lot of work on your part) +# there's usually not much reason to change DEBUG. If you want to, +# however, the easiest way is to usually set it on the make command +# line: +# make clean +# make DEBUG=-g all +# recompiles the current directory with debug info. +# +# Similarly, if you have a lot of warnings and you want to temporarily +# ignore them while you fix more serious problems, you can turn off +# the error-on-warning behavior on the fly by setting WERROR to empty: +# make WERROR= +# +# This convenience is why these variables are separately defined +# rather than just being rolled into CFLAGS. +# +############################################################ +# +# These build variables can be set explicitly for further control if +# desired, but should in general not need attention. +# +# (Tools.) +# +# PYTHON_INTERPRETER Location of Python interpreter. +# Default is "/usr/bin/env python". +# +# This may need to be changed on some platforms; but the configure +# script is supposed to take care of it for you. If that fails, or +# picks the wrong thing, please file a bug report. +# +# (Locations.) +# +# BUILDTOP Top of tree where .o files go. +# Default is $(WORKDIR). +# +# TOOLDIR Place for compiled programs used in +# the build. Default is $(WORKDIR)/tooldir. +# +# INSTALLTOP Staging directory for installation. +# Default is $(WORKDIR)/install. +# +# Probably the only reason to change these would be if you're short on +# diskspace in $(WORKDIR). +# +# (Platform.) +# +# GNUTARGET The GNU gcc/binutils name for the +# target we're building for. +# Defaults to $(MACHINE)-harvard-os161. +# +# This should not need to be changed. +# +# (Programs.) +# +# CC (Cross-)compiler. +# Default is $(GNUTARGET)-gcc. +# +# LDCC (Cross-)compiler when invoked for linking. +# Default is $(CC). +# +# AS (Cross-)assembler. +# Default is $(GNUTARGET)-as. +# +# LD (Cross-)linker. +# Default is $(GNUTARGET)-ld. +# +# AR Archiver (librarian). +# Default is $(GNUTARGET)-ar. +# +# RANLIB Library postprocessor/indexer. +# Default is $(GNUTARGET)-ranlib. +# +# NM Tool to print symbol tables. +# Default is $(GNUTARGET)-nm. +# +# SIZE Tool to print sizes of binaries. +# Default is $(GNUTARGET)-size. +# +# STRIP Tool to remove debugging information. +# Default is $(GNUTARGET)-strip. +# +# The above are the compilation tools for OS/161. They create programs +# that run on OS/161. Since OS/161 is not meant to be self-hosting, +# programs that we need to run during the build, or run manually +# outside of the machine simulator, need to be compiled with a +# different compiler that creates programs that run for the "host" OS, +# whatever that is (Linux, NetBSD, FreeBSD, MacOS X, Solaris, etc.) +# The host compilation tools are prefixed with HOST_ as follows: +# +# +# HOST_CC Host compiler. +# Default is gcc. +# +# HOST_LDCC Host compiler when invoked for linking. +# Default is $(HOST_CC). +# +# HOST_AS Host assembler. +# Default is as. +# +# HOST_LD Host linker. +# Default is ld. +# +# HOST_AR Host archiver (librarian). +# Default is ar. +# +# HOST_RANLIB Host library postprocessor/indexer. +# Default is ranlib. +# +# HOST_NM Host tool to print symbol tables. +# Default is nm. +# +# HOST_SIZE Host tool to print sizes of binaries. +# Default is size. +# +# HOST_STRIP Host tool to remove debugging information. +# Default is strip. +# +# In general there should be no need to change the cross-compiler +# variables, unless you are e.g. trying to build OS/161 with something +# other than gcc, or you want to supply an explicit location for a +# specific copy of gcc somewhere rather than use the one on your +# $PATH. +# +# However, on some systems it might conceivably be necessary to change +# the host tool variables. For example, there are some (now extremely +# old) systems where "ranlib" is not only not needed but also corrupts +# libraries, in which case you might set HOST_RANLIB=true. If your +# host machine doesn't have "gcc" you may be able to set HOST_CC=cc +# and fiddle with HOST_WARNINGS and HOST_CFLAGS (below) and have +# things still more or less work. +# +# (Compilation.) +# +# HOST_DEBUG Like DEBUG, but for programs to be +# built to run on the host OS. +# Default is $(DEBUG). +# +# HOST_WARNINGS Like WARNINGS, but for programs to be +# built to run on the host OS. +# Default is $(WARNINGS). +# +# HOST_WERROR Like WERROR, but for programs to be +# built to run on the host OS. +# Default is $(WERROR). +# +############################################################ +# +# These build variables should probably not be tinkered with in +# defs.mk and serve as baseline values to be added to by individual +# program makefiles and used by other os161.*.mk files. +# +# (Compilation.) +# +# CFLAGS Full baseline compile flags. +# Default is $(DEBUG) $(WARNINGS) $(WERROR), +# plus what's needed for -nostdinc. +# +# KCFLAGS Like CFLAGS, but for the kernel, which +# configures debug/optimize separately. +# Default is $(KDEBUG) $(WARNINGS) $(WERROR). +# (KDEBUG is set by the kernel config script.) +# +# HOST_CFLAGS Like CFLAGS, but for programs to be +# built to run on the host OS. Default is +# $(HOST_DEBUG) $(HOST_WARNINGS) $(HOST_WERROR). +# +# LDFLAGS Baseline link-time flags. +# Default is empty plus what's needed for +# -nostdlib. +# +# KLDFLAGS Baseline link-time flags for kernel. +# Default is empty. +# +# HOST_LDFLAGS Like LDFLAGS, but for programs to be +# built to run on the host OS. +# Default is empty. +# +# LIBS Baseline list of libraries to link to. +# Default is empty plus what's needed for +# -nostdlib. +# +# HOST_LIBS Like LIBS, but for programs to be +# built to run on the host OS. +# Default is empty. +# +############################################################ +# +# These variables should not be changed directly, or by individual +# program makefiles either, and are for use by other os161.*.mk files. +# +# (Locations.) +# +# MYDIR Name of current source directory, relative +# to $(TOP); e.g. bin/sh. +# +# MYBUILDDIR Build directory for current source directory. +# +# MKDIRS Directories to create, mostly for installing. +# +# ABSTOP_PATTERN, ABSTOP Private, used to compute other locations. +# +# (Compilation.) +# +# MORECFLAGS Same as CFLAGS but comes later on the +# compile command line. In general individual +# makefiles shouldn't touch this. +# Default is empty plus what's needed for +# -nostdinc. +# +# MORELIBS Same as LIBS but comes after on the link +# line. In general individual makefiles +# shouldn't touch this. +# Default is empty plus what's needed for +# -nostdlib. +# +############################################################ + +# Some further vars that currently exist but should be moved +# around elsewhere: +# +# COMPAT_CFLAGS +# COMPAT_TARGETS + + +############################################################ +# Establish defaults. +# (Variables are set in the order documented above.) +# +# These definitions are set firmly here (that is, not with ?=) because +# some of them, like CC, are predefined by make. Because defs.mk is +# included afterwards it can override any of these settings. +# + +# +# User-settable configuration +# + +# Locations of things. +OSTREE=$(HOME)/os161/root # Root directory to install into. +WORKDIR=$(TOP)/build # Top of tree to build into. +BUILDSYMLINKS=yes # yes => link build -> $(BUILDTOP)/$(HERE). + +# Platform we're building for. +PLATFORM=sys161 +MACHINE=mips + +# Compilation +DEBUG=-O2 +WARNINGS=-Wall -W -Wwrite-strings -Wmissing-prototypes +WERROR=-Werror + +# +# Less-likely-to-need-setting +# + +# Locations of things. +BUILDTOP=$(WORKDIR) # Top of directory for compiler output. +TOOLDIR=$(WORKDIR)/tooldir # Place for host progs used in the build. +INSTALLTOP=$(WORKDIR)/install # Staging area for installation. + +# Platform. +GNUTARGET=$(MACHINE)-harvard-os161 + +# Programs and tools. +CC=$(GNUTARGET)-gcc # Compiler. +LDCC=$(CC) # Compiler when used for linking. +AS=$(GNUTARGET)-as # Assembler. +LD=$(GNUTARGET)-ld # Linker. +AR=$(GNUTARGET)-ar # Archiver. +RANLIB=$(GNUTARGET)-ranlib # Library indexer. +NM=$(GNUTARGET)-nm # Symbol dumper. +SIZE=$(GNUTARGET)-size # Size tool. +STRIP=$(GNUTARGET)-strip # Debug strip tool. +HOST_CC=gcc # Host compiler. +HOST_LDCC=$(HOST_CC) # Host compiler when used for linking. +HOST_AS=as # Host assembler. +HOST_LD=ld # Host linker. +HOST_AR=ar # Host archiver. +HOST_RANLIB=ranlib # Host library indexer. +HOST_NM=nm # Host symbol dumper. +HOST_SIZE=size # Host size tool. +HOST_STRIP=strip # Host debug strip tool. + +# Compilation. +HOST_DEBUG=$(DEBUG) +HOST_WARNINGS=$(WARNINGS) +HOST_WERROR=$(WERROR) + +# +# Probably-shouldn't-be-touched +# + +CFLAGS=$(DEBUG) $(WARNINGS) $(WERROR) -std=gnu99 +KCFLAGS=$(KDEBUG) $(WARNINGS) $(WERROR) -std=gnu99 +HOST_CFLAGS=$(HOST_DEBUG) $(HOST_WARNINGS) $(HOST_WERROR) \ + -I$(INSTALLTOP)/hostinclude + +LDFLAGS= +KLDFLAGS= +HOST_LDFLAGS= + +LIBS= +HOST_LIBS= + +# +# Don't touch. +# + +MORECFLAGS= +MORELIBS= + +# lib/hostcompat. +COMPAT_CFLAGS= +COMPAT_TARGETS= + +############################################################ +# Get defs.mk to get the real configuration for this tree. +# If it doesn't exist, we'll go with the defaults. + +.-include "$(TOP)/defs.mk" + +############################################################ +# Make sure we have a supported PLATFORM and MACHINE. + +# We support mips on system/161. +SUPPORTED_TARGETS=sys161 mips + +_OK_=0 +.for _P_ _M_ in $(SUPPORTED_TARGETS) +.if "$(PLATFORM)" == "$(_P_)" && "$(MACHINE)" == "$(_M_)" +_OK_=1 +.endif +.endfor + +.if "$(_OK_)" != "1" +.init: + @echo "Platform $(PLATFORM) and machine $(MACHINE) not supported" + @false +.endif + +############################################################ +# Get any machine-dependent flags or makefile definitions + +.-include "$(TOP)/mk/os161.config-$(MACHINE).mk" + +############################################################ +# Establish some derived locations. + +# +# Absolute location of the top of the source tree. This should only be +# used to un-absolutize other paths; the tree ought to be independent +# of where it happens to live. +# +# This works by turning $(TOP) into a regexp and substituting it into +# the current directory. Note that it doesn't escape all regexp +# metacharacters -- if you make a directory named "foo*bar" or +# something you deserve the consequences. +# +# .CURDIR is a make builtin. +# +ABSTOP_PATTERN=$(TOP:S/./\\./g:S/\\.\\./[^\/]*/g) +ABSTOP=$(.CURDIR:C/$(ABSTOP_PATTERN)\$//) + +# Find the name of the current directory relative to TOP. +# This works by removing ABSTOP from the front of .CURDIR. +MYDIR=$(.CURDIR:S/^$(ABSTOP)//) + +# Find the build directory corresponding to the current source dir. +.if "$(MYDIR)" == "" +# avoid stray slash +MYBUILDDIR=$(BUILDTOP) +.else +MYBUILDDIR=$(BUILDTOP)/$(MYDIR) +.endif + +############################################################ +# Ensure we compile a consistent tree. + +# +# Traditionally in Unix the first step of recompiling the system is to +# install new header files. Furthermore, the second step is to compile +# and install new libraries, before continuing on to the rest of the +# OS, which can then be compiled with those new headers and new +# libraries. +# +# Combining the compile and install phases like this is simpler and +# uses less disk space on extra copies of things (which mattered, back +# in the day) but has a number of problems. Chief among these is that +# if the build bombs out halfway through you end up with a partly +# updated and maybe broken system. It also means that once you start +# recompiling the system you can't easily back out. And the behavior +# violates the principle of least surprise. +# +# OS/161 1.x had, intentionally, a very traditional build environment. +# In OS/161 2.x, however, we use a staging area to avoid mixing build +# and install. This means that we must compile only against the +# staging area, $(INSTALLTOP), and never use the headers or libraries +# installed in $(OSTREE) until install time. +# +# This means that regardless of whether we have a gcc configured so it +# includes from our $(OSTREE) by default or not, we must use -nostdinc +# and -nostdlib and explicitly link with materials from $(INSTALLTOP). +# +# Use MORECFLAGS and MORELIBS, which are supported by os161.compile.mk +# for this purpose, so the include paths and library list come out in +# the right order. +# + +CFLAGS+=-nostdinc +MORECFLAGS+=-I$(INSTALLTOP)/include +LDFLAGS+=-nostdlib -L$(INSTALLTOP)/lib $(INSTALLTOP)/lib/crt0.o +MORELIBS+=-lc +LIBDEPS+=$(INSTALLTOP)/lib/crt0.o $(INSTALLTOP)/lib/libc.a + +############################################################ + +# end. diff --git a/mk/os161.hostcompile.mk b/mk/os161.hostcompile.mk new file mode 100644 index 0000000..c7c6cf3 --- /dev/null +++ b/mk/os161.hostcompile.mk @@ -0,0 +1,75 @@ +# +# OS/161 build environment: compile source files for the host system. +# +# Usage: use os161.hostprog.mk or os161.hostlib.mk +# +# Variables controlling this file: +# +# SRCS .c and .S files to compile. +# +# Provides: +# +# HOST_OBJS .ho files from compilation. +# + +# Objects list starts empty. It is added to below. +HOST_OBJS= + +# .ho is a host object. +.SUFFIXES: .ho + +clean-local: cleanhostcompile +cleanhostcompile: + rm -f $(MYBUILDDIR)/*.ho $(MYBUILDDIR)/*.ha + +distclean-local: distcleanhostcompile +distcleanhostcompile: + rm -f $(MYBUILDDIR)/.hostdepend + +# +# Depend: generate dependency information. +# Use gcc's -MM argument for this. +# +# Note that we use -MM rather than -M, so we don't get system headers. +# They would be host system headers and we don't want to get involved +# with those. +# +# The fixdepends script transforms the results by substituting some +# make variables back into them; this way the depend files are +# independent of (at least some of) the build configuration. It also +# changes .o files to .ho files so the host and native builds are +# independent, and allows for placing the .ho files in the build +# directory. +# +depend-local: $(MYBUILDDIR) .WAIT predepend .WAIT dependhostcompile +dependhostcompile: + $(HOST_CC) $(HOST_CFLAGS) -DHOST -MM $(SRCS) |\ + $(TOP)/mk/fixdepends.sh '$(INSTALLTOP)' host \ + > $(MYBUILDDIR)/.hostdeptmp + mv -f $(MYBUILDDIR)/.hostdeptmp $(MYBUILDDIR)/.hostdepend + +.-include "$(MYBUILDDIR)/.hostdepend" + +predepend: +.PHONY: predepend + +# No tags for host programs. +tags: tagshostcompile +tagshostcompile: ; + +# +# Compile rules. +# We can use the same rules for .c and .S because gcc knows how to handle +# .S files. +# +.for _S_ in $(SRCS:M*.[cS]) +HOST_OBJS+=$(MYBUILDDIR)/$(_S_:T:R).ho +$(MYBUILDDIR)/$(_S_:T:R).ho: $(_S_) + $(HOST_CC) $(HOST_CFLAGS) -DHOST -c $(_S_) -o $(.TARGET) +.endfor + +# Make non-file rules PHONY. +.PHONY: clean-local cleanhostcompile distclean-local distcleanhostcompile +.PHONY: depend-local dependhostcompile tags tagshostcompile + +# End. diff --git a/mk/os161.hostlib.mk b/mk/os161.hostlib.mk new file mode 100644 index 0000000..88517d9 --- /dev/null +++ b/mk/os161.hostlib.mk @@ -0,0 +1,78 @@ +# +# OS/161 build environment: build a library for the compile host +# +# Usage: +# TOP=../.. +# .include "$(TOP)/mk/os161.config.mk" +# [defs go here] +# .include "$(TOP)/mk/os161.hostlib.mk" +# [any extra rules go here] +# +# Variables controlling this file: +# +# LIB Name of library. We create lib$(LIB).a. +# SRCS .c and .S files to compile. +# +# HOST_CFLAGS Compile flags. +# +# Note that individual program makefiles should only *append* to +# HOST_CFLAGS, not assign it. Otherwise stuff set by os161.config.mk +# will get lost and bad things will happen. +# +# Because we only build static libs, we can't use and don't need +# LDFLAGS or LIBS. (Shared libs would want these.) +# +# Note that there's no HOSTLIBDIR; host libs are always put in +# $(TOOLDIR)/hostlib and do not end up in $(OSTREE). +# + +_LIB_=lib$(LIB).a + +# We may want these directories created. (Used by os161.baserules.mk.) +MKDIRS+=$(MYBUILDDIR) +MKDIRS+=$(TOOLDIR)/hostlib + +# Default rule: create the program. +# (In make the first rule found is the default.) +all: all-local +all-local: $(MYBUILDDIR) .WAIT $(MYBUILDDIR)/$(_LIB_) + +# Now get rules to compile the SRCS. +.include "$(TOP)/mk/os161.hostcompile.mk" + +# Further rules for libraries. + +# +# Install: we can install into either $(INSTALLTOP) or $(OSTREE). +# When building the whole system, we always install into the staging +# area. We provide the same direct install that os161.prog.mk +# provides; however, because it this doesn't relink anything using the +# library it generally isn't a very useful thing to do. Hence the +# warning. +# +# Note that we make a hard link instead of a copy by default to reduce +# overhead. +# +install-staging-local: $(TOOLDIR)/hostlib .WAIT $(TOOLDIR)/hostlib/$(_LIB_) +$(TOOLDIR)/hostlib/$(_LIB_): $(MYBUILDDIR)/$(_LIB_) + rm -f $(.TARGET) + ln $(MYBUILDDIR)/$(_LIB_) $(.TARGET) || \ + cp $(MYBUILDDIR)/$(_LIB_) $(.TARGET) + +install-local: + @echo "Nothing to manually install" + +# Build the library. +$(MYBUILDDIR)/$(_LIB_): $(HOST_OBJS) + rm -f $(.TARGET) + $(HOST_AR) -cq $(.TARGET) $(HOST_OBJS) + $(HOST_RANLIB) $(.TARGET) + +# Mark targets that don't represent files PHONY, to prevent various +# lossage if files by those names appear. +.PHONY: all all-local install-staging-local install-local + +# Finally, get the shared definitions for the most basic rules. +.include "$(TOP)/mk/os161.baserules.mk" + +# End. diff --git a/mk/os161.hostprog.mk b/mk/os161.hostprog.mk new file mode 100644 index 0000000..13e5984 --- /dev/null +++ b/mk/os161.hostprog.mk @@ -0,0 +1,109 @@ +# +# OS/161 build environment: build a host-system program +# +# Usage: +# TOP=../.. +# .include "$(TOP)/mk/os161.config.mk" +# [defs go here] +# .include "$(TOP)/mk/os161.hostprog.mk" +# [any extra rules go here] +# +# Variables controlling this file: +# +# PROG Name of program to generate. +# SRCS .c and .S files to compile. +# +# HOST_CFLAGS Compile flags. +# HOST_LDFLAGS Link flags. +# HOST_LIBS Libraries to link with. +# +# HOSTBINDIR Directory under $(OSTREE) to install into, +# e.g. /hostbin. Should have a leading slash. +# If not set, the program goes in +# $(TOOLDIR)/hostbin instead. +# +# Note that individual program makefiles should only *append* to +# HOST_CFLAGS, HOST_LDFLAGS, and HOST_LIBS, not assign them. Otherwise +# stuff set by os161.config.mk will get lost and bad things will +# happen. +# +# This is set up so it can be used together with os161.prog.mk if +# necessary. +# + +# Real name +_PROG_=host-$(PROG) + +# Directory to install into +.if defined(HOSTBINDIR) +_INSTALLDIR_=$(INSTALLTOP)$(HOSTBINDIR) +.else +_INSTALLDIR_=$(TOOLDIR)/hostbin +.endif + +# We may want these directories created. (Used by os161.baserules.mk.) +MKDIRS+=$(MYBUILDDIR) +MKDIRS+=$(_INSTALLDIR_) +.if defined(HOSTBINDIR) +MKDIRS+=$(OSTREE)$(HOSTBINDIR) +.endif + +# Default rule: create the program. +# (In make the first rule found is the default.) +all: all-local +all-local: $(MYBUILDDIR) .WAIT $(MYBUILDDIR)/$(_PROG_) + +# Now get rules to compile the SRCS. +.include "$(TOP)/mk/os161.hostcompile.mk" + +# Further rules for programs. + +# Clean: delete extraneous files. +clean-local: cleanhostprog +cleanhostprog: + rm -f $(MYBUILDDIR)/$(_PROG_) + +# +# Install: we can install into either $(INSTALLTOP) or $(OSTREE). +# When building the whole system, we always install into the staging +# area. However, if you're working on a particular program it is +# usually convenient to be able to install it directly to $(OSTREE) +# instead of doing a complete top-level install. +# +# Note that we make a hard link instead of a copy by default to reduce +# overhead. +# +install-staging-local: $(_INSTALLDIR_) .WAIT $(_INSTALLDIR_)/$(_PROG_) +$(_INSTALLDIR_)/$(_PROG_): $(MYBUILDDIR)/$(_PROG_) + rm -f $(.TARGET) + ln $(MYBUILDDIR)/$(_PROG_) $(.TARGET) || \ + cp $(MYBUILDDIR)/$(_PROG_) $(.TARGET) + +.if defined(HOSTBINDIR) +install-local: install-hostprog +install-hostprog: $(OSTREE)$(HOSTBINDIR) $(MYBUILDDIR)/$(_PROG_) + rm -f $(OSTREE)$(HOSTBINDIR)/$(_PROG_) + ln $(MYBUILDDIR)/$(_PROG_) $(OSTREE)$(HOSTBINDIR)/$(_PROG_) || \ + cp $(MYBUILDDIR)/$(_PROG_) $(OSTREE)$(HOSTBINDIR)/$(_PROG_) +.else +install-local: + @echo "Nothing to manually install" +.endif + +# Always implicitly include the compat library. +_COMPATLIB_=$(TOOLDIR)/hostlib/libhostcompat.a + +# Link the program. +$(MYBUILDDIR)/$(_PROG_): $(HOST_OBJS) $(_COMPATLIB_) + $(HOST_LDCC) $(HOST_LDFLAGS) $(HOST_OBJS) $(HOST_LIBS) $(_COMPATLIB_) \ + -o $(.TARGET) + +# Mark targets that don't represent files PHONY, to prevent various +# lossage if files by those names appear. +.PHONY: all all-local clean-local cleanhostprog install-staging-local +.PHONY: install-local install-hostprog + +# Finally, get the shared definitions for the most basic rules. +.include "$(TOP)/mk/os161.baserules.mk" + +# End. diff --git a/mk/os161.includes.mk b/mk/os161.includes.mk new file mode 100644 index 0000000..9ad616b --- /dev/null +++ b/mk/os161.includes.mk @@ -0,0 +1,56 @@ +# +# OS/161 build environment: include file installation. +# +# Set INCLUDES to a list of pairs: +# +# source-dir destination-dir +# +# where the destination dir should begin with include/. +# All header files in each dir are copied. +# +# Optionally set INCLUDELINKS to a list of pairs +# +# target linkname +# +# This will create symlinks target <- linkname. linkname +# should begin with include/. target usually won't. +# +# +# If you forcibly make install, header files are copied to $(OSTREE). +# + +all depend install-staging clean distclean tags: ; +all-local depend-local install-staging-local clean-local distclean-local: ; + +.for _SRC_ _DEST_ in $(INCLUDES) +MKDIRS+=$(INSTALLTOP)/$(_DEST_) +includes: $(INSTALLTOP)/$(_DEST_) .WAIT + +MKDIRS+=$(OSTREE)/$(_DEST_) +install: $(OSTREE)/$(_DEST_) .WAIT +.endfor + +includes: includes-local +includes-local: +.for _SRC_ _DEST_ in $(INCLUDES) + $(TOP)/mk/installheaders.sh $(_SRC_) $(INSTALLTOP)/$(_DEST_) +.endfor +.for _TGT_ _LINK_ in $(INCLUDELINKS) + [ -h $(INSTALLTOP)/$(_LINK_) ] || \ + ln -sf $(_TGT_) $(INSTALLTOP)/$(_LINK_) +.endfor + +install-local: +.for _SRC_ _DEST_ in $(INCLUDES) + $(TOP)/mk/installheaders.sh $(_SRC_) $(OSTREE)/$(_DEST_) +.endfor +.for _TGT_ _LINK_ in $(INCLUDELINKS) + [ -h $(INSTALLTOP)/$(_LINK_) ] || \ + ln -sf $(_TGT_) $(INSTALLTOP)/$(_LINK_) +.endfor + +.PHONY: all depend install-staging clean distclean tags +.PHONY: includes includes-local install-local + +.include "$(TOP)/mk/os161.baserules.mk" + diff --git a/mk/os161.kernel.mk b/mk/os161.kernel.mk new file mode 100644 index 0000000..ebb8003 --- /dev/null +++ b/mk/os161.kernel.mk @@ -0,0 +1,217 @@ +# +# OS/161 build environment: build a kernel +# +# Note that kernels build in kernel build directories and not into +# $(BUILDDIR). +# + +# +# The makefile stub generated by the kernel config script looks like this: +# KTOP=../.. # top of the kernel tree +# TOP=$(KTOP)/.. # top of the whole tree +# KDEBUG=-g # debug vs. optimize +# CONFNAME=GENERIC # name of the kernel config file +# .include "$(TOP)/mk/os161.config.mk" +# .include "files.mk" +# .include "$(TOP)/mk/os161.kernel.mk" +# +# files.mk is also generated by the kernel config script. +# + +# +# Additional defs for building a kernel. +# + +# All sources. +ALLSRCS=$(SRCS) $(SRCS.MACHINE.$(MACHINE)) $(SRCS.PLATFORM.$(PLATFORM)) + +# Filename for the kernel. +KERNEL=kernel + +# Don't use headers and libraries that don't belong to the kernel. +# Kernels have to be standalone. +KCFLAGS+=-nostdinc +KLDFLAGS+=-nostdlib + +# Do use the kernel's header files. +KCFLAGS+=-I$(KTOP)/include -I$(KTOP)/dev -I. -Iincludelinks + +# Tell gcc that we're building something other than an ordinary +# application, so it makes fewer assumptions about standard library +# functions. +KCFLAGS+=-ffreestanding + +# Define _KERNEL so code in src/common can tell which header files +# it should use. +KCFLAGS+=-D_KERNEL + +# Provide the linker with a "linker script". This is a piece of +# obscure mumble that tells the linker how to put together the output +# program. We need it because a kernel needs (in general) to be linked +# to run at a different virtual address from an ordinary program. +# +# Traditionally all you need to do is pass -Ttext to set the address +# for the text (code), but this doesn't work with the GNU linker by +# default because of a silly design bug. +# +# Look for a linker script for the PLATFORM first, and if not that try +# MACHINE, and if neither of those exists assume we don't actually +# need one. + +.if exists($(KTOP)/arch/$(PLATFORM)/conf/ldscript) +KLDFLAGS+=-T $(KTOP)/arch/$(PLATFORM)/conf/ldscript +.elif exists($(KTOP)/arch/$(MACHINE)/conf/ldscript) +KLDFLAGS+=-T $(KTOP)/arch/$(MACHINE)/conf/ldscript +.endif + +# +# This should expand to all the header files in the kernel so they can +# be fed to tags. +# +TAGS_HEADERS=\ + $(KTOP)/*/*.h \ + $(KTOP)/include/kern/*.h \ + $(KTOP)/dev/*/*.h \ + $(KTOP)/arch/$(MACHINE)/*/*.h \ + $(KTOP)/arch/$(MACHINE)/include/kern/*.h \ + $(KTOP)/arch/$(PLATFORM)/*/*.h + +# +# Rules. +# + +# Default rule: link the kernel. +all: includelinks .WAIT $(KERNEL) + +# +# Here's how we link the kernel. +# +# vers.c/.o is generated on every build. It contains a numeric serial +# number incremented every time newvers.sh is run. These values are +# printed out by newvers.sh and are also displayed at boot time. This +# makes it possible to tell at a glance whether you're actually +# running the same kernel you just compiled. +# +# The version number is kept in the file called "version" in the build +# directory. +# +# By immemorial tradition, "size" is run on the kernel after it's linked. +# +$(KERNEL): + $(KTOP)/conf/newvers.sh $(CONFNAME) + $(CC) $(KCFLAGS) -c vers.c + $(LD) $(KLDFLAGS) $(OBJS) vers.o -o $(KERNEL) + @echo '*** This is $(CONFNAME) build #'`cat version`' ***' + $(SIZE) $(KERNEL) + +# +# Use the -M argument to gcc to get it to output dependency information. +# Note that we use -M, which includes deps for #include <...> files, +# rather than -MM, which doesn't. This is because we are the operating +# system: the #include <...> files are part of our project -- in fact, in +# the kernel they're the kernel's own include files -- and they will be +# changing! +# +# Each source file's depend info gets dumped into its own .depend file +# so the overall depend process parallelizes. Otherwise (assuming you +# have a reasonably modern machine) this is the slowest part of the +# kernel build. +# +depend: + $(MAKE) includelinks + rm -f .depend.* || true + $(MAKE) realdepend + +.for _S_ in $(ALLSRCS) +DEPFILES+=.depend.$(_S_:T) +.depend.$(_S_:T): + $(CC) $(KCFLAGS) -M $(_S_) > .depend.$(_S_:T) +.endfor +realdepend: $(DEPFILES) + cat $(DEPFILES) > .depend + +# our make does this implicitly +#.-include ".depend" + +# +# This allows includes of the forms +# +# +# +# and also (for this platform/machine) +# +# +# +# to go to the right place. +# +includelinks: + mkdir includelinks + mkdir includelinks/kern + ln -s ../../../arch/$(MACHINE)/include includelinks/$(MACHINE) + ln -s ../../../../arch/$(MACHINE)/include/kern \ + includelinks/kern/$(MACHINE) + ln -s ../../../arch/$(PLATFORM)/include includelinks/$(PLATFORM) + ln -s $(MACHINE) includelinks/machine + ln -s $(MACHINE) includelinks/kern/machine + ln -s $(PLATFORM) includelinks/platform + +# +# Remove everything generated during the compile. +# (To remove absolutely everything automatically generated, you can just +# blow away the whole compile directory.) +# +clean: + rm -f *.o *.a tags $(KERNEL) + rm -rf includelinks + +distclean cleandir: clean + rm -f .depend + +# +# Rerun config for this configuration. +# +reconfig: + (cd $(KTOP)/conf && ./config $(CONFNAME)) + +# +# [ -d $(OSTREE) ] succeeds if $(OSTREE) is a directory. +# (See test(1).) Thus, if $(OSTREE) doesn't exist, it will be created. +# +# The kernel gets installed at the top of the installed system tree. +# Since with OS/161 it's relatively likely that you'll be working with +# several configurations at once, it gets installed under the name of +# this config, and a symbolic link with the "real" name is set up to +# point to the last kernel installed. +# +install: + [ -d $(OSTREE) ] || mkdir $(OSTREE) + cp $(KERNEL) $(OSTREE)/$(KERNEL)-$(CONFNAME) + -rm -f $(OSTREE)/$(KERNEL) + ln -s $(KERNEL)-$(CONFNAME) $(OSTREE)/$(KERNEL) + +# +# Run tags on all the sources and header files. This is probably not +# the most useful way to do this and may need attention. (XXX?) +# +tags: + ctags -wtd $(ALLSRCS) $(TAGS_HEADERS) + +# +# This tells make that these rules are not files so it (hopefully) +# won't become confused if files by those names appear. +# +.PHONY: all depend realdepend clean reconfig install tags + +# +# Compilation rules. +# +.for _S_ in $(ALLSRCS) +OBJS+=$(_S_:T:R).o +$(_S_:T:R).o: $(_S_) + $(CC) $(KCFLAGS) -c $(_S_) +.endfor + +# Make the kernel depend on all the object files. +$(KERNEL): $(OBJS) + +# End. diff --git a/mk/os161.lib.mk b/mk/os161.lib.mk new file mode 100644 index 0000000..699ee71 --- /dev/null +++ b/mk/os161.lib.mk @@ -0,0 +1,84 @@ +# +# OS/161 build environment: build a library +# +# Usage: +# TOP=../.. +# .include "$(TOP)/mk/os161.config.mk" +# [defs go here] +# .include "$(TOP)/mk/os161.lib.mk" +# [any extra rules go here] +# +# Variables controlling this file: +# +# LIB Name of library. We create lib$(LIB).a. +# SRCS .c and .S files to compile. +# +# CFLAGS Compile flags. +# +# LIBDIR Directory under $(OSTREE) to install into, +# e.g. /lib. Should have a leading slash. +# +# Note that individual program makefiles should only *append* to +# CFLAGS, not assign it. Otherwise stuff set by os161.config.mk will +# get lost and bad things will happen. +# +# Because we only build static libs, we can't use and don't need +# LDFLAGS, LIBS, or LIBDEPS. (Shared libs would want these.) +# + +LIBDIR?=/lib + +_LIB_=lib$(LIB).a + +# We may want these directories created. (Used by os161.baserules.mk.) +MKDIRS+=$(MYBUILDDIR) +MKDIRS+=$(INSTALLTOP)$(LIBDIR) +MKDIRS+=$(OSTREE)$(LIBDIR) + +# Default rule: create the program. +# (In make the first rule found is the default.) +all: all-local +all-local: $(MYBUILDDIR) .WAIT $(MYBUILDDIR)/$(_LIB_) + +# Now get rules to compile the SRCS. +.include "$(TOP)/mk/os161.compile.mk" + +# Further rules for libraries. + +# +# Install: we can install into either $(INSTALLTOP) or $(OSTREE). +# When building the whole system, we always install into the staging +# area. We provide the same direct install that os161.prog.mk +# provides; however, because it this doesn't relink anything using the +# library it generally isn't a very useful thing to do. Hence the +# warning. +# +# Note that we make a hard link instead of a copy by default to reduce +# overhead. +# +install-staging-local: $(INSTALLTOP)$(LIBDIR) .WAIT $(INSTALLTOP)$(LIBDIR)/$(_LIB_) +$(INSTALLTOP)$(LIBDIR)/$(_LIB_): $(MYBUILDDIR)/$(_LIB_) + rm -f $(.TARGET) + ln $(MYBUILDDIR)/$(_LIB_) $(.TARGET) || \ + cp $(MYBUILDDIR)/$(_LIB_) $(.TARGET) + +install-local: $(OSTREE)$(LIBDIR) $(MYBUILDDIR)/$(_LIB_) + @echo "Warning: manually installing library without relinking anything" + rm -f $(OSTREE)$(LIBDIR)/$(_LIB_) + ln $(MYBUILDDIR)/$(_LIB_) $(OSTREE)$(LIBDIR)/$(_LIB_) || \ + cp $(MYBUILDDIR)/$(_LIB_) $(OSTREE)$(LIBDIR)/$(_LIB_) + +# Build the library. +$(MYBUILDDIR)/$(_LIB_): $(OBJS) + rm -f $(.TARGET) + $(AR) -cq $(.TARGET) $(OBJS) + $(RANLIB) $(.TARGET) + +# Mark targets that don't represent files PHONY, to prevent various +# lossage if files by those names appear. +.PHONY: all all-local install-staging-local install-local + +# Finally, get the shared definitions for the most basic rules. +.include "$(TOP)/mk/os161.baserules.mk" + +# End. diff --git a/mk/os161.man.mk b/mk/os161.man.mk new file mode 100644 index 0000000..0e3590a --- /dev/null +++ b/mk/os161.man.mk @@ -0,0 +1,69 @@ +# +# OS/161 build environment: install man pages +# +# Usage: +# TOP=../.. +# .include "$(TOP)/mk/os161.config.mk" +# [defs go here] +# .include "$(TOP)/mk/os161.man.mk" +# [any extra rules go here] +# +# Variables controlling this file: +# +# MANFILES Files to install. +# +# MANDIR Directory under $(OSTREE) to install into, +# e.g. /man/bin. Should have a leading slash. +# + +# We may want these directories created. (Used by os161.baserules.mk.) +# We don't use the build directory because we don't currently generate +# anything for man pages. +#MKDIRS+=$(MYBUILDDIR) +MKDIRS+=$(INSTALLTOP)$(MANDIR) +MKDIRS+=$(OSTREE)$(MANDIR) + +# Default rule: do nothing. +# (In make the first rule found is the default.) +all: all-local +all-local: ; + +# +# Install: we can install into either $(INSTALLTOP) or $(OSTREE). +# When building the whole system, we always install into the staging +# area. However, if you're working on a particular program it is +# usually convenient to be able to install it directly to $(OSTREE) +# instead of doing a complete top-level install. +# +# Note that we make a hard link instead of a copy by default to reduce +# overhead. +# +install-staging-local: $(INSTALLTOP)$(MANDIR) .WAIT + +.for _F_ in $(MANFILES) +install-staging-local: $(INSTALLTOP)$(MANDIR)/$(_F_) +$(INSTALLTOP)$(MANDIR)/$(_F_): $(_F_) + rm -f $(.TARGET) + ln $(_F_) $(.TARGET) || cp $(_F_) $(.TARGET) +.endfor + +install-local: $(OSTREE)$(MANDIR) .WAIT installmanpages +installmanpages: +.for _F_ in $(MANFILES) + rm -f $(OSTREE)$(MANDIR)/$(_F_) + ln $(_F_) $(OSTREE)$(MANDIR)/$(_F_) || \ + cp $(_F_) $(OSTREE)$(MANDIR)/$(_F_) +.endfor + +# clean: remove build products (nothing to do) +clean-local: ; + +# Mark targets that don't represent files PHONY, to prevent various +# lossage if files by those names appear. +.PHONY: all all-local install-staging-local install-local installmanpages +.PHONY: clean-local + +# Finally, get the shared definitions for the most basic rules. +.include "$(TOP)/mk/os161.baserules.mk" + +# End. diff --git a/mk/os161.mkdirs.mk b/mk/os161.mkdirs.mk new file mode 100644 index 0000000..370eb87 --- /dev/null +++ b/mk/os161.mkdirs.mk @@ -0,0 +1,59 @@ +# +# OS/161 build environment: MKDIRS logic +# +# This generates rules for all intermediate directories as well as +# the directories listed. (That is, if you say MKDIRS=/usr/bin/foo +# you get rules for /usr and /usr/bin as well as /usr/bin/foo.) +# + +# Variable for complete list of dirs. Start empty. +_MKDIRS_= + +# For each dir in the list... +.for _DIR_ in $(MKDIRS) + +# +# Initialize some temporaries. +# _HEAD_ contains / if the path was absolute. +# _INCR_DIR_ accumulates the full directory name incrementally. +# +# Use := to force full evaluation of the RHS of each expression while +# still in the loop, instead of when the variables are used later. +# +_HEAD_:=$(_DIR_:M/*:C/..*/\//) +_INCR_DIR_:= + +# For each component in the directory, split on slashes... +.for _COMPONENT_ in $(_DIR_:S/\// /g) + +# Add the component to _INCR_DIR_. +_INCR_DIR_:=$(_INCR_DIR_)$(_COMPONENT_)/ + +# Add the current partial directory to the main list. +# Lose the trailing slash. +_MKDIRS_:=$(_MKDIRS_) $(_HEAD_)$(_INCR_DIR_:S/\/$//) + +.endfor # _COMPONENT_ +.endfor # _DIR_ + +# +# Now issue a rule for each directory in the expanded list, +# ordering and uniquifying it. +# +# XXX use /dev/null to suppress curious messages like "../../.. is up +# to date". This scheme probably ought to be reworked. +# +.for _DIR_ in $(_MKDIRS_:O:u) +.if !target($(_DIR_)) +$(_DIR_): +.for _PRE_ in $(_DIR_:M*/*:H:N..) + @$(MAKE) $(_PRE_) >/dev/null 2>&1 || true +.endfor + mkdir $(_DIR_) || true +.endif +.endfor + +# Clear MKDIRS in case we're included again. +MKDIRS= + +# End. diff --git a/mk/os161.prog.mk b/mk/os161.prog.mk new file mode 100644 index 0000000..96876c5 --- /dev/null +++ b/mk/os161.prog.mk @@ -0,0 +1,85 @@ +# +# OS/161 build environment: build a program +# +# Usage: +# TOP=../.. +# .include "$(TOP)/mk/os161.config.mk" +# [defs go here] +# .include "$(TOP)/mk/os161.prog.mk" +# [any extra rules go here] +# +# Variables controlling this file: +# +# PROG Name of program to generate. +# SRCS .c and .S files to compile. +# +# CFLAGS Compile flags. +# LDFLAGS Link flags. +# LIBS Libraries to link with. +# LIBDEPS Full paths of LIBS for depending on. +# +# BINDIR Directory under $(OSTREE) to install into, +# e.g. /bin. Should have a leading slash. +# +# Note that individual program makefiles should only *append* to +# CFLAGS, LDFLAGS, LIBS, and LIBDEPS, not assign them. Otherwise stuff +# set by os161.config.mk will get lost and bad things will happen. +# + +BINDIR?=/bin + +# We may want these directories created. (Used by os161.baserules.mk.) +MKDIRS+=$(MYBUILDDIR) +MKDIRS+=$(INSTALLTOP)$(BINDIR) +MKDIRS+=$(OSTREE)$(BINDIR) + +# Default rule: create the program. +# (In make the first rule found is the default.) +all: all-local +all-local: $(MYBUILDDIR) .WAIT $(MYBUILDDIR)/$(PROG) + +# Now get rules to compile the SRCS. +.include "$(TOP)/mk/os161.compile.mk" + +# Further rules for programs. + +# Clean: delete extraneous files. +clean-local: cleanprog +cleanprog: + rm -f $(MYBUILDDIR)/$(PROG) + +# +# Install: we can install into either $(INSTALLTOP) or $(OSTREE). +# When building the whole system, we always install into the staging +# area. However, if you're working on a particular program it is +# usually convenient to be able to install it directly to $(OSTREE) +# instead of doing a complete top-level install. +# +# Note that we make a hard link instead of a copy by default to reduce +# overhead. +# +install-staging-local: $(INSTALLTOP)$(BINDIR) .WAIT $(INSTALLTOP)$(BINDIR)/$(PROG) +$(INSTALLTOP)$(BINDIR)/$(PROG): $(MYBUILDDIR)/$(PROG) + rm -f $(.TARGET) + ln $(MYBUILDDIR)/$(PROG) $(.TARGET) || \ + cp $(MYBUILDDIR)/$(PROG) $(.TARGET) + +install-local: install-prog +install-prog: $(OSTREE)$(BINDIR) $(MYBUILDDIR)/$(PROG) + rm -f $(OSTREE)$(BINDIR)/$(PROG) + ln $(MYBUILDDIR)/$(PROG) $(OSTREE)$(BINDIR)/$(PROG) || \ + cp $(MYBUILDDIR)/$(PROG) $(OSTREE)$(BINDIR)/$(PROG) + +# Link the program. +$(MYBUILDDIR)/$(PROG): $(OBJS) $(LIBDEPS) + $(LDCC) $(LDFLAGS) $(OBJS) $(LIBS) $(MORELIBS) -o $(.TARGET) + +# Mark targets that don't represent files PHONY, to prevent various +# lossage if files by those names appear. +.PHONY: all all-local clean cleanprog install-staging-local +.PHONY: install-local install-prog + +# Finally, get the shared definitions for the most basic rules. +.include "$(TOP)/mk/os161.baserules.mk" + +# End. diff --git a/mk/os161.script.mk b/mk/os161.script.mk new file mode 100644 index 0000000..6d579c8 --- /dev/null +++ b/mk/os161.script.mk @@ -0,0 +1,92 @@ +# +# OS/161 build environment: install scripts +# +# Usage: +# TOP=../.. +# .include "$(TOP)/mk/os161.config.mk" +# [defs go here] +# .include "$(TOP)/mk/os161.man.mk" +# [any extra rules go here] +# +# Variables controlling this file: +# +# EXECSCRIPTS Executable files to install. +# NONEXECSCRIPTS Non-executable files to install. +# +# SCRIPTDIR Directory under $(OSTREE) to install into, +# e.g. /hostbin. Should have a leading slash. +# + +ALLSCRIPTS=$(NONEXECSCRIPTS) + +# We may want these directories created. (Used by os161.baserules.mk.) +MKDIRS+=$(MYBUILDDIR) +MKDIRS+=$(INSTALLTOP)$(SCRIPTDIR) +MKDIRS+=$(OSTREE)$(SCRIPTDIR) + +# Default rule: "build" the executable scripts. This sets the hash-bang +# header with the interpreter path. +# (In make the first rule found is the default.) +all: all-local +all-local: $(MYBUILDDIR) .WAIT +.for S in $(EXECSCRIPTS) +ALLSCRIPTS+=$(MYBUILDDIR)/$(S) +all-local: $(MYBUILDDIR)/$(S) +$(MYBUILDDIR)/$(S): $(S) +# This must test $@, or assign another variable; it can't test $(S). +# (This is a bmake bug.) +.if !empty(@:M*.py) + echo '#!'"$(PYTHON_INTERPRETER)" > $@.new +.else + sed -n -e '1p' < $(S) > $@.new +.endif + sed -e '1d' < $(S) >> $@.new + chmod 755 $@.new + mv -f $@.new $@ +.endfor + +# depend doesn't need to do anything +depend-local: ; + +# +# Install: we can install into either $(INSTALLTOP) or $(OSTREE). +# When building the whole system, we always install into the staging +# area. However, if you're working on a particular program it is +# usually convenient to be able to install it directly to $(OSTREE) +# instead of doing a complete top-level install. +# +# Note that we make a hard link instead of a copy by default to reduce +# overhead. +# +install-staging-local: $(INSTALLTOP)$(SCRIPTDIR) .WAIT + +.for _F_ in $(ALLSCRIPTS) +install-staging-local: $(INSTALLTOP)$(SCRIPTDIR)/$(_F_:T) +$(INSTALLTOP)$(SCRIPTDIR)/$(_F_:T): $(_F_) + rm -f $(.TARGET) + ln $(_F_) $(.TARGET) || cp $(_F_) $(.TARGET) +.endfor + +install-local: $(OSTREE)$(SCRIPTDIR) .WAIT installscripts +installscripts: +.for _F_ in $(ALLSCRIPTS) + rm -f $(OSTREE)$(SCRIPTDIR)/$(_F_:T) + ln $(_F_) $(OSTREE)$(SCRIPTDIR)/$(_F_:T) || \ + cp $(_F_) $(OSTREE)$(SCRIPTDIR)/$(_F_:T) +.endfor + +# clean: remove build products +clean-local: +.for S in $(EXECSCRIPTS) + rm -f $(MYBUILDDIR)/$(S) +.endfor + +# Mark targets that don't represent files PHONY, to prevent various +# lossage if files by those names appear. +.PHONY: all all-local install-staging-local install-local installscripts +.PHONY: clean-local + +# Finally, get the shared definitions for the most basic rules. +.include "$(TOP)/mk/os161.baserules.mk" + +# End. diff --git a/mk/os161.subdir.mk b/mk/os161.subdir.mk new file mode 100644 index 0000000..dada68d --- /dev/null +++ b/mk/os161.subdir.mk @@ -0,0 +1,51 @@ +# +# OS/161 build environment: recurse into subdirectories +# +# Usage: +# TOP=../.. +# .include "$(TOP)/mk/os161.config.mk" +# [defs go here] +# .include "$(TOP)/mk/os161.subdir.mk" +# [any extra rules go here] +# +# Variables controlling this file: +# +# SUBDIRS Directories to recurse into. +# EXTRATARGETS Additional targets to define. +# +# BASETARGETS may also be set to empty to suppress the usual targets. +# +# Note: SUBDIRS may contain .WAIT, which is treated as a parallelism +# barrier like in the right hand side of a make rule. +# +# Further note: if combining os161.subdir.mk with other os161.*.mk +# files (other than os161.config.mk), include os161.subdir.mk first; +# then the ordering of things will cause recursion to happen +# first. Also, .WAIT is inserted so that the recursion will finish +# before anything else happens, which is almost always desirable. +# + +BASETARGETS?=\ + all depend install install-staging clean distclean tags \ + cleandir stage dependall build rebuild fullrebuild + +# first, make each target depend on its -subdirs target, +# and declare both PHONY. +.for _T_ in $(BASETARGETS) $(EXTRATARGETS) +$(_T_): $(_T_)-subdirs .WAIT +.PHONY: $(_T_) $(_T_)-subdirs +.endfor + +# now, make each -subdirs target depend on a rule for each subdir. +.for _D_ in $(SUBDIRS) +.for _T_ in $(BASETARGETS) $(EXTRATARGETS) +.if "$(_D_)" == ".WAIT" +$(_T_)-subdirs: .WAIT +.else +$(_T_)-subdirs: $(_T_)-subdirs-$(_D_) +.PHONY: $(_T_)-subdirs-$(_D_) +$(_T_)-subdirs-$(_D_): + (cd $(_D_) && $(MAKE) $(_T_)) +.endif +.endfor +.endfor diff --git a/testscripts/Makefile b/testscripts/Makefile new file mode 100644 index 0000000..8243e6e --- /dev/null +++ b/testscripts/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for src/testscripts (test driver tools) +# + +TOP=.. +.include "$(TOP)/mk/os161.config.mk" + +SCRIPTDIR=/testscripts +EXECSCRIPTS=test.py +NONEXECSCRIPTS=runtest.py + +.include "$(TOP)/mk/os161.script.mk" diff --git a/testscripts/runtest.py b/testscripts/runtest.py new file mode 100644 index 0000000..852db48 --- /dev/null +++ b/testscripts/runtest.py @@ -0,0 +1,202 @@ +# +# Usage: +# import runtest +# runtest.run(testcommands, outputfile, +# menuprompt=None, default "OS/161 kernel [? for menu]: " +# shellprompt=None, default "OS/161$ " +# conf=None, default is sys161 default behavior +# ram=None, default is per sys161 config +# cpus=None, default is per sys161 config +# doom=None, default is no doom counter +# progress=30, default is 30 seconds +# timeout=300, default is 300 seconds +# kernel=None) default is "kernel" +# +# Returns None on success or a (string) message if something apparently +# went wrong in the middle. (XXX: should it throw exceptions instead?) +# +# * The testcommands argument is a string containing a list of commands +# separated by semicolons. These can be either kernel menu commands +# or shell commands; the command 's' is recognized for switching from +# the menu to the shell and 'exit' for switching back to the menu. +# (This affects waiting for prompts - running the shell via 'p' or +# crashing out of the shell will confuse things.) +# +# The command 'q' from the menu is also recognized as causing a +# shutdown. This will be done automatically after everything else if +# not issued explicitly. +# +# The following commands are interpreted as macros: +# DOMOUNT expands to "mount sfs lhd1:; cd lhd1:" +# DOUNMOUNT expands to "cd /; unmount lhd1:" +# WAIT sleeps 3 seconds and just presses return +# +# * The outputfile argument should be a python file (e.g. sys.stdout) +# and receives a copy of the System/161 output. +# +# * The menuprompt and shellprompt arguments can be used to change the +# menu and shell prompt strings looked for. For the moment these can +# only be fixed strings, not regular expressions. (This is probably +# easy to improve, but I ran into some mysterious problems when I +# tried, so YMMV.) By default if you pass None prompt strings matching +# what OS/161 issues by default are used. +# +# * The conf argument can be used to supply an alternate sys161.conf +# file. If None is given (the default), sys161 will use its default +# config file. +# +# * The ram and cpus arguments can be used to override the RAM size +# and number-of-cpus settings in the sys161 config file. The number of +# cpus must be an integer, but any RAM size specification understood +# by sys161 can be used. Note: this feature requires System/161 2.0.5 +# or higher. +# +# * The doom argument can be used to set the doom counter. If None is +# given (the default) the doom counter is not engaged. +# +# * The progress and timeout arguments can be used to set the timeouts +# for System/161 progress monitoring and pexpect-level global timeout, +# respectively. The defaults (somewhat arbitraily chosen) are 30 and +# 300 seconds. Passing progress=None disables progress monitoring; this +# is necessary for nontrivial tests that run within the kernel, as +# progress monitoring measures userland progress. Passing timeout=None +# probably either disables the global timeout or makes pexpect crash; +# I haven't tested it. I don't recommend trying: it is your defense +# against test runs hanging forever. +# +# Note that no-debugger unattended mode (sys161 -X) is always used. +# The purpose of this script is specifically to support unattended +# test runs... +# +# Depends on pexpect, which you may need to install specifically +# depending on your OS. +# + +import time +import pexpect + +# +# Macro commands +# +macros = { + "MOUNT" : ["mount sfs lhd1:", "cd lhd1:"], + "UNMOUNT" : ["cd /", "unmount lhd1:"], + # "WAIT" special-cased below +} + +# +# Wait for a prompt; returns True if we got it, False if we need to +# bail. +# +def getprompt(proc, prompt): + which = proc.expect_exact([ + prompt, + "panic: ", # panic message + "sys161: No progress in ", # sys161 deadman print + "sys161: Elapsed ", # sys161 shutdown print + pexpect.EOF, + pexpect.TIMEOUT + ]) + if which == 0: + # got the prompt + return None + if which == 1: + proc.expect_exact([pexpect.EOF, pexpect.TIMEOUT]) + return "panic" + if which == 2: + proc.expect_exact([pexpect.EOF, pexpect.TIMEOUT]) + return "progress timeout" + if which == 3: + proc.expect_exact([pexpect.EOF, pexpect.TIMEOUT]) + return "unexpected shutdown" + if which == 4: + return "unexpected end of input" + if which == 5: + return "top-level timeout" + return "runtest: Internal error: pexpect returned out-of-range result" +# end getprompt + +# +# main test function +# +def run(testcommands, outputfile, + menuprompt=None, shellprompt=None, + conf=None, ram=None, cpus=None, + doom=None, + progress=30, timeout=300, + kernel=None): + if menuprompt is None: + menuprompt = "OS/161 kernel [? for menu]: " + if shellprompt is None: + shellprompt = "OS/161$ " + if kernel is None: + kernel = "kernel" + + args = ["-X"] + if conf is not None: + args.append("-c") + args.append(conf) + if cpus is not None: + args.append("-C") + args.append("31:cpus=%d" % cpus) + if doom is not None: + args.append("-D") + args.append("%d" % doom) + if progress is not None: + args.append("-Z") + args.append("%d" % progress) + if ram is not None: + args.append("-C") + args.append("31:ramsize=%s" % ram) + args.append(kernel) + + proc = pexpect.spawn("sys161", args, timeout=timeout, + ignore_sighup=False) + proc.logfile_read = outputfile + + commands = [s.strip() for s in testcommands.split(";")] + commands = [macros[c] if c in macros else [c] for c in commands] + # Apparently list flatten() is unpythonic... + commands = [c for sublist in commands for c in sublist] + + prompts = { True: shellprompt, False: menuprompt } + inshell = False + quit = False + for cmd in commands: + msg = getprompt(proc, prompts[inshell]) + if msg is not None: + return msg + if cmd == "WAIT": + time.sleep(3) + cmd = "" + proc.send("%s\r" % cmd) + if not inshell and cmd == "q": + quit = True + if not inshell and cmd == "s": + inshell = True + if inshell and cmd == "exit": + inshell = False + if not quit: + if inshell: + msg = getprompt(proc, prompts[inshell]) + if msg is not None: + return msg + proc.send("exit\r") + inshell = False + msg = getprompt(proc, prompts[inshell]) + if msg is not None: + return msg + proc.send("q\r") + quit = True + + proc.expect_exact([pexpect.EOF, pexpect.TIMEOUT]) + + # Apparently if you call pexpect.wait() you must have + # explicitly read all the input, or it hangs; and the process + # can't be already dead, or it crashes. Therefore it appears + # to be entirely useless. I hope not calling it doesn't cause + # zombies to accumulate. + #proc.wait() + + return None +# end run diff --git a/testscripts/test.py b/testscripts/test.py new file mode 100755 index 0000000..619c7d5 --- /dev/null +++ b/testscripts/test.py @@ -0,0 +1,113 @@ +#!/usr/pkg/bin/python2.7 +# test.py - run some test material +# usage: auto/test.py [options] test-commands +# options: +# --menuprompt=STR Change menu prompt string +# --shellprompt=STR Change shell prompt string +# --conf=sys161.conf Use alternate sys161 config +# --ram=N Force RAM size (default from sys161 config) +# --cpus=N Force number of cpus (default from sys161 config) +# --doom=N Set doom counter to N (default none) +# --progress=N Progress monitoring with N-second timeout (default 30) +# --no-progress Disable progress monitoring +# --timeout=N Global timeout, in seconds (default 300) +# --kernel=KERNEL Choose kernel to run (default "kernel") +# +# +# This is a directly executable wrapper around runtest.py. You can use +# it from the host OS shell to run more or less arbitrary scripts, or +# you can write your own Python scripts using runtest.py directly. +# +# See the top of runtest.py for an explanation of the arguments. +# + +import sys +from optparse import OptionParser + +import runtest + +############################################################ +# global settings + +g_doom = None +g_conf = None +g_cpus = None +g_kernel = None +g_menuprompt = None +g_progress = 30 +g_ram = None +g_shellprompt = None +g_timeout = 300 + +############################################################ +# main + +def getargs(): + global g_menuprompt + global g_shellprompt + global g_ram + global g_conf + global g_cpus + global g_doom + global g_progress + global g_timeout + global g_kernel + + # XXX is there no better scheme for this? + p = OptionParser() + + # grr -h is hardwired + p.add_option("-c", "--conf", dest="conf") + p.add_option("-D", "--doom", dest="doom") + p.add_option("-j", "--cpus", dest="cpus") + p.add_option("-k", "--kernel", dest="kernel") + p.add_option("-m", "--menuprompt", dest="menuprompt") + p.add_option("-r", "--ram", dest="ram") + p.add_option("-s", "--shellprompt", dest="shellprompt") + p.add_option("-t", "--timeout", dest="timeout") + p.add_option("-z", "--no-progress", dest="no_progress") + p.add_option("-Z", "--progress", dest="progress") + + (options, args) = p.parse_args() + if options.menuprompt is not None: + g_menuprompt = options.menuprompt + if options.shellprompt is not None: + g_shellprompt = options.shellprompt + if options.conf is not None: + g_conf = options.conf + if options.ram is not None: + g_ram = options.ram + if options.cpus is not None: + g_cpus = int(options.cpus) + if options.doom is not None: + g_doom = int(options.doom) + if options.progress is not None: + g_progress = int(options.progress) + if options.no_progress is not None: + g_progress = None + if options.timeout is not None: + g_timeout = int(options.timeout) + if options.kernel is not None: + g_kernel = options.kernel + + if len(args) != 1: + sys.stderr.write("Usage: test.py [options] test-commands\n") + exit(1) + return args[0] +# end getargs + +testcommands = getargs() +msg = runtest.run(testcommands, + sys.stdout, + menuprompt=g_menuprompt, + shellprompt=g_shellprompt, + conf=g_conf, + ram=g_ram, + cpus=g_cpus, + doom=g_doom, + progress=g_progress, + timeout=g_timeout, + kernel=g_kernel) +if msg is not None: + sys.stderr.write("test.py: test commands aborted with %s\n" % msg) +exit(0) diff --git a/userland/Makefile b/userland/Makefile new file mode 100644 index 0000000..0ad87da --- /dev/null +++ b/userland/Makefile @@ -0,0 +1,28 @@ +# +# Toplevel userland makefile for OS/161. +# + +TOP=.. +.include "$(TOP)/mk/os161.config.mk" + +# lib must be first. +SUBDIRS=lib .WAIT bin sbin testbin + +INCLUDES=\ + include include \ + include/sys include/sys \ + include/test include/test \ + include/types include/types + +INCLUDELINKS=\ + kern/machine include/machine \ + $(MACHINE) include/kern/machine + +.include "$(TOP)/mk/os161.subdir.mk" +.include "$(TOP)/mk/os161.includes.mk" + +includes: hostincludes +hostincludes: + (cd lib/hostcompat && $(MAKE) includes) + +.PHONY: includes hostincludes diff --git a/userland/bin/Makefile b/userland/bin/Makefile new file mode 100644 index 0000000..ee13626 --- /dev/null +++ b/userland/bin/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for src/bin (sources for programs installed in /bin) +# + +TOP=../.. +.include "$(TOP)/mk/os161.config.mk" + +SUBDIRS=true false sync mkdir rmdir pwd cat cp ln mv rm ls sh tac + +.include "$(TOP)/mk/os161.subdir.mk" diff --git a/userland/bin/cat/Makefile b/userland/bin/cat/Makefile new file mode 100644 index 0000000..e11daac --- /dev/null +++ b/userland/bin/cat/Makefile @@ -0,0 +1,12 @@ +# Makefile for cat + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=cat +SRCS=cat.c +BINDIR=/bin + + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/bin/cat/cat.c b/userland/bin/cat/cat.c new file mode 100644 index 0000000..3415eff --- /dev/null +++ b/userland/bin/cat/cat.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +/* + * cat - concatenate and print + * Usage: cat [files] + */ + + + +/* Print a file that's already been opened. */ +static +void +docat(const char *name, int fd) +{ + char buf[1024]; + int len, wr, wrtot; + + /* + * As long as we get more than zero bytes, we haven't hit EOF. + * Zero means EOF. Less than zero means an error occurred. + * We may read less than we asked for, though, in various cases + * for various reasons. + */ + while ((len = read(fd, buf, sizeof(buf)))>0) { + /* + * Likewise, we may actually write less than we attempted + * to. So loop until we're done. + */ + wrtot = 0; + while (wrtot < len) { + wr = write(STDOUT_FILENO, buf+wrtot, len-wrtot); + if (wr<0) { + err(1, "stdout"); + } + wrtot += wr; + } + } + /* + * If we got a read error, print it and exit. + */ + if (len<0) { + err(1, "%s", name); + } +} + +/* Print a file by name. */ +static +void +cat(const char *file) +{ + int fd; + + /* + * "-" means print stdin. + */ + if (!strcmp(file, "-")) { + docat("stdin", STDIN_FILENO); + return; + } + + /* + * Open the file, print it, and close it. + * Bail out if we can't open it. + */ + fd = open(file, O_RDONLY); + if (fd<0) { + err(1, "%s", file); + } + docat(file, fd); + close(fd); +} + + +int +main(int argc, char *argv[]) +{ + if (argc==1) { + /* No args - just do stdin */ + docat("stdin", STDIN_FILENO); + } + else { + /* Print all the files specified on the command line. */ + int i; + for (i=1; i +#include + +/* + * cp - copy a file. + * Usage: cp oldfile newfile + */ + + +/* Copy one file to another. */ +static +void +copy(const char *from, const char *to) +{ + int fromfd; + int tofd; + char buf[1024]; + int len, wr, wrtot; + + /* + * Open the files, and give up if they won't open + */ + fromfd = open(from, O_RDONLY); + if (fromfd<0) { + err(1, "%s", from); + } + tofd = open(to, O_WRONLY|O_CREAT|O_TRUNC); + if (tofd<0) { + err(1, "%s", to); + } + + /* + * As long as we get more than zero bytes, we haven't hit EOF. + * Zero means EOF. Less than zero means an error occurred. + * We may read less than we asked for, though, in various cases + * for various reasons. + */ + while ((len = read(fromfd, buf, sizeof(buf)))>0) { + /* + * Likewise, we may actually write less than we attempted + * to. So loop until we're done. + */ + wrtot = 0; + while (wrtot < len) { + wr = write(tofd, buf+wrtot, len-wrtot); + if (wr<0) { + err(1, "%s", to); + } + wrtot += wr; + } + } + /* + * If we got a read error, print it and exit. + */ + if (len<0) { + err(1, "%s", from); + } + + if (close(fromfd) < 0) { + err(1, "%s: close", from); + } + + if (close(tofd) < 0) { + err(1, "%s: close", to); + } +} + +int +main(int argc, char *argv[]) +{ + /* + * Just do it. + * + * We don't allow the Unix model where you can do + * cp file1 file2 file3 destination-directory + * + * although this would be pretty easy to add. + */ + if (argc!=3) { + errx(1, "Usage: cp OLDFILE NEWFILE"); + } + copy(argv[1], argv[2]); + return 0; +} diff --git a/userland/bin/false/Makefile b/userland/bin/false/Makefile new file mode 100644 index 0000000..faaa104 --- /dev/null +++ b/userland/bin/false/Makefile @@ -0,0 +1,12 @@ +# Makefile for false + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=false +SRCS=false.c +BINDIR=/bin + + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/bin/false/false.c b/userland/bin/false/false.c new file mode 100644 index 0000000..8b01304 --- /dev/null +++ b/userland/bin/false/false.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * false - fail. + * + * "All software sucks. Ok, so maybe /bin/true doesn't. But /bin/false + * sure does - it fails all the time." + */ + +int +main(void) +{ + /* Just exit with a failure code. */ + exit(1); +} diff --git a/userland/bin/ln/Makefile b/userland/bin/ln/Makefile new file mode 100644 index 0000000..f6154b0 --- /dev/null +++ b/userland/bin/ln/Makefile @@ -0,0 +1,12 @@ +# Makefile for ln + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=ln +SRCS=ln.c +BINDIR=/bin + + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/bin/ln/ln.c b/userland/bin/ln/ln.c new file mode 100644 index 0000000..8d488e5 --- /dev/null +++ b/userland/bin/ln/ln.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +/* + * ln - hardlink or symlink files + * + * Usage: ln oldfile newfile + * ln -s symlinkcontents symlinkfile + */ + + +/* + * Create a symlink with filename PATH that contains text TEXT. + * When fed to ls -l, this produces something that looks like + * + * lrwxrwxrwx [stuff] PATH -> TEXT + */ +static +void +dosymlink(const char *text, const char *path) +{ + if (symlink(text, path)) { + err(1, "%s", path); + } +} + +/* + * Create a hard link such that NEWFILE names the same file as + * OLDFILE. Since it's a hard link, the two names for the file + * are equal; both are the "real" file. + */ +static +void +dohardlink(const char *oldfile, const char *newfile) +{ + if (link(oldfile, newfile)) { + err(1, "%s or %s", oldfile, newfile); + exit(1); + } +} + +int +main(int argc, char *argv[]) +{ + /* + * Just do whatever was asked for. + * + * We don't allow the Unix model where you can do + * ln [-s] file1 file2 file3 destination-directory + */ + if (argc==4 && !strcmp(argv[1], "-s")) { + dosymlink(argv[2], argv[3]); + } + else if (argc==3) { + dohardlink(argv[1], argv[2]); + } + else { + warnx("Usage: ln oldfile newfile"); + errx(1, " ln -s symlinkcontents symlinkfile\n"); + } + return 0; +} diff --git a/userland/bin/ls/Makefile b/userland/bin/ls/Makefile new file mode 100644 index 0000000..fccea90 --- /dev/null +++ b/userland/bin/ls/Makefile @@ -0,0 +1,12 @@ +# Makefile for ls + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=ls +SRCS=ls.c +BINDIR=/bin + + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/bin/ls/ls.c b/userland/bin/ls/ls.c new file mode 100644 index 0000000..2041bc8 --- /dev/null +++ b/userland/bin/ls/ls.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * ls - list files. + * Usage: ls [-adlRs] [files] + * -a Show files whose names begin with a dot. + * -d Don't list contents of directories specified on the command line. + * -l Long format listing. + * -R Recurse into subdirectories found. + * -s (with -l) Show block counts. + */ + +/* Flags for which options we're using. */ +static int aopt=0; +static int dopt=0; +static int lopt=0; +static int Ropt=0; +static int sopt=0; + +/* Process an option character. */ +static +void +option(int ch) +{ + switch (ch) { + case 'a': aopt=1; break; + case 'd': dopt=1; break; + case 'l': lopt=1; break; + case 'R': Ropt=1; break; + case 's': sopt=1; break; + default: + errx(1, "Unknown option -%c", ch); + } +} + +/* + * Utility function to find the non-directory part of a pathname. + */ +static +const char * +basename(const char *path) +{ + const char *s; + + s = strrchr(path, '/'); + if (s) { + return s+1; + } + return path; +} + +/* + * Utility function to check if a name refers to a directory. + */ +static +int +isdir(const char *path) +{ + struct stat buf; + int fd; + + /* Assume stat() may not be implemented; use fstat */ + fd = open(path, O_RDONLY); + if (fd<0) { + err(1, "%s", path); + } + if (fstat(fd, &buf)<0) { + err(1, "%s: fstat", path); + } + close(fd); + + return S_ISDIR(buf.st_mode); +} + +/* + * When listing one of several subdirectories, show the name of the + * directory. + */ +static +void +printheader(const char *file) +{ + /* No blank line before the first header */ + static int first=1; + if (first) { + first = 0; + } + else { + printf("\n"); + } + printf("%s:\n", file); +} + +/* + * Show a single file. + * We don't do the neat multicolumn listing that Unix ls does. + */ +static +void +print(const char *path) +{ + struct stat statbuf; + const char *file; + int typech; + + if (lopt || sopt) { + int fd; + + fd = open(path, O_RDONLY); + if (fd<0) { + err(1, "%s", path); + } + if (fstat(fd, &statbuf)<0) { + err(1, "%s: fstat", path); + } + close(fd); + } + + file = basename(path); + + if (sopt) { + printf("%3d ", statbuf.st_blocks); + } + + if (lopt) { + if (S_ISREG(statbuf.st_mode)) { + typech = '-'; + } + else if (S_ISDIR(statbuf.st_mode)) { + typech = 'd'; + } + else if (S_ISLNK(statbuf.st_mode)) { + typech = 'l'; + } + else if (S_ISCHR(statbuf.st_mode)) { + typech = 'c'; + } + else if (S_ISBLK(statbuf.st_mode)) { + typech = 'b'; + } + else { + typech = '?'; + } + + printf("%crwx------ %2d root %-7llu ", + typech, + statbuf.st_nlink, + statbuf.st_size); + } + printf("%s\n", file); +} + +/* + * List a directory. + */ +static +void +listdir(const char *path, int showheader) +{ + int fd; + char buf[1024]; + char newpath[1024]; + ssize_t len; + + if (showheader) { + printheader(path); + } + + /* + * Open it. + */ + fd = open(path, O_RDONLY); + if (fd<0) { + err(1, "%s", path); + } + + /* + * List the directory. + */ + while ((len = getdirentry(fd, buf, sizeof(buf)-1)) > 0) { + buf[len] = 0; + + /* Assemble the full name of the new item */ + snprintf(newpath, sizeof(newpath), "%s/%s", path, buf); + + if (aopt || buf[0]!='.') { + /* Print it */ + print(newpath); + } + } + if (len<0) { + err(1, "%s: getdirentry", path); + } + + /* Done */ + close(fd); +} + +static +void +recursedir(const char *path) +{ + int fd; + char buf[1024]; + char newpath[1024]; + int len; + + /* + * Open it. + */ + fd = open(path, O_RDONLY); + if (fd<0) { + err(1, "%s", path); + } + + /* + * List the directory. + */ + while ((len = getdirentry(fd, buf, sizeof(buf)-1)) > 0) { + buf[len] = 0; + + /* Assemble the full name of the new item */ + snprintf(newpath, sizeof(newpath), "%s/%s", path, buf); + + if (!aopt && buf[0]=='.') { + /* skip this one */ + continue; + } + + if (!strcmp(buf, ".") || !strcmp(buf, "..")) { + /* always skip these */ + continue; + } + + if (!isdir(newpath)) { + continue; + } + + listdir(newpath, 1 /*showheader*/); + if (Ropt) { + recursedir(newpath); + } + } + if (len<0) { + err(1, "%s", path); + } + + close(fd); +} + +static +void +listitem(const char *path, int showheader) +{ + if (!dopt && isdir(path)) { + listdir(path, showheader || Ropt); + if (Ropt) { + recursedir(path); + } + } + else { + print(path); + } +} + +int +main(int argc, char *argv[]) +{ + int i,j, items=0; + + /* + * Go through the arguments and count how many non-option args. + */ + for (i=1; i1); + } + } + + /* + * If no filenames were specified to list, list the current + * directory. + */ + if (items==0) { + listitem(".", 0); + } + + return 0; +} diff --git a/userland/bin/mkdir/Makefile b/userland/bin/mkdir/Makefile new file mode 100644 index 0000000..efa3cfa --- /dev/null +++ b/userland/bin/mkdir/Makefile @@ -0,0 +1,12 @@ +# Makefile for mkdir + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=mkdir +SRCS=mkdir.c +BINDIR=/bin + + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/bin/mkdir/mkdir.c b/userland/bin/mkdir/mkdir.c new file mode 100644 index 0000000..c0a7e9e --- /dev/null +++ b/userland/bin/mkdir/mkdir.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +/* + * mkdir - create a directory. + * Usage: mkdir DIRECTORY + * + * Just calls the mkdir() system call. + */ + +int +main(int argc, char *argv[]) +{ + if (argc!=2) { + errx(1, "Usage: mkdir DIRECTORY"); + } + + if (mkdir(argv[1], 0775)) { + err(1, "%s", argv[1]); + } + return 0; +} diff --git a/userland/bin/mv/Makefile b/userland/bin/mv/Makefile new file mode 100644 index 0000000..89fe396 --- /dev/null +++ b/userland/bin/mv/Makefile @@ -0,0 +1,12 @@ +# Makefile for mv + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=mv +SRCS=mv.c +BINDIR=/bin + + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/bin/mv/mv.c b/userland/bin/mv/mv.c new file mode 100644 index 0000000..2705140 --- /dev/null +++ b/userland/bin/mv/mv.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * mv - move (rename) files. + * Usage: mv oldfile newfile + * + * Just calls rename() on them. If it fails, we don't attempt to + * figure out which filename was wrong or what happened. + * + * In certain circumstances, Unix mv will fall back to copying and + * deleting the old copy. We don't do that. + * + * We also don't allow the Unix form of + * mv file1 file2 file3 destination-dir + */ + +static +void +dorename(const char *oldfile, const char *newfile) +{ + if (rename(oldfile, newfile)) { + err(1, "%s or %s", oldfile, newfile); + } +} + +int +main(int argc, char *argv[]) +{ + if (argc!=3) { + errx(1, "Usage: mv oldfile newfile"); + } + dorename(argv[1], argv[2]); + return 0; +} diff --git a/userland/bin/pwd/Makefile b/userland/bin/pwd/Makefile new file mode 100644 index 0000000..950918d --- /dev/null +++ b/userland/bin/pwd/Makefile @@ -0,0 +1,12 @@ +# Makefile for pwd + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=pwd +SRCS=pwd.c +BINDIR=/bin + + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/bin/pwd/pwd.c b/userland/bin/pwd/pwd.c new file mode 100644 index 0000000..b7e1604 --- /dev/null +++ b/userland/bin/pwd/pwd.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +/* + * pwd - print working directory. + * Usage: pwd + * + * Just uses the getcwd library call (which in turn uses the __getcwd + * system call.) + */ + +int +main(void) +{ + char buf[PATH_MAX+1], *p; + + p = getcwd(buf, sizeof(buf)); + if (p == NULL) { + err(1, "."); + } + printf("%s\n", buf); + return 0; +} diff --git a/userland/bin/rm/Makefile b/userland/bin/rm/Makefile new file mode 100644 index 0000000..eb3abd8 --- /dev/null +++ b/userland/bin/rm/Makefile @@ -0,0 +1,12 @@ +# Makefile for rm + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=rm +SRCS=rm.c +BINDIR=/bin + + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/bin/rm/rm.c b/userland/bin/rm/rm.c new file mode 100644 index 0000000..feb2515 --- /dev/null +++ b/userland/bin/rm/rm.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * rm - remove (delete) files + * Usage: rm file... + */ + +/* Delete a single file. */ +static +void +doremove(const char *file) +{ + if (remove(file)) { + err(1, "%s", file); + } +} + +int +main(int argc, char *argv[]) +{ + int i; + + if (argc<2) { + /* Must have at least one file. */ + errx(1, "Usage: rm FILES"); + } + + /* Just delete everything on the command line. */ + for (i=1; i +#include + +/* + * rmdir - remove a directory + * Usage: rmdir DIRECTORY + * + * Just calls the rmdir() system call. + */ + +int +main(int argc, char *argv[]) +{ + if (argc!=2) { + errx(1, "Usage: rmdir DIRECTORY"); + } + + if (rmdir(argv[1])) { + err(1, "%s", argv[1]); + } + return 0; +} diff --git a/userland/bin/sh/Makefile b/userland/bin/sh/Makefile new file mode 100644 index 0000000..aa932b2 --- /dev/null +++ b/userland/bin/sh/Makefile @@ -0,0 +1,13 @@ +# Makefile for sh + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=sh +SRCS=sh.c +BINDIR=/bin +HOSTBINDIR=/hostbin + + +.include "$(TOP)/mk/os161.prog.mk" +#.include "$(TOP)/mk/os161.hostprog.mk" diff --git a/userland/bin/sh/sh.c b/userland/bin/sh/sh.c new file mode 100644 index 0000000..2b9819f --- /dev/null +++ b/userland/bin/sh/sh.c @@ -0,0 +1,591 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * sh - shell + * + * Usage: + * sh + * sh -c command + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HOST +#include "hostcompat.h" +#endif + +#ifndef NARG_MAX +/* no NARG_MAX on most unixes */ +#define NARG_MAX 1024 +#endif + +/* avoid making this unreasonably large; causes problems under dumbvm */ +#define CMDLINE_MAX 4096 + +/* struct to (portably) hold exit info */ +struct exitinfo { + unsigned val:8, + signaled:1, + stopped:1, + coredump:1; +}; + +/* set to nonzero if __time syscall seems to work */ +static int timing = 0; + +/* array of backgrounded jobs (allows "foregrounding") */ +#define MAXBG 128 +static pid_t bgpids[MAXBG]; + +/* + * can_bg + * just checks for an open slot. + */ +static +int +can_bg(void) +{ + int i; + + for (i = 0; i < MAXBG; i++) { + if (bgpids[i] == 0) { + return 1; + } + } + + return 0; +} + +/* + * remember_bg + * sticks the pid in an open slot in the background array. note the assert -- + * better check can_bg before calling this. + */ +static +void +remember_bg(pid_t pid) +{ + int i; + for (i = 0; i < MAXBG; i++) { + if (bgpids[i] == 0) { + bgpids[i] = pid; + return; + } + } + assert(0); +} + +/* + * constructor for exitinfo + */ +static +void +exitinfo_exit(struct exitinfo *ei, int code) +{ + ei->val = code; + ei->signaled = 0; + ei->stopped = 0; + ei->coredump = 0; +} + +/* + * readstatus + * unpack results from wait + */ +static +void +readstatus(int status, struct exitinfo *ei) +{ + if (WIFEXITED(status)) { + ei->val = WEXITSTATUS(status); + ei->signaled = 0; + ei->stopped = 0; + ei->coredump = 0; + } + else if (WIFSIGNALED(status) && WCOREDUMP(status)) { + ei->val = WTERMSIG(status); + ei->signaled = 1; + ei->stopped = 0; + ei->coredump = 1; + } + else if (WIFSIGNALED(status)) { + ei->val = WTERMSIG(status); + ei->signaled = 1; + ei->stopped = 0; + ei->coredump = 0; + } + else if (WIFSTOPPED(status)) { + ei->val = WSTOPSIG(status); + ei->signaled = 0; + ei->stopped = 1; + ei->coredump = 0; + } + else { + printf("Invalid status code %d", status); + ei->val = status; + ei->signaled = 0; + ei->stopped = 0; + ei->coredump = 0; + } + +} + +/* + * printstatus + * print results from wait + */ +static +void +printstatus(const struct exitinfo *ei, int printexitzero) +{ + if (ei->signaled && ei->coredump) { + printf("Signal %d (core dumped)\n", ei->val); + } + else if (ei->signaled) { + printf("Signal %d\n", ei->val); + } + else if (ei->stopped) { + printf("Stopped on signal %d\n", ei->val); + } + else if (printexitzero || ei->val != 0) { + printf("Exit %d\n", ei->val); + } +} + +/* + * dowait + * just does a waitpid. + */ +static +void +dowait(pid_t pid) +{ + struct exitinfo ei; + int status; + + if (waitpid(pid, &status, 0) < 0) { + warn("pid %d", pid); + } + else { + printf("pid %d: ", pid); + readstatus(status, &ei); + printstatus(&ei, 1); + } +} + +#ifdef WNOHANG +/* + * dowaitpoll + * like dowait, but uses WNOHANG. returns true if we got something. + */ +static +int +dowaitpoll(pid_t pid) +{ + struct exitinfo ei; + pid_t foundpid; + int status; + + foundpid = waitpid(pid, &status, WNOHANG); + if (foundpid < 0) { + warn("pid %d", pid); + } + else if (foundpid != 0) { + printf("pid %d: ", pid); + readstatus(status, &ei); + printstatus(&ei, 1); + return 1; + } + return 0; +} + +/* + * waitpoll + * poll all background jobs for having exited. + */ +static +void +waitpoll(void) +{ + int i; + for (i=0; i < MAXBG; i++) { + if (bgpids[i] != 0) { + if (dowaitpoll(bgpids[i])) { + bgpids[i] = 0; + } + } + } +} +#endif /* WNOHANG */ + +/* + * wait + * allows the user to "foreground" a process by waiting on it. without ps to + * know the pids, this is a little tough to use with an arg, but without an + * arg it will wait for all the background jobs. + */ +static +void +cmd_wait(int ac, char *av[], struct exitinfo *ei) +{ + int i; + pid_t pid; + + if (ac == 2) { + pid = atoi(av[1]); + dowait(pid); + for (i = 0; i < MAXBG; i++) { + if (bgpids[i]==pid) { + bgpids[i] = 0; + } + } + exitinfo_exit(ei, 0); + return; + } + else if (ac == 1) { + for (i=0; i < MAXBG; i++) { + if (bgpids[i] != 0) { + dowait(bgpids[i]); + bgpids[i] = 0; + } + } + exitinfo_exit(ei, 0); + return; + } + printf("Usage: wait [pid]\n"); + exitinfo_exit(ei, 1); +} + +/* + * chdir + * just an interface to the system call. no concept of home directory, so + * require the directory. + */ +static +void +cmd_chdir(int ac, char *av[], struct exitinfo *ei) +{ + if (ac == 2) { + if (chdir(av[1])) { + warn("chdir: %s", av[1]); + exitinfo_exit(ei, 1); + return; + } + exitinfo_exit(ei, 0); + return; + } + printf("Usage: chdir dir\n"); + exitinfo_exit(ei, 1); +} + +/* + * exit + * pretty simple. allow the user to choose the exit code if they want, + * otherwise default to 0 (success). + */ +static +void +cmd_exit(int ac, char *av[], struct exitinfo *ei) +{ + int code; + + if (ac == 1) { + code = 0; + } + else if (ac == 2) { + code = atoi(av[1]); + } + else { + printf("Usage: exit [code]\n"); + exitinfo_exit(ei, 1); + return; + } + + exit(code); +} + +/* + * a struct of the builtins associates the builtin name with the function that + * executes it. they must all take an argc and argv. + */ +static struct { + const char *name; + void (*func)(int, char **, struct exitinfo *); +} builtins[] = { + { "cd", cmd_chdir }, + { "chdir", cmd_chdir }, + { "exit", cmd_exit }, + { "wait", cmd_wait }, + { NULL, NULL } +}; + +/* + * docommand + * tokenizes the command line using strtok. if there aren't any commands, + * simply returns. checks to see if it's a builtin, running it if it is. + * otherwise, it's a standard command. check for the '&', try to background + * the job if possible, otherwise just run it and wait on it. + */ +static +void +docommand(char *buf, struct exitinfo *ei) +{ + char *args[NARG_MAX + 1]; + int nargs, i; + char *s; + pid_t pid; + int status; + int bg=0; + time_t startsecs, endsecs; + unsigned long startnsecs, endnsecs; + + nargs = 0; + for (s = strtok(buf, " \t\r\n"); s; s = strtok(NULL, " \t\r\n")) { + if (nargs >= NARG_MAX) { + printf("%s: Too many arguments " + "(exceeds system limit)\n", + args[0]); + exitinfo_exit(ei, 1); + return; + } + args[nargs++] = s; + } + args[nargs] = NULL; + + if (nargs==0) { + /* empty line */ + exitinfo_exit(ei, 0); + return; + } + + for (i=0; builtins[i].name; i++) { + if (!strcmp(builtins[i].name, args[0])) { + builtins[i].func(nargs, args, ei); + return; + } + } + + /* Not a builtin; run it */ + + if (nargs > 0 && !strcmp(args[nargs-1], "&")) { + /* background */ + if (!can_bg()) { + printf("%s: Too many background jobs; wait for " + "some to finish before starting more\n", + args[0]); + exitinfo_exit(ei, 1); + return; + } + nargs--; + args[nargs] = NULL; + bg = 1; + } + + if (timing) { + __time(&startsecs, &startnsecs); + } + + pid = fork(); + switch (pid) { + case -1: + /* error */ + warn("fork"); + exitinfo_exit(ei, 255); + return; + case 0: + /* child */ + execvp(args[0], args); + warn("%s", args[0]); + /* + * Use _exit() instead of exit() in the child + * process to avoid calling atexit() functions, + * which would cause hostcompat (if present) to + * reset the tty state and mess up our input + * handling. + */ + _exit(1); + default: + break; + } + + /* parent */ + if (bg) { + /* background this command */ + remember_bg(pid); + printf("[%d] %s ... &\n", pid, args[0]); + exitinfo_exit(ei, 0); + return; + } + + if (waitpid(pid, &status, 0) < 0) { + warn("waitpid"); + exitinfo_exit(ei, 255); + } + else { + readstatus(status, ei); + } + + if (timing) { + __time(&endsecs, &endnsecs); + if (endnsecs < startnsecs) { + endnsecs += 1000000000; + endsecs--; + } + endnsecs -= startnsecs; + endsecs -= startsecs; + warnx("subprocess time: %lu.%09lu seconds", + (unsigned long) endsecs, (unsigned long) endnsecs); + } +} + +/* + * getcmd + * pulls valid characters off the console, filling the buffer. + * backspace deletes a character, simply by moving the position back. + * a newline or carriage return breaks the loop, which terminates + * the string and returns. + * + * if there's an invalid character or a backspace when there's nothing + * in the buffer, putchars an alert (bell). + */ +static +void +getcmd(char *buf, size_t len) +{ + size_t pos = 0; + int done=0, ch; + + /* + * In the absence of a , assume input is 7-bit ASCII. + */ + + while (!done) { + ch = getchar(); + if ((ch == '\b' || ch == 127) && pos > 0) { + putchar('\b'); + putchar(' '); + putchar('\b'); + pos--; + } + else if (ch == '\r' || ch == '\n') { + putchar('\r'); + putchar('\n'); + done = 1; + } + else if (ch >= 32 && ch < 127 && pos < len-1) { + buf[pos++] = ch; + putchar(ch); + } + else { + /* alert (bell) character */ + putchar('\a'); + } + } + buf[pos] = 0; +} + +/* + * interactive + * runs the interactive shell. basically, just infinitely loops, grabbing + * commands and running them (and printing the exit status if it's not + * success.) + */ +static +void +interactive(void) +{ + char buf[CMDLINE_MAX]; + struct exitinfo ei; + + while (1) { + printf("OS/161$ "); + getcmd(buf, sizeof(buf)); + docommand(buf, &ei); + printstatus(&ei, 0); +#ifdef WNOHANG + waitpoll(); +#endif + } +} + +static +void +check_timing(void) +{ + time_t secs; + unsigned long nsecs; + if (__time(&secs, &nsecs) != -1) { + timing = 1; + warnx("Timing enabled."); + } +} + +/* + * main + * if there are no arguments, run interactively, otherwise, run a program + * from within the shell, but immediately exit. + */ +int +main(int argc, char *argv[]) +{ +#ifdef HOST + hostcompat_init(argc, argv); +#endif + check_timing(); + + /* + * Allow argc to be 0 in case we're running on a broken kernel, + * or one that doesn't set argv when starting the first shell. + */ + if (argc == 0 || argc == 1) { + interactive(); + } + else if (argc == 3 && !strcmp(argv[1], "-c")) { + struct exitinfo ei; + docommand(argv[2], &ei); + printstatus(&ei, 0); + if (ei.signaled || ei.stopped || ei.val != 0) { + exit(1); + } + } + else { + errx(1, "Usage: sh [-c command]"); + } + return 0; +} diff --git a/userland/bin/sync/Makefile b/userland/bin/sync/Makefile new file mode 100644 index 0000000..a1672cc --- /dev/null +++ b/userland/bin/sync/Makefile @@ -0,0 +1,12 @@ +# Makefile for sync + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=sync +SRCS=sync.c +BINDIR=/bin + + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/bin/sync/sync.c b/userland/bin/sync/sync.c new file mode 100644 index 0000000..81b4434 --- /dev/null +++ b/userland/bin/sync/sync.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * sync - force kernel buffers (write-back disk cache) to disk. + * + * Just calls the sync() system call. + */ + +int +main(void) +{ + sync(); + return 0; +} diff --git a/userland/bin/tac/Makefile b/userland/bin/tac/Makefile new file mode 100644 index 0000000..dc262fb --- /dev/null +++ b/userland/bin/tac/Makefile @@ -0,0 +1,12 @@ +# Makefile for tac + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=tac +SRCS=tac.c +BINDIR=/bin + + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/bin/tac/tac.c b/userland/bin/tac/tac.c new file mode 100644 index 0000000..edaa48d --- /dev/null +++ b/userland/bin/tac/tac.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * tac - print file backwards line by line (reverse cat) + * usage: tac [files] + * + * This implementation copies the input to a scratch file, using a + * second scratch file to keep notes, and then prints the scratch file + * backwards. This is inefficient, but has the side effect of testing + * the behavior of scratch files that have been unlinked. + * + * Note that if the remove system call isn't implemented, unlinking + * the scratch files will fail and the scratch files will get left + * behind. To avoid unnecessary noise (e.g. on emufs) we won't + * complain about this. + * + * This program uses these system calls: + * getpid open read write lseek close remove _exit + */ + +#include +#include +#include +#include +#include +#include +#include + +struct indexentry { + off_t pos; + off_t len; +}; + +static int datafd = -1, indexfd = -1; +static char dataname[64], indexname[64]; + +static char buf[4096]; + +//////////////////////////////////////////////////////////// +// string ops + +/* this is standard and should go into libc */ +static +void * +memchr(const void *buf, int ch, size_t buflen) +{ + const unsigned char *ubuf = buf; + size_t i; + + for (i=0; i 0) { + dowrite(indexfd, indexname, &x, sizeof(x)); + } + + if (closefd != -1) { + close(closefd); + } +} + +static +void +dumpdata(void) +{ + struct indexentry x; + off_t indexsize, pos, done; + size_t amount, len; + + indexsize = dolseek(indexfd, indexname, 0, SEEK_CUR); + pos = indexsize; + assert(pos % sizeof(x) == 0); + while (pos > 0) { + pos -= sizeof(x); + assert(pos >= 0); + dolseek(indexfd, indexname, pos, SEEK_SET); + + len = doread(indexfd, indexname, &x, sizeof(x)); + if (len != sizeof(x)) { + errx(1, "%s: read: Unexpected EOF", indexname); + } + dolseek(datafd, dataname, x.pos, SEEK_SET); + + for (done = 0; done < x.len; done += amount) { + amount = sizeof(buf); + if ((off_t)amount > x.len - done) { + amount = x.len - done; + } + len = doread(datafd, dataname, buf, amount); + if (len != amount) { + errx(1, "%s: read: Unexpected short count" + " %zu of %zu", dataname, len, amount); + } + dowrite(STDOUT_FILENO, "stdout", buf, len); + } + } +} + +//////////////////////////////////////////////////////////// +// main + +static +int +openscratch(const char *name, int flags, mode_t mode) +{ + int fd; + + fd = open(name, flags, mode); + if (fd < 0) { + err(1, "%s", name); + } + if (remove(name) < 0) { + if (errno != ENOSYS) { + err(1, "%s: remove", name); + } + } + return fd; +} + +static +void +openfiles(void) +{ + pid_t pid; + + pid = getpid(); + + snprintf(dataname, sizeof(dataname), ".tmp.tacdata.%d", (int)pid); + datafd = openscratch(dataname, O_RDWR|O_CREAT|O_TRUNC, 0664); + + snprintf(indexname, sizeof(indexname), ".tmp.tacindex.%d", (int)pid); + indexfd = openscratch(indexname, O_RDWR|O_CREAT|O_TRUNC, 0664); +} + +static +void +closefiles(void) +{ + close(datafd); + close(indexfd); + indexfd = datafd = -1; +} + +int +main(int argc, char *argv[]) +{ + int i; + + openfiles(); + + if (argc > 1) { + for (i=1; i +#include + +/* + * true - succeed. + */ + +int +main(void) +{ + /* Just exit with success. */ + exit(0); +} diff --git a/userland/include/assert.h b/userland/include/assert.h new file mode 100644 index 0000000..4dbc2cd --- /dev/null +++ b/userland/include/assert.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ASSERT_H_ +#define _ASSERT_H_ + +/* + * Required by the C standard + */ +#undef assert + +/* + * Function to call when an assert fails. + */ +void __bad_assert(const char *file, int line, const char *msg); + +/* + * Asserts are only "on" if NDEBUG isn't set. (This is standard C.) + */ + +#ifdef NDEBUG + +#if 0 /* not allowed by the C standard */ +#define assert(x) ((void)(x)) /* retain any side effects of X */ +#else +#define assert(x) ((void)0) /* mysteriously hide any side effects of X */ +#endif + +#else +#define assert(x) ((x) ? (void)0 : __bad_assert(__FILE__, __LINE__, #x)) +#endif + + +#endif /* _ASSERT_H_ */ diff --git a/userland/include/err.h b/userland/include/err.h new file mode 100644 index 0000000..8d3f9cb --- /dev/null +++ b/userland/include/err.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ERR_H_ +#define _ERR_H_ + +#include /* for __DEAD */ +#include /* for __va_list */ + +/* + * 4.4BSD error-printing functions. + * + * These print the program name and the supplied message, and + * (non-*x versions only) the string for the error currently + * stored in "errno", and a newline. The err* versions then + * exit with the supplied exitcode. + * + * The v* versions are to the non-v* versions like vprintf is to + * printf. + */ + +void warn(const char *fmt, ...); +void warnx(const char *fmt, ...); +__DEAD void err(int exitcode, const char *fmt, ...); +__DEAD void errx(int exitcode, const char *fmt, ...); + +void vwarn(const char *fmt, __va_list); +void vwarnx(const char *fmt, __va_list); +__DEAD void verr(int exitcode, const char *fmt, __va_list); +__DEAD void verrx(int exitcode, const char *fmt, __va_list); + +#endif /* _ERR_H_ */ diff --git a/userland/include/errno.h b/userland/include/errno.h new file mode 100644 index 0000000..6c45396 --- /dev/null +++ b/userland/include/errno.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _ERRNO_H_ +#define _ERRNO_H_ + +/* Get the error codes from the kernel. */ +#include + +/* Declare the standard global variable errno. */ +extern int errno; + +#endif /* _ERRNO_H_ */ diff --git a/userland/include/fcntl.h b/userland/include/fcntl.h new file mode 100644 index 0000000..2d39a64 --- /dev/null +++ b/userland/include/fcntl.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* This file is for UNIX compat. In OS/161, everything's in */ +#include diff --git a/userland/include/limits.h b/userland/include/limits.h new file mode 100644 index 0000000..f488852 --- /dev/null +++ b/userland/include/limits.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LIMITS_H_ +#define _LIMITS_H_ + +/* + * System limits. + */ + +/* Get the limits the kernel exports. libc doesn't have any limits :-) */ +#include + +/* Provide the real names */ +#define NAME_MAX __NAME_MAX +#define PATH_MAX __PATH_MAX +#define ARG_MAX __ARG_MAX +#define PID_MIN __PID_MIN +#define PID_MAX __PID_MAX +#define PIPE_BUF __PIPE_BUF +#define NGROUPS_MAX __NGROUPS_MAX +#define LOGIN_NAME_MAX __LOGIN_NAME_MAX +#define OPEN_MAX __OPEN_MAX +#define IOV_MAX __IOV_MAX + + +#endif /* _LIMITS_H_ */ diff --git a/userland/include/setjmp.h b/userland/include/setjmp.h new file mode 100644 index 0000000..ca55b40 --- /dev/null +++ b/userland/include/setjmp.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SETJMP_H_ +#define _SETJMP_H_ + +/* Get the (machine-dependent) definition of jmp_buf. */ +#include + +/* + * Functions. + * + * setjmp saves the current processor state in the jmp_buf and + * returns 0. A subsequent call to longjmp with the same jmp_buf + * causes execution to return to where setjmp was called. setjmp + * returns a second time, this time returning CODE. (If CODE is + * 0, it is forced to 1.) + * + * If the stack frame that called setjmp returns before longjmp is + * called, the results are undefined. + */ + +int setjmp(jmp_buf jb); +void longjmp(jmp_buf jb, int code); + +#endif /* _SETJMP_H_ */ diff --git a/userland/include/signal.h b/userland/include/signal.h new file mode 100644 index 0000000..b7c2523 --- /dev/null +++ b/userland/include/signal.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include diff --git a/userland/include/stdarg.h b/userland/include/stdarg.h new file mode 100644 index 0000000..f17f2ab --- /dev/null +++ b/userland/include/stdarg.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _STDARG_H_ +#define _STDARG_H_ + +#include + +/* + * As of gcc 3.0, the stdarg declarations can be made machine- + * independent because gcc abstracts the implementations away for + * us. However, they went and changed __builtin_stdarg_start to + * __builtin_va_start sometime between gcc 4.1 and 4.8 (not sure + * when) so we need to check that. + */ + +typedef __va_list va_list; + +#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8) +#define va_start(ap, fmt) __builtin_stdarg_start(ap, fmt) +#else +#define va_start(ap, fmt) __builtin_va_start(ap, fmt) +#endif +#define va_arg(ap,t) __builtin_va_arg(ap,t) +#define va_copy(ap1,ap2) __builtin_va_copy(ap1,ap2) +#define va_end(ap) __builtin_va_end(ap) + +#endif /* _STDARG_H_ */ diff --git a/userland/include/stdbool.h b/userland/include/stdbool.h new file mode 100644 index 0000000..53a5f63 --- /dev/null +++ b/userland/include/stdbool.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _STDBOOL_H_ +#define _STDBOOL_H_ + +typedef _Bool bool; +#define true 1 +#define false 0 + +#endif /* _STDBOOL_H_ */ diff --git a/userland/include/stdint.h b/userland/include/stdint.h new file mode 100644 index 0000000..e9acb3d --- /dev/null +++ b/userland/include/stdint.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _STDINT_H_ +#define _STDINT_H_ + +/* + * - C99 header file with sized integer types. + */ + +#include + +typedef __i8 int8_t; +typedef __i16 int16_t; +typedef __i32 int32_t; +typedef __i64 int64_t; +typedef __u8 uint8_t; +typedef __u16 uint16_t; +typedef __u32 uint32_t; +typedef __u64 uint64_t; + +typedef __intptr_t intptr_t; +typedef __uintptr_t uintptr_t; + +#endif /* _STDINT_H_ */ diff --git a/userland/include/stdio.h b/userland/include/stdio.h new file mode 100644 index 0000000..20e96cb --- /dev/null +++ b/userland/include/stdio.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _STDIO_H_ +#define _STDIO_H_ + +/* + * Get the __-protected definition of va_list. We aren't supposed to + * include stdarg.h here. + */ +#include +#include +#include + +/* Constant returned by a bunch of stdio functions on error */ +#define EOF (-1) + +/* + * The actual guts of printf + * (for libc internal use only) + */ +int __vprintf(void (*sendfunc)(void *clientdata, const char *, size_t len), + void *clientdata, + const char *fmt, + __va_list ap); + +/* Printf calls for user programs */ +int printf(const char *fmt, ...); +int vprintf(const char *fmt, __va_list ap); +int snprintf(char *buf, size_t len, const char *fmt, ...); +int vsnprintf(char *buf, size_t len, const char *fmt, __va_list ap); + +/* Print the argument string and then a newline. Returns 0 or -1 on error. */ +int puts(const char *); + +/* Like puts, but without the newline. Returns #chars written. */ +/* Nonstandard C, hence the __. */ +int __puts(const char *); + +/* Writes one character. Returns it. */ +int putchar(int); + +/* Reads one character (0-255) or returns EOF on error. */ +int getchar(void); + +#endif /* _STDIO_H_ */ diff --git a/userland/include/stdlib.h b/userland/include/stdlib.h new file mode 100644 index 0000000..eaa3169 --- /dev/null +++ b/userland/include/stdlib.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _STDLIB_H_ +#define _STDLIB_H_ + +#include +#include +#include + +/* + * Ascii to integer - turn a string holding a number into a number. + */ +int atoi(const char *); + +/* + * Standard routine to bail out of a program in a severe error condition. + */ +void abort(void); + +/* + * Routine to exit cleanly. + * (This does libc cleanup before calling the _exit system call.) + */ +void exit(int code); + +/* + * Get the value of an environment variable. A default environment is + * provided if the kernel doesn't pass environment strings. + */ +char *getenv(const char *var); + +/* + * Run a command. Returns its exit status as it comes back from waitpid(). + */ +int system(const char *command); + +/* + * Pseudo-random number generator. + */ +#define RAND_MAX 0x7fffffff +long random(void); +void srandom(unsigned long seed); +char *initstate(unsigned long, char *, size_t); +char *setstate(char *); + +/* + * Memory allocation functions. + */ +void *malloc(size_t size); +void free(void *ptr); + +/* + * Sort. + */ +void qsort(void *data, unsigned num, size_t size, + int (*f)(const void *, const void *)); + +#endif /* _STDLIB_H_ */ diff --git a/userland/include/string.h b/userland/include/string.h new file mode 100644 index 0000000..2c9de95 --- /dev/null +++ b/userland/include/string.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _STRING_H_ +#define _STRING_H_ + +#include +#include +#include + +/* + * Standard C string functions. + */ +char *strcat(char *, const char *); +char *strcpy(char *, const char *); +char *strchr(const char *, int); +char *strrchr(const char *, int); +int strcmp(const char *, const char *); +size_t strlen(const char *); +char *strtok_r(char *, const char *, char **); +char *strtok(char *, const char *); + +void *memset(void *, int c, size_t); +void *memcpy(void *, const void *, size_t); +void *memmove(void *, const void *, size_t); +int memcmp(const void *, const void *, size_t); + +/* + * POSIX string functions. + */ +const char *strerror(int errcode); + +/* + * BSD string functions. + */ +void bzero(void *, size_t); + + +#endif /* _STRING_H_ */ diff --git a/userland/include/sys/cdefs.h b/userland/include/sys/cdefs.h new file mode 100644 index 0000000..bba447e --- /dev/null +++ b/userland/include/sys/cdefs.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file contains definitions for preprocessor macros needed for + * declaring things in the system include files. It must not define + * anything in the user namespace so it is safe to include anywhere. + */ + +#ifndef _SYS_CDEFS_H_ +#define _SYS_CDEFS_H_ + +#ifdef __GNUC__ +#define __DEAD __attribute__((__noreturn__)) +#else +#define __DEAD +#endif + +#endif /* _SYS_CDEFS_H_ */ diff --git a/userland/include/sys/endian.h b/userland/include/sys/endian.h new file mode 100644 index 0000000..f957631 --- /dev/null +++ b/userland/include/sys/endian.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SYS_ENDIAN_H_ +#define _SYS_ENDIAN_H_ + +#include + +#endif /* _SYS_ENDIAN_H_ */ diff --git a/userland/include/sys/ioctl.h b/userland/include/sys/ioctl.h new file mode 100644 index 0000000..2d39a64 --- /dev/null +++ b/userland/include/sys/ioctl.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* This file is for UNIX compat. In OS/161, everything's in */ +#include diff --git a/userland/include/sys/null.h b/userland/include/sys/null.h new file mode 100644 index 0000000..8ed8971 --- /dev/null +++ b/userland/include/sys/null.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SYS_NULL_H_ +#define _SYS_NULL_H_ + +/* + * Null pointer. + */ + +#define NULL ((void *)0) + +#endif /* _SYS_NULL_H_ */ diff --git a/userland/include/sys/reboot.h b/userland/include/sys/reboot.h new file mode 100644 index 0000000..2d39a64 --- /dev/null +++ b/userland/include/sys/reboot.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* This file is for UNIX compat. In OS/161, everything's in */ +#include diff --git a/userland/include/sys/stat.h b/userland/include/sys/stat.h new file mode 100644 index 0000000..5ee6580 --- /dev/null +++ b/userland/include/sys/stat.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SYS_STAT_H_ +#define _SYS_STAT_H_ + +/* + * Get struct stat and all the #defines from the kernel + */ +#include +#include + +/* + * Test macros for object types. + */ +#define S_ISDIR(mode) ((mode & _S_IFMT) == _S_IFDIR) +#define S_ISREG(mode) ((mode & _S_IFMT) == _S_IFREG) +#define S_ISDIR(mode) ((mode & _S_IFMT) == _S_IFDIR) +#define S_ISLNK(mode) ((mode & _S_IFMT) == _S_IFLNK) +#define S_ISIFO(mode) ((mode & _S_IFMT) == _S_IFIFO) +#define S_ISSOCK(mode) ((mode & _S_IFMT) ==_S_IFSOCK) +#define S_ISCHR(mode) ((mode & _S_IFMT) == _S_IFCHR) +#define S_ISBLK(mode) ((mode & _S_IFMT) == _S_IFBLK) + +/* + * Provide non-underscore names. These are not actually standard; for + * some reason only the test macros are. + */ +#define S_IFMT _S_IFMT +#define S_IFREG _S_IFREG +#define S_IFDIR _S_IFDIR +#define S_IFLNK _S_IFLNK +#define S_IFIFO _S_IFIFO +#define S_IFSOCK _S_IFSOCK +#define S_IFCHR _S_IFCHR +#define S_IFBLK _S_IFBLK + +/* + * stat is the same as fstat, only on a file that isn't already + * open. lstat is the same as stat, only if the name passed names a + * symlink, information about the symlink is returned rather than + * information about the file it points to. You don't need to + * implement lstat unless you're implementing symbolic links. + */ +int fstat(int filehandle, struct stat *buf); +int stat(const char *path, struct stat *buf); +int lstat(const char *path, struct stat *buf); + +/* + * The second argument to mkdir is the mode for the new directory. + * Unless you're implementing security and permissions, you can + * (and should) ignore it. See notes in unistd.h. + */ +int mkdir(const char *dirname, int ignore); + + +#endif /* _SYS_STAT_H_ */ diff --git a/userland/include/sys/types.h b/userland/include/sys/types.h new file mode 100644 index 0000000..a3f8f94 --- /dev/null +++ b/userland/include/sys/types.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _SYS_TYPES_H_ +#define _SYS_TYPES_H_ + +/* + * This header file is supposed to define standard system types, + * stuff like size_t and pid_t, as well as define a few other + * standard symbols like NULL. + * + * There are no such types that are user-level only. + */ + +/* Get the exported kernel definitions, protected with __ */ +#include + +/* Pick up stuff that needs to be defined individually due to standards. */ +#include +#include + +/* + * Define the rest with user-visible names. + * + * Note that the standards-compliance stuff is not by any means + * complete here yet... + */ + +typedef __ssize_t ssize_t; +typedef __ptrdiff_t ptrdiff_t; + +/* ...and machine-independent from . */ +typedef __blkcnt_t blkcnt_t; +typedef __blksize_t blksize_t; +typedef __daddr_t daddr_t; +typedef __dev_t dev_t; +typedef __fsid_t fsid_t; +typedef __gid_t gid_t; +typedef __in_addr_t in_addr_t; +typedef __in_port_t in_port_t; +typedef __ino_t ino_t; +typedef __mode_t mode_t; +typedef __nlink_t nlink_t; +typedef __off_t off_t; +typedef __pid_t pid_t; +typedef __rlim_t rlim_t; +typedef __sa_family_t sa_family_t; +typedef __time_t time_t; +typedef __uid_t uid_t; + +typedef __nfds_t nfds_t; +typedef __socklen_t socklen_t; + +/* + * Number of bits per byte. + */ + +#define CHAR_BIT __CHAR_BIT + + +#endif /* _SYS_TYPES_H_ */ diff --git a/userland/include/sys/wait.h b/userland/include/sys/wait.h new file mode 100644 index 0000000..2d39a64 --- /dev/null +++ b/userland/include/sys/wait.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* This file is for UNIX compat. In OS/161, everything's in */ +#include diff --git a/userland/include/test/quint.h b/userland/include/test/quint.h new file mode 100644 index 0000000..b38a76c --- /dev/null +++ b/userland/include/test/quint.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +void quint(const char *prog); diff --git a/userland/include/test/triple.h b/userland/include/test/triple.h new file mode 100644 index 0000000..4f743c9 --- /dev/null +++ b/userland/include/test/triple.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +void triple(const char *prog); diff --git a/userland/include/time.h b/userland/include/time.h new file mode 100644 index 0000000..2d39a64 --- /dev/null +++ b/userland/include/time.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* This file is for UNIX compat. In OS/161, everything's in */ +#include diff --git a/userland/include/types/size_t.h b/userland/include/types/size_t.h new file mode 100644 index 0000000..d7a9532 --- /dev/null +++ b/userland/include/types/size_t.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _TYPES_SIZE_T_H_ +#define _TYPES_SIZE_T_H_ + +#include +typedef __size_t size_t; + +#endif /* _TYPES_SIZE_T_H_ */ diff --git a/userland/include/unistd.h b/userland/include/unistd.h new file mode 100644 index 0000000..44f2c6a --- /dev/null +++ b/userland/include/unistd.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _UNISTD_H_ +#define _UNISTD_H_ + +#include +#include + +/* + * Get the various constants (flags, codes, etc.) for calls from + * kernel includes. This way user-level code doesn't need to know + * about the kern/ headers. + */ +#include +#include +#include +#include +#include +#include +#include + + +/* + * Prototypes for OS/161 system calls. + * + * Note that the following system calls are prototyped in other + * header files, as follows: + * + * stat: sys/stat.h + * fstat: sys/stat.h + * lstat: sys/stat.h + * mkdir: sys/stat.h + * + * If this were standard Unix, more prototypes would go in other + * header files as well, as follows: + * + * waitpid: sys/wait.h + * open: fcntl.h or sys/fcntl.h + * reboot: sys/reboot.h + * ioctl: sys/ioctl.h + * remove: stdio.h + * rename: stdio.h + * time: time.h + * + * Also note that the prototypes for open() and mkdir() contain, for + * compatibility with Unix, an extra argument that is not meaningful + * in OS/161. This is the "mode" (file permissions) for a newly created + * object. (With open, if no file is created, this is ignored, and the + * call prototype is gimmicked so it doesn't have to be passed either.) + * + * You should ignore these arguments in the OS/161 kernel unless you're + * implementing security and file permissions. + * + * If you are implementing security and file permissions and using a + * model different from Unix so that you need different arguments to + * these calls, you may make appropriate changes, or define new syscalls + * with different names and take the old ones out, or whatever. + * + * As a general rule of thumb, however, while you can make as many new + * syscalls of your own as you like, you shouldn't change the + * definitions of the ones that are already here. They've been written + * to be pretty much compatible with Unix, and the teaching staff has + * test code that expects them to behave in particular ways. + * + * Of course, if you want to redesign the user/kernel API and make a + * lot of work for yourself, feel free, just contact the teaching + * staff beforehand. :-) + * + * The categories (required/recommended/optional) are guesses - check + * the text of the various assignments for an authoritative list. + */ + + +/* + * NOTE NOTE NOTE NOTE NOTE + * + * This file is *not* shared with the kernel, even though in a sense + * the kernel needs to know about these prototypes. This is because, + * due to error handling concerns, the in-kernel versions of these + * functions will usually have slightly different signatures. + */ + + +/* Required. */ +__DEAD void _exit(int code); +int execv(const char *prog, char *const *args); +pid_t fork(void); +pid_t waitpid(pid_t pid, int *returncode, int flags); +/* + * Open actually takes either two or three args: the optional third + * arg is the file mode used for creation. Unless you're implementing + * security and permissions, you can ignore it. + */ +int open(const char *filename, int flags, ...); +ssize_t read(int filehandle, void *buf, size_t size); +ssize_t write(int filehandle, const void *buf, size_t size); +int close(int filehandle); +int reboot(int code); +int sync(void); +/* mkdir - see sys/stat.h */ +int rmdir(const char *dirname); + +/* Recommended. */ +pid_t getpid(void); +int ioctl(int filehandle, int code, void *buf); +off_t lseek(int filehandle, off_t pos, int code); +int fsync(int filehandle); +int ftruncate(int filehandle, off_t size); +int remove(const char *filename); +int rename(const char *oldfile, const char *newfile); +int link(const char *oldfile, const char *newfile); +/* fstat - see sys/stat.h */ +int chdir(const char *path); + +/* Optional. */ +void *sbrk(__intptr_t change); +ssize_t getdirentry(int filehandle, char *buf, size_t buflen); +int symlink(const char *target, const char *linkname); +ssize_t readlink(const char *path, char *buf, size_t buflen); +int dup2(int filehandle, int newhandle); +int pipe(int filehandles[2]); +int __time(time_t *seconds, unsigned long *nanoseconds); +ssize_t __getcwd(char *buf, size_t buflen); +/* stat - see sys/stat.h */ +/* lstat - see sys/stat.h */ + +/* + * These are not themselves system calls, but wrapper routines in libc. + */ + +int execvp(const char *prog, char *const *args); /* calls execv */ +char *getcwd(char *buf, size_t buflen); /* calls __getcwd */ +time_t time(time_t *seconds); /* calls __time */ + +#endif /* _UNISTD_H_ */ diff --git a/userland/lib/Makefile b/userland/lib/Makefile new file mode 100644 index 0000000..842056c --- /dev/null +++ b/userland/lib/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for src/lib (sources for libraries installed in /lib) +# +# Note that all includes are found in src/include - the "includes" +# make rule for installing .h files does not come here. +# + +TOP=../.. +.include "$(TOP)/mk/os161.config.mk" + +SUBDIRS=crt0 libc libtest hostcompat + +.include "$(TOP)/mk/os161.subdir.mk" diff --git a/userland/lib/crt0/Makefile b/userland/lib/crt0/Makefile new file mode 100644 index 0000000..6af5a1d --- /dev/null +++ b/userland/lib/crt0/Makefile @@ -0,0 +1,27 @@ +# +# Makefile for crt0.o +# + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +SRCS=$(MACHINE)/crt0.S +MKDIRS=$(INSTALLTOP)/lib $(OSTREE)/lib $(MYBUILDDIR) + +.include "$(TOP)/mk/os161.baserules.mk" +.include "$(TOP)/mk/os161.compile.mk" + +all-local: $(MYBUILDDIR) .WAIT $(OBJS) + +install-staging-local: $(INSTALLTOP)/lib .WAIT +install-local: $(OSTREE)/lib .WAIT + +.for O in $(OBJS) +install-staging-local: $(INSTALLTOP)/lib/$(O:T) +$(INSTALLTOP)/lib/$(O:T): $(O) + cp $(O) $(INSTALLTOP)/lib/$(O:T) + +install-local: $(OSTREE)/lib/$(O:T) +$(OSTREE)/lib/$(O:T): $(O) + cp $(O) $(OSTREE)/lib/$(O:T) +.endfor diff --git a/userland/lib/crt0/mips/crt0.S b/userland/lib/crt0/mips/crt0.S new file mode 100644 index 0000000..0e17cd2 --- /dev/null +++ b/userland/lib/crt0/mips/crt0.S @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * crt0.o for MIPS r2000/r3000. + * + * crt stands for "C runtime". + * + * Basically, this is the startup code that gets invoked before main(), + * and regains control when main returns. + * + * All we really do is save copies of argv and environ for use by libc + * funcions (e.g. err* and warn*), and call exit when main returns. + */ + +#include +#include + + .set noreorder /* so we can use delay slots explicitly */ + + .text + .globl __start + .type __start,@function + .ent __start +__start: + /* Load the "global pointer" register */ + la gp, _gp + + /* + * We expect that the kernel passes argc in a0, argv in a1, + * and environ in a2. We do not expect the kernel to set up a + * complete stack frame, however. + * + * The MIPS ABI decrees that every caller will leave 16 bytes of + * space in the bottom of its stack frame for writing back the + * values of a0-a3, even when calling functions that take fewer + * than four arguments. It also requires the stack to be aligned + * to an 8-byte boundary. (This is because of 64-bit MIPS, which + * we're not dealing with... but we'll conform to the standard.) + */ + li t0, 0xfffffff8 /* mask for stack alignment */ + and sp, sp, t0 /* align the stack */ + addiu sp, sp, -16 /* create our frame */ + + sw a1, __argv /* save second arg (argv) in __argv for use later */ + sw a2, __environ /* save third arg (environ) for use later */ + + jal main /* call main */ + nop /* delay slot */ + + /* + * Now, we have the return value of main in v0. + * + * Move it to s0 (which is callee-save) so we still have + * it in case exit() returns. + * + * Also move it to a0 so it's the argument to exit. + */ + move s0, v0 /* save return value */ +1: + jal exit /* call exit() */ + move a0, s0 /* Set argument (in delay slot) */ + + /* + * exit() does not return. (Even if _exit() is not implemented + * so *it* returns, exit() is supposed to take care of that.) + * But just in case, loop and try again. + */ + b 1b /* loop back */ + nop /* delay slot */ + .end __start diff --git a/userland/lib/hostcompat/Makefile b/userland/lib/hostcompat/Makefile new file mode 100644 index 0000000..4cd6ab0 --- /dev/null +++ b/userland/lib/hostcompat/Makefile @@ -0,0 +1,55 @@ +# +# Makefile for hostcompat library +# +# defs.mk contains two special settings for us. +# +# COMPAT_CFLAGS contains our configuration cflags. +# COMPAT_TARGETS are additional targets to run at install time. +# +# COMPAT_CFLAGS may include any of the following: +# +# -DNEED_ERR Compile err, errx, etc. +# -DNEED_NTOHLL Compile ntohll and htonll +# +# COMPAT_TARGETS may include any of the following: +# +# install-errh Install an +# + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +LIB=hostcompat +SRCS=err.c ntohll.c time.c hostcompat.c + +HOST_CFLAGS+=$(COMPAT_CFLAGS) + +MKDIRS=$(INSTALLTOP)/hostinclude + +.include "$(TOP)/mk/os161.hostlib.mk" + +# XXX: installheaders.sh should be made flexible enough to be used here +includes: $(INSTALLTOP)/hostinclude .WAIT $(COMPAT_TARGETS) + @if diff hostcompat.h \ + $(INSTALLTOP)/hostinclude/hostcompat.h > /dev/null 2>&1; then \ + :; \ + else \ + echo cp hostcompat.h $(INSTALLTOP)/hostinclude/; \ + cp hostcompat.h $(INSTALLTOP)/hostinclude/; \ + fi + [ -h $(INSTALLTOP)/hostinclude/kern ] || \ + ln -sf ../include/kern $(INSTALLTOP)/hostinclude/kern + +install-errh: + @if diff host-err.h \ + $(INSTALLTOP)/hostinclude/err.h > /dev/null 2>&1; then \ + :; \ + else \ + echo cp host-err.h $(INSTALLTOP)/hostinclude/err.h; \ + cp host-err.h $(INSTALLTOP)/hostinclude/err.h; \ + fi + +# Recompile these if the config changes, as they might change with it +err.o ntohll.o: $(TOP)/defs.mk + +.PHONY: includes install-errh diff --git a/userland/lib/hostcompat/err.c b/userland/lib/hostcompat/err.c new file mode 100644 index 0000000..7c81928 --- /dev/null +++ b/userland/lib/hostcompat/err.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * 4.4BSD error printing functions. + */ + +#include +#include +#include +#include + +#include "host-err.h" + +#ifdef NEED_ERR + +/* + * This is initialized by hostcompat_init + */ +extern const char *hostcompat_progname; + +/* + * Common routine for all the *err* and *warn* functions. + */ +static +void +hostcompat_printerr(int use_errno, const char *fmt, va_list ap) +{ + const char *errmsg; + + /* + * Get the error message for the current errno. + * Do this early, before doing anything that might change the + * value in errno. + */ + errmsg = strerror(errno); + + /* + * Look up the program name. + * Strictly speaking we should pull off the rightmost + * path component of argv[0] and use that as the program + * name (this is how BSD err* prints) but it doesn't make + * much difference. + */ + if (hostcompat_progname != NULL) { + fprintf(stderr, "%s: ", hostcompat_progname); + } + else { + fprintf(stderr, "libhostcompat: hostcompat_init not called\n"); + fprintf(stderr, "libhostcompat-program: "); + } + + /* process the printf format and args */ + vfprintf(stderr, fmt, ap); + + if (use_errno) { + /* if we're using errno, print the error string from above. */ + fprintf(stderr, ": %s\n", errmsg); + } + else { + /* otherwise, just a newline. */ + fprintf(stderr, "\n"); + } +} + +/* + * The va_list versions of the warn/err functions. + */ + +/* warn/vwarn: use errno, don't exit */ +void +vwarn(const char *fmt, va_list ap) +{ + hostcompat_printerr(1, fmt, ap); +} + +/* warnx/vwarnx: don't use errno, don't exit */ +void +vwarnx(const char *fmt, va_list ap) +{ + hostcompat_printerr(0, fmt, ap); +} + +/* err/verr: use errno, then exit */ +void +verr(int exitcode, const char *fmt, va_list ap) +{ + hostcompat_printerr(1, fmt, ap); + exit(exitcode); +} + +/* errx/verrx: don't use errno, but do then exit */ +void +verrx(int exitcode, const char *fmt, va_list ap) +{ + hostcompat_printerr(0, fmt, ap); + exit(exitcode); +} + +/* + * The non-va_list versions of the warn/err functions. + * Just hand off to the va_list versions. + */ + +void +warn(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarn(fmt, ap); + va_end(ap); +} + +void +warnx(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarnx(fmt, ap); + va_end(ap); +} + +void +err(int exitcode, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verr(exitcode, fmt, ap); + va_end(ap); +} + +void +errx(int exitcode, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verrx(exitcode, fmt, ap); + va_end(ap); +} + +#endif /* NEED_ERR */ diff --git a/userland/lib/hostcompat/host-err.h b/userland/lib/hostcompat/host-err.h new file mode 100644 index 0000000..fd41a22 --- /dev/null +++ b/userland/lib/hostcompat/host-err.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#ifndef HOSTCOMPAT_ERR_H +#define HOSTCOMPAT_ERR_H + +#include + +/* + * 4.4BSD error-printing functions. + * + * These print the program name and the supplied message, and + * (non-*x versions only) the string for the error currently + * stored in "errno", and a newline. The err* versions then + * exit with the supplied exitcode. + * + * The v* versions are to the non-v* versions like vprintf is to + * printf. + */ + +void warn(const char *fmt, ...); +void warnx(const char *fmt, ...); +void err(int exitcode, const char *fmt, ...); +void errx(int exitcode, const char *fmt, ...); + +void vwarn(const char *fmt, va_list); +void vwarnx(const char *fmt, va_list); +void verr(int exitcode, const char *fmt, va_list); +void verrx(int exitcode, const char *fmt, va_list); + +#endif /* HOSTCOMPAT_ERR_H */ diff --git a/userland/lib/hostcompat/hostcompat.c b/userland/lib/hostcompat/hostcompat.c new file mode 100644 index 0000000..8e9db6d --- /dev/null +++ b/userland/lib/hostcompat/hostcompat.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "hostcompat.h" + +/* + * The program name. + * This is used in err.c. + */ +const char *hostcompat_progname = NULL; + +/* + * Unix tty state, for when we're running and to put it back the way it was, + * respectively. + */ +static struct termios hostcompat_runtios; +static struct termios hostcompat_savetios; + +/* + * Put the tty state back the way it was. + */ +static +void +hostcompat_ttyreset(void) +{ + tcsetattr(STDIN_FILENO, TCSADRAIN, &hostcompat_savetios); +} + +/* + * Set the tty state back to the way we want it for running. + */ +static +void +hostcompat_ttyresume(void) +{ + tcsetattr(STDIN_FILENO, TCSADRAIN, &hostcompat_runtios); +} + +/* + * Set up the tty state stuff. + */ +static +int +hostcompat_ttysetup(void) +{ + struct termios tios; + + /* Get the current tty state. */ + if (tcgetattr(STDIN_FILENO, &tios) < 0) { + /* stdin is not a tty */ + return -1; + } + + hostcompat_savetios = tios; + + /* Turn off canonical ("cooked") input. */ + tios.c_lflag &= ~ICANON; + + /* + * With canonical input off, this says how many characters must be + * typed before read() will return. + */ + tios.c_cc[VMIN] = 1; + + /* This can be used to set up read timeouts, but we don't need that. */ + tios.c_cc[VTIME] = 0; + + /* Turn off echoing of keypresses. */ + tios.c_lflag &= ~(ECHO|ECHONL|ECHOCTL); + + /* Do not support XON/XOFF flow control. */ + tios.c_iflag &= ~(IXON|IXOFF); + + /* On input, we want no CR/LF translation. */ + tios.c_iflag &= ~(INLCR|IGNCR|ICRNL); + + /* However, on output we want LF ('\n') mapped to CRLF. */ +#ifdef OCRNL /* missing on OS X */ + tios.c_oflag &= ~(OCRNL); +#endif + tios.c_oflag |= OPOST|ONLCR; + + /* Enable keyboard signals (^C, ^Z, etc.) because they're useful. */ + tios.c_lflag |= ISIG; + + /* Set the new tty state. */ + hostcompat_runtios = tios; + tcsetattr(STDIN_FILENO, TCSADRAIN, &tios); + + return 0; +} + +/* + * Signal handler for all the fatal signals (SIGSEGV, SIGTERM, etc.) + */ +static +void +hostcompat_die(int sig) +{ + /* Set the tty back to the way we found it */ + hostcompat_ttyreset(); + + /* Make sure the default action will occur when we get another signal*/ + signal(sig, SIG_DFL); + + /* Post the signal back to ourselves, to cause the right exit status.*/ + kill(getpid(), sig); + + /* Just in case. */ + _exit(255); +} + +/* + * Signal handler for the stop signals (SIGTSTP, SIGTTIN, etc.) + */ +static +void +hostcompat_stop(int sig) +{ + /* Set the tty back to the way we found it */ + hostcompat_ttyreset(); + + /* Make sure the default action will occur when we get another signal*/ + signal(sig, SIG_DFL); + + /* Post the signal back to ourselves. */ + kill(getpid(), sig); +} + +/* + * Signal handler for SIGCONT. + */ +static +void +hostcompat_cont(int sig) +{ + (void)sig; + + /* Set the tty to the way we want it for running. */ + hostcompat_ttyresume(); + + /* + * Reload the signal handlers for stop/continue signals, in case + * they were set up with one-shot signals. + */ + signal(SIGTTIN, hostcompat_stop); + signal(SIGTTOU, hostcompat_stop); + signal(SIGTSTP, hostcompat_stop); + signal(SIGCONT, hostcompat_cont); +} + +/* + * Initialize the hostcompat library. + */ +void +hostcompat_init(int argc, char *argv[]) +{ + /* Set the program name */ + if (argc > 0 && argv[0] != NULL) { + hostcompat_progname = argv[0]; + } + + /* Set the tty modes */ + if (hostcompat_ttysetup() < 0) { + return; + } + + /* When exit() is called, clean up */ + atexit(hostcompat_ttyreset); + + /* stdout/stderr should be unbuffered */ + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + + /* Catch all the fatal signals, so we can clean up */ + signal(SIGHUP, hostcompat_die); + signal(SIGINT, hostcompat_die); + signal(SIGQUIT, hostcompat_die); + signal(SIGILL, hostcompat_die); + signal(SIGTRAP, hostcompat_die); + signal(SIGABRT, hostcompat_die); +#ifdef SIGEMT + signal(SIGEMT, hostcompat_die); +#endif + signal(SIGFPE, hostcompat_die); + signal(SIGBUS, hostcompat_die); + signal(SIGSEGV, hostcompat_die); + signal(SIGSYS, hostcompat_die); + signal(SIGPIPE, hostcompat_die); + signal(SIGALRM, hostcompat_die); + signal(SIGTERM, hostcompat_die); + signal(SIGXCPU, hostcompat_die); + signal(SIGXFSZ, hostcompat_die); + signal(SIGVTALRM, hostcompat_die); + signal(SIGPROF, hostcompat_die); + signal(SIGUSR1, hostcompat_die); + signal(SIGUSR2, hostcompat_die); + + /* Catch the stop signals, so we can adjust the tty */ + signal(SIGTTIN, hostcompat_stop); + signal(SIGTTOU, hostcompat_stop); + signal(SIGTSTP, hostcompat_stop); + + /* Catch the continue signal, so we can adjust the tty */ + signal(SIGCONT, hostcompat_cont); +} diff --git a/userland/lib/hostcompat/hostcompat.h b/userland/lib/hostcompat/hostcompat.h new file mode 100644 index 0000000..7191964 --- /dev/null +++ b/userland/lib/hostcompat/hostcompat.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include +#include + +void hostcompat_init(int argc, char **argv); + +time_t __time(time_t *secs, unsigned long *nsecs); + +#ifdef DECLARE_NTOHLL +uint64_t ntohll(uint64_t); +#define htonll(x) (ntohll(x)) +#endif diff --git a/userland/lib/hostcompat/ntohll.c b/userland/lib/hostcompat/ntohll.c new file mode 100644 index 0000000..2131fdc --- /dev/null +++ b/userland/lib/hostcompat/ntohll.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +#include "hostcompat.h" + +#ifdef NEED_NTOHLL + +uint64_t +ntohll(uint64_t x) +{ + uint32_t x0, x1, y0, y1; + + if (ntohl(1) == 1) { + return x; + } + + x0 = x & 0xffffffff; + y0 = ntohl(x0); + x1 = x >> 32; + y1 = ntohl(x1); + return ((uint64_t)y0 << 32) | y1; +} + +#endif diff --git a/userland/lib/hostcompat/time.c b/userland/lib/hostcompat/time.c new file mode 100644 index 0000000..5a687d4 --- /dev/null +++ b/userland/lib/hostcompat/time.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * OS/161 __time implementation in terms of Unix gettimeofday(). + */ + +#include +#include +#include /* sometimes required for NULL */ + +#include "hostcompat.h" + +time_t +__time(time_t *secs, unsigned long *nsecs) +{ + struct timeval tv; + if (gettimeofday(&tv, NULL) < 0) { + return -1; + } + if (secs) { + *secs = tv.tv_sec; + } + if (nsecs) { + *nsecs = tv.tv_usec * 1000; + } + return tv.tv_sec; +} diff --git a/userland/lib/libc/Makefile b/userland/lib/libc/Makefile new file mode 100644 index 0000000..1d25230 --- /dev/null +++ b/userland/lib/libc/Makefile @@ -0,0 +1,132 @@ +# +# Makefile for OS/161 C standard library +# + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +COMMON=$(TOP)/common/libc + +# printf +SRCS+=\ + $(COMMON)/printf/__printf.c \ + $(COMMON)/printf/snprintf.c + +# stdio +SRCS+=\ + stdio/__puts.c \ + stdio/getchar.c \ + stdio/printf.c \ + stdio/putchar.c \ + stdio/puts.c + +# stdlib +SRCS+=\ + stdlib/abort.c \ + $(COMMON)/stdlib/atoi.c \ + stdlib/exit.c \ + stdlib/getenv.c \ + stdlib/malloc.c \ + stdlib/qsort.c \ + stdlib/random.c \ + stdlib/system.c + +# string +SRCS+=\ + $(COMMON)/string/bzero.c \ + string/memcmp.c \ + $(COMMON)/string/memcpy.c \ + $(COMMON)/string/memmove.c \ + $(COMMON)/string/memset.c \ + $(COMMON)/string/strcat.c \ + $(COMMON)/string/strchr.c \ + $(COMMON)/string/strcmp.c \ + $(COMMON)/string/strcpy.c \ + string/strerror.c \ + $(COMMON)/string/strlen.c \ + $(COMMON)/string/strrchr.c \ + string/strtok.c \ + $(COMMON)/string/strtok_r.c + +# time +SRCS+=\ + time/time.c + +# system call stubs +SRCS+=\ + $(MYBUILDDIR)/syscalls.S + +# gcc support +COMMONGCC=$(TOP)/common/gcc-millicode +SRCS+=\ + $(COMMONGCC)/adddi3.c \ + $(COMMONGCC)/anddi3.c \ + $(COMMONGCC)/ashldi3.c \ + $(COMMONGCC)/ashrdi3.c \ + $(COMMONGCC)/cmpdi2.c \ + $(COMMONGCC)/divdi3.c \ + $(COMMONGCC)/iordi3.c \ + $(COMMONGCC)/lshldi3.c \ + $(COMMONGCC)/lshrdi3.c \ + $(COMMONGCC)/moddi3.c \ + $(COMMONGCC)/muldi3.c \ + $(COMMONGCC)/negdi2.c \ + $(COMMONGCC)/notdi2.c \ + $(COMMONGCC)/qdivrem.c \ + $(COMMONGCC)/subdi3.c \ + $(COMMONGCC)/ucmpdi2.c \ + $(COMMONGCC)/udivdi3.c \ + $(COMMONGCC)/umoddi3.c \ + $(COMMONGCC)/xordi3.c + + +# other stuff +SRCS+=\ + unix/__assert.c \ + unix/err.c \ + unix/errno.c \ + unix/execvp.c \ + unix/getcwd.c \ + $(COMMON)/arch/mips/setjmp.S + +# Name of the library. +LIB=c + +# Let the templates do most of the work. +.include "$(TOP)/mk/os161.lib.mk" + +# +# Generate syscall entry points from system call list. +# +# Note that this will bomb if the kernel headers haven't been +# installed into the staging area. +# + +SYSCALL_H=$(INSTALLTOP)/include/kern/syscall.h + +# This is not ideal as it won't rebuild syscalls.S if defs.mk is removed. +# But it's better than failing if defs.mk is not present. +.if exists($(TOP)/defs.mk) +$(MYBUILDDIR)/syscalls.S: $(TOP)/defs.mk +.endif +$(MYBUILDDIR)/syscalls.S: $(SYSCALL_H) +$(MYBUILDDIR)/syscalls.S: syscalls/gensyscalls.sh +$(MYBUILDDIR)/syscalls.S: arch/$(MACHINE)/syscalls-$(MACHINE).S + -rm -f $@ $@.tmp + echo '/* Automatically generated; do not edit */' > $@.tmp + cat arch/$(MACHINE)/syscalls-$(MACHINE).S >> $@.tmp + syscalls/gensyscalls.sh < $(SYSCALL_H) >> $@.tmp + mv -f $@.tmp $@ + +clean: cleanhere +cleanhere: + rm -f $(MYBUILDDIR)/syscalls.S + +predepend: + $(MAKE) $(MYBUILDDIR)/syscalls.S + +.PHONY: clean cleanhere depend predepend + +# Have the machine-dependent stuff depend on defs.mk in case MACHINE +# or PLATFORM changes. +setjmp.o: $(TOP)/defs.mk diff --git a/userland/lib/libc/arch/mips/syscalls-mips.S b/userland/lib/libc/arch/mips/syscalls-mips.S new file mode 100644 index 0000000..f7fb3b8 --- /dev/null +++ b/userland/lib/libc/arch/mips/syscalls-mips.S @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This file is copied to syscalls.S, and then the actual syscalls are + * appended as lines of the form + * SYSCALL(symbol, number) + * + * Warning: gccs before 3.0 run cpp in -traditional mode on .S files. + * So if you use an older gcc you'll need to change the token pasting + * in SYSCALL(). + */ + +#include +#include + +/* + * Definition for each syscall. + * All we do is load the syscall number into v0, the register the + * kernel expects to find it in, and jump to the shared syscall code. + * (Note that the addiu instruction is in the jump's delay slot.) + */ +#define SYSCALL(sym, num) \ + .set noreorder ; \ + .globl sym ; \ + .type sym,@function ; \ + .ent sym ; \ +sym: ; \ + j __syscall ; \ + addiu v0, $0, SYS_##sym ; \ + .end sym ; \ + .set reorder + +/* + * Now, the shared system call code. + * The MIPS syscall ABI is as follows: + * + * On entry, call number in v0. The rest is like a normal function + * call: four args in a0-a3, the other args on the stack. + * + * On successful return, zero in a3 register; return value in v0 + * (v0 and v1 for a 64-bit return value). + * + * On error return, nonzero in a3 register; errno value in v0. + * + * The use of a3 as a return register to hold the success flag is + * gross, but I didn't make it up. + * + * Note that by longstanding Unix convention and POSIX decree, errno + * is not to be set unless the call actually fails. + */ + + .set noreorder + .text + .type __syscall,@function + .ent __syscall +__syscall: + syscall /* make system call */ + beq a3, $0, 1f /* if a3 is zero, call succeeded */ + nop /* delay slot */ + sw v0, errno /* call failed: store errno */ + li v1, -1 /* and force return value to -1 */ + li v0, -1 +1: + j ra /* return */ + nop /* delay slot */ + .end __syscall + .set reorder + diff --git a/userland/lib/libc/stdio/__puts.c b/userland/lib/libc/stdio/__puts.c new file mode 100644 index 0000000..6db7ea8 --- /dev/null +++ b/userland/lib/libc/stdio/__puts.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2015 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +/* + * Nonstandard (hence the __) version of puts that doesn't append + * a newline. + * + * Returns the length of the string printed. + */ + +int +__puts(const char *str) +{ + size_t len; + ssize_t ret; + + len = strlen(str); + ret = write(STDOUT_FILENO, str, len); + if (ret == -1) { + return EOF; + } + return len; +} diff --git a/userland/lib/libc/stdio/getchar.c b/userland/lib/libc/stdio/getchar.c new file mode 100644 index 0000000..4f6c94c --- /dev/null +++ b/userland/lib/libc/stdio/getchar.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * C standard I/O function - read character from stdin + * and return it or the symbolic constant EOF (-1). + */ + +int +getchar(void) +{ + char ch; + int len; + + len = read(STDIN_FILENO, &ch, 1); + if (len<=0) { + /* end of file or error */ + return EOF; + } + + /* + * Cast through unsigned char, to prevent sign extension. This + * sends back values on the range 0-255, rather than -128 to 127, + * so EOF can be distinguished from legal input. + */ + return (int)(unsigned char)ch; +} diff --git a/userland/lib/libc/stdio/printf.c b/userland/lib/libc/stdio/printf.c new file mode 100644 index 0000000..f0d627b --- /dev/null +++ b/userland/lib/libc/stdio/printf.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2015 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +/* + * printf - C standard I/O function. + */ + + +/* + * Function passed to __vprintf to do the actual output. + */ +static +void +__printf_send(void *mydata, const char *data, size_t len) +{ + ssize_t ret; + int *err = mydata; + + ret = write(STDOUT_FILENO, data, len); + *err = (ret == -1) ? errno : 0; +} + +/* printf: hand off to vprintf */ +int +printf(const char *fmt, ...) +{ + int chars; + va_list ap; + + va_start(ap, fmt); + chars = vprintf(fmt, ap); + va_end(ap); + return chars; +} + +/* vprintf: call __vprintf to do the work. */ +int +vprintf(const char *fmt, va_list ap) +{ + int chars, err; + chars = __vprintf(__printf_send, &err, fmt, ap); + if (err) { + errno = err; + return -1; + } + return chars; +} diff --git a/userland/lib/libc/stdio/putchar.c b/userland/lib/libc/stdio/putchar.c new file mode 100644 index 0000000..977cdde --- /dev/null +++ b/userland/lib/libc/stdio/putchar.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * C standard function - print a single character. + * + * Properly, stdio is supposed to be buffered, but for present purposes + * writing that code is not really worthwhile. + */ + +int +putchar(int ch) +{ + char c = ch; + int len; + len = write(STDOUT_FILENO, &c, 1); + if (len<=0) { + return EOF; + } + return ch; +} diff --git a/userland/lib/libc/stdio/puts.c b/userland/lib/libc/stdio/puts.c new file mode 100644 index 0000000..8b5724f --- /dev/null +++ b/userland/lib/libc/stdio/puts.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * C standard I/O function - print a string and a newline. + */ + +int +puts(const char *s) +{ + __puts(s); + putchar('\n'); + return 0; +} diff --git a/userland/lib/libc/stdlib/abort.c b/userland/lib/libc/stdlib/abort.c new file mode 100644 index 0000000..807de26 --- /dev/null +++ b/userland/lib/libc/stdlib/abort.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * C standard function: panic exit from a user program. + * + * On most Unix systems, this sends the current process a fatal signal. + * We can't do that (no signals in OS/161) so we just exit with a + * nonzero exit code, skipping any libc cleanup. + */ + +void +abort(void) +{ + _exit(255); +} diff --git a/userland/lib/libc/stdlib/exit.c b/userland/lib/libc/stdlib/exit.c new file mode 100644 index 0000000..8838aad --- /dev/null +++ b/userland/lib/libc/stdlib/exit.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * C standard function: exit process. + */ + +void +exit(int code) +{ + /* + * In a more complicated libc, this would call functions registered + * with atexit() before calling the syscall to actually exit. + */ + +#ifdef __mips__ + /* + * Because gcc knows that _exit doesn't return, if we call it + * directly it will drop any code that follows it. This means + * that if _exit *does* return, as happens before it's + * implemented, undefined and usually weird behavior ensues. + * + * As a hack (this is quite gross) do the call by hand in an + * asm block. Then gcc doesn't know what it is, and won't + * optimize the following code out, and we can make sure + * that exit() at least really does not return. + * + * This asm block violates gcc's asm rules by destroying a + * register it doesn't declare ($4, which is a0) but this + * hopefully doesn't matter as the only local it can lose + * track of is "code" and we don't use it afterwards. + */ + __asm volatile("jal _exit;" /* call _exit */ + "move $4, %0" /* put code in a0 (delay slot) */ + : /* no outputs */ + : "r" (code)); /* code is an input */ + /* + * Ok, exiting doesn't work; see if we can get our process + * killed by making an illegal memory access. Use a magic + * number address so the symptoms are recognizable and + * unlikely to occur by accident otherwise. + */ + __asm volatile("li $2, 0xeeeee00f;" /* load magic addr into v0 */ + "lw $2, 0($2)" /* fetch from it */ + :: ); /* no args */ +#else + _exit(code); +#endif + /* + * We can't return; so if we can't exit, the only other choice + * is to loop. + */ + while (1) { } +} diff --git a/userland/lib/libc/stdlib/getenv.c b/userland/lib/libc/stdlib/getenv.c new file mode 100644 index 0000000..1eda471 --- /dev/null +++ b/userland/lib/libc/stdlib/getenv.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * getenv(): ANSI C + * + * Get an environment variable. + */ + +/* + * This is initialized by crt0, though it actually lives in errno.c + */ +extern char **__environ; + +/* + * This is what we use by default if the kernel didn't supply an + * environment. + */ +static const char *__default_environ[] = { + "PATH=/bin:/sbin:/testbin", + "SHELL=/bin/sh", + "TERM=vt220", + NULL +}; + +char * +getenv(const char *var) +{ + size_t varlen, thislen; + char *s; + unsigned i; + + if (__environ == NULL) { + __environ = (char **)__default_environ; + } + varlen = strlen(var); + for (i=0; __environ[i] != NULL; i++) { + s = strchr(__environ[i], '='); + if (s == NULL) { + /* ? */ + continue; + } + thislen = s - __environ[i]; + if (thislen == varlen && !memcmp(__environ[i], var, thislen)) { + return s + 1; + } + } + return NULL; +} diff --git a/userland/lib/libc/stdlib/malloc.c b/userland/lib/libc/stdlib/malloc.c new file mode 100644 index 0000000..4a21153 --- /dev/null +++ b/userland/lib/libc/stdlib/malloc.c @@ -0,0 +1,591 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * User-level malloc and free implementation. + * + * This is a basic first-fit allocator. It's intended to be simple and + * easy to follow. It performs abysmally if the heap becomes larger than + * physical memory. To get (much) better out-of-core performance, port + * the kernel's malloc. :-) + */ + +#include +#include // for uintptr_t on non-OS/161 platforms +#include +#include +#include + +#undef MALLOCDEBUG + +#if defined(__mips__) || defined(__i386__) +#define MALLOC32 +#elif defined(__alpha__) || defined(__x86_64__) +#define MALLOC64 +#else +#error "please fix me" +#endif + +/* + * malloc block header. + * + * mh_prevblock is the downwards offset to the previous header, 0 if this + * is the bottom of the heap. + * + * mh_nextblock is the upwards offset to the next header. + * + * mh_pad is unused. + * mh_inuse is 1 if the block is in use, 0 if it is free. + * mh_magic* should always be a fixed value. + * + * MBLOCKSIZE should equal sizeof(struct mheader) and be a power of 2. + * MBLOCKSHIFT is the log base 2 of MBLOCKSIZE. + * MMAGIC is the value for mh_magic*. + */ +struct mheader { + +#if defined(MALLOC32) +#define MBLOCKSIZE 8 +#define MBLOCKSHIFT 3 +#define MMAGIC 2 + /* + * 32-bit platform. size_t is 32 bits (4 bytes). + * Block size is 8 bytes. + */ + unsigned mh_prevblock:29; + unsigned mh_pad:1; + unsigned mh_magic1:2; + + unsigned mh_nextblock:29; + unsigned mh_inuse:1; + unsigned mh_magic2:2; + +#elif defined(MALLOC64) +#define MBLOCKSIZE 16 +#define MBLOCKSHIFT 4 +#define MMAGIC 6 + /* + * 64-bit platform. size_t is 64 bits (8 bytes) + * Block size is 16 bytes. + */ + unsigned mh_prevblock:60; + unsigned mh_pad:1; + unsigned mh_magic1:3; + + unsigned mh_nextblock:60; + unsigned mh_inuse:1; + unsigned mh_magic2:3; + +#else +#error "please fix me" +#endif +}; + +/* + * Operator macros on struct mheader. + * + * M_NEXT/PREVOFF: return offset to next/previous header + * M_NEXT/PREV: return next/previous header + * + * M_DATA: return data pointer of a header + * M_SIZE: return data size of a header + * + * M_OK: true if the magic values are correct + * + * M_MKFIELD: prepare a value for mh_next/prevblock. + * (value should include the header size) + */ + +#define M_NEXTOFF(mh) ((size_t)(((size_t)((mh)->mh_nextblock))<mh_prevblock))<mh_magic1==MMAGIC && (mh)->mh_magic2==MMAGIC) + +#define M_MKFIELD(off) ((off)>>MBLOCKSHIFT) + +/* + * System page size. In POSIX you're supposed to call + * sysconf(_SC_PAGESIZE). If _SC_PAGESIZE isn't defined, as on OS/161, + * assume 4K. + */ + +#ifdef _SC_PAGESIZE +static size_t __malloc_pagesize; +#define PAGE_SIZE __malloc_pagesize +#else +#define PAGE_SIZE 4096 +#endif + +//////////////////////////////////////////////////////////// + +/* + * Static variables - the bottom and top addresses of the heap. + */ +static uintptr_t __heapbase, __heaptop; + +/* + * Setup function. + */ +static +void +__malloc_init(void) +{ + void *x; + + /* + * Check various assumed properties of the sizes. + */ + if (sizeof(struct mheader) != MBLOCKSIZE) { + errx(1, "malloc: Internal error - MBLOCKSIZE wrong"); + } + if ((MBLOCKSIZE & (MBLOCKSIZE-1))!=0) { + errx(1, "malloc: Internal error - MBLOCKSIZE not power of 2"); + } + if (1<mh_prevblock != rightprevblock) { + errx(1, "malloc: Heap corrupt; header at 0x%lx" + " has bad previous-block size %lu " + "(should be %lu)", + (unsigned long) i, + (unsigned long) mh->mh_prevblock << MBLOCKSHIFT, + (unsigned long) rightprevblock << MBLOCKSHIFT); + } + rightprevblock = mh->mh_nextblock; + + warnx("heap: 0x%lx 0x%-6lx (next: 0x%lx) %s", + (unsigned long) i + MBLOCKSIZE, + (unsigned long) M_SIZE(mh), + (unsigned long) (i+M_NEXTOFF(mh)), + mh->mh_inuse ? "INUSE" : "FREE"); + } + if (i!=__heaptop) { + errx(1, "malloc: Heap corrupt; ran off end"); + } + + warnx("heap: ************************************************"); +} + +#endif /* MALLOCDEBUG */ + +//////////////////////////////////////////////////////////// + +/* + * Get more memory (at the top of the heap) using sbrk, and + * return a pointer to it. + */ +static +void * +__malloc_sbrk(size_t size) +{ + void *x; + + x = sbrk(size); + if (x == (void *)-1) { + return NULL; + } + + if ((uintptr_t)x != __heaptop) { + errx(1, "malloc: Internal error - " + "heap top moved itself from 0x%lx to 0x%lx", + (unsigned long) __heaptop, + (unsigned long) (uintptr_t) x); + } + __heaptop += size; + return x; +} + +/* + * Make a new (free) block from the block passed in, leaving size + * bytes for data in the current block. size must be a multiple of + * MBLOCKSIZE. + * + * Only split if the excess space is at least twice the blocksize - + * one blocksize to hold a header and one for data. + */ +static +void +__malloc_split(struct mheader *mh, size_t size) +{ + struct mheader *mhnext, *mhnew; + size_t oldsize; + + if (size % MBLOCKSIZE != 0) { + errx(1, "malloc: Internal error (size %lu passed to split)", + (unsigned long) size); + } + + if (M_SIZE(mh) - size < 2*MBLOCKSIZE) { + /* no room */ + return; + } + + mhnext = M_NEXT(mh); + + oldsize = M_SIZE(mh); + mh->mh_nextblock = M_MKFIELD(size + MBLOCKSIZE); + + mhnew = M_NEXT(mh); + if (mhnew==mhnext) { + errx(1, "malloc: Internal error (split screwed up?)"); + } + + mhnew->mh_prevblock = M_MKFIELD(size + MBLOCKSIZE); + mhnew->mh_pad = 0; + mhnew->mh_magic1 = MMAGIC; + mhnew->mh_nextblock = M_MKFIELD(oldsize - size); + mhnew->mh_inuse = 0; + mhnew->mh_magic2 = MMAGIC; + + if (mhnext != (struct mheader *) __heaptop) { + mhnext->mh_prevblock = mhnew->mh_nextblock; + } +} + +/* + * malloc itself. + */ +void * +malloc(size_t size) +{ + struct mheader *mh; + uintptr_t i; + size_t rightprevblock; + size_t morespace; + void *p; + + if (__heapbase==0) { + __malloc_init(); + } + if (__heapbase==0 || __heaptop==0 || __heapbase > __heaptop) { + warnx("malloc: Internal error - local data corrupt"); + errx(1, "malloc: heapbase 0x%lx; heaptop 0x%lx", + (unsigned long) __heapbase, (unsigned long) __heaptop); + } + +#ifdef MALLOCDEBUG + warnx("malloc: about to allocate %lu (0x%lx) bytes", + (unsigned long) size, (unsigned long) size); + __malloc_dump(); +#endif + + /* Round size up to an integral number of blocks. */ + size = ((size + MBLOCKSIZE - 1) & ~(size_t)(MBLOCKSIZE-1)); + + /* + * First-fit search algorithm for available blocks. + * Check to make sure the next/previous sizes all agree. + */ + rightprevblock = 0; + mh = NULL; + for (i=__heapbase; i<__heaptop; i += M_NEXTOFF(mh)) { + mh = (struct mheader *) i; + if (!M_OK(mh)) { + errx(1, "malloc: Heap corrupt; header at 0x%lx" + " has bad magic bits", + (unsigned long) i); + } + if (mh->mh_prevblock != rightprevblock) { + errx(1, "malloc: Heap corrupt; header at 0x%lx" + " has bad previous-block size %lu " + "(should be %lu)", + (unsigned long) i, + (unsigned long) mh->mh_prevblock << MBLOCKSHIFT, + (unsigned long) rightprevblock << MBLOCKSHIFT); + } + rightprevblock = mh->mh_nextblock; + + /* Can't allocate a block that's in use. */ + if (mh->mh_inuse) { + continue; + } + + /* Can't allocate a block that isn't big enough. */ + if (M_SIZE(mh) < size) { + continue; + } + + /* Try splitting block. */ + __malloc_split(mh, size); + + /* + * Now, allocate. + */ + mh->mh_inuse = 1; + +#ifdef MALLOCDEBUG + warnx("malloc: allocating at %p", M_DATA(mh)); + __malloc_dump(); +#endif + return M_DATA(mh); + } + if (i!=__heaptop) { + errx(1, "malloc: Heap corrupt; ran off end"); + } + + /* + * Didn't find anything. Expand the heap. + * + * If the heap is nonempty and the top block (the one mh is + * left pointing to after the above loop) is free, we can + * expand it. Otherwise we need a new block. + */ + if (mh != NULL && !mh->mh_inuse) { + assert(size > M_SIZE(mh)); + morespace = size - M_SIZE(mh); + } + else { + morespace = MBLOCKSIZE + size; + } + + /* Round the amount of space we ask for up to a whole page. */ + morespace = PAGE_SIZE * ((morespace + PAGE_SIZE - 1) / PAGE_SIZE); + + p = __malloc_sbrk(morespace); + if (p == NULL) { + return NULL; + } + + if (mh != NULL && !mh->mh_inuse) { + /* update old header */ + mh->mh_nextblock = M_MKFIELD(M_NEXTOFF(mh) + morespace); + mh->mh_inuse = 1; + } + else { + /* fill out new header */ + mh = p; + mh->mh_prevblock = rightprevblock; + mh->mh_magic1 = MMAGIC; + mh->mh_magic2 = MMAGIC; + mh->mh_pad = 0; + mh->mh_inuse = 1; + mh->mh_nextblock = M_MKFIELD(morespace); + } + + /* + * Either way, try splitting the block we got as because of + * the page rounding it might be quite a bit bigger than we + * needed. + */ + __malloc_split(mh, size); + +#ifdef MALLOCDEBUG + warnx("malloc: allocating at %p", M_DATA(mh)); + __malloc_dump(); +#endif + return M_DATA(mh); +} + +//////////////////////////////////////////////////////////// + +/* + * Clear a range of memory with 0xdeadbeef. + * ptr must be suitably aligned. + */ +static +void +__malloc_deadbeef(void *ptr, size_t size) +{ + uint32_t *x = ptr; + size_t i, n = size/sizeof(uint32_t); + for (i=0; imh_nextblock != mhnext->mh_prevblock) { + errx(1, "free: Heap corrupt (%p and %p inconsistent)", + mh, mhnext); + } + if (mh->mh_inuse || mhnext->mh_inuse) { + /* can't merge */ + return; + } + + mhnextnext = M_NEXT(mhnext); + + mh->mh_nextblock = M_MKFIELD(MBLOCKSIZE + M_SIZE(mh) + + MBLOCKSIZE + M_SIZE(mhnext)); + + if (mhnextnext != (struct mheader *)__heaptop) { + mhnextnext->mh_prevblock = mh->mh_nextblock; + } + + /* Deadbeef out the memory used by the now-obsolete header */ + __malloc_deadbeef(mhnext, sizeof(struct mheader)); +} + +/* + * The actual free() implementation. + */ +void +free(void *x) +{ + struct mheader *mh, *mhnext, *mhprev; + + if (x==NULL) { + /* safest practice */ + return; + } + + /* Consistency check. */ + if (__heapbase==0 || __heaptop==0 || __heapbase > __heaptop) { + warnx("free: Internal error - local data corrupt"); + errx(1, "free: heapbase 0x%lx; heaptop 0x%lx", + (unsigned long) __heapbase, (unsigned long) __heaptop); + } + + /* Don't allow freeing pointers that aren't on the heap. */ + if ((uintptr_t)x < __heapbase || (uintptr_t)x >= __heaptop) { + errx(1, "free: Invalid pointer %p freed (out of range)", x); + } + +#ifdef MALLOCDEBUG + warnx("free: about to free %p", x); + __malloc_dump(); +#endif + + mh = ((struct mheader *)x)-1; + if (!M_OK(mh)) { + errx(1, "free: Invalid pointer %p freed (corrupt header)", x); + } + + if (!mh->mh_inuse) { + errx(1, "free: Invalid pointer %p freed (already free)", x); + } + + /* mark it free */ + mh->mh_inuse = 0; + + /* wipe it */ + __malloc_deadbeef(M_DATA(mh), M_SIZE(mh)); + + /* Try merging with the block above (but not if we're at the top) */ + mhnext = M_NEXT(mh); + if (mhnext != (struct mheader *)__heaptop) { + __malloc_trymerge(mh, mhnext); + } + + /* Try merging with the block below (but not if we're at the bottom) */ + if (mh != (struct mheader *)__heapbase) { + mhprev = M_PREV(mh); + __malloc_trymerge(mhprev, mh); + } + +#ifdef MALLOCDEBUG + warnx("free: freed %p", x); + __malloc_dump(); +#endif +} diff --git a/userland/lib/libc/stdlib/qsort.c b/userland/lib/libc/stdlib/qsort.c new file mode 100644 index 0000000..095ef7d --- /dev/null +++ b/userland/lib/libc/stdlib/qsort.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +/* + * qsort() for OS/161, where it isn't in libc. + */ +void +qsort(void *vdata, unsigned num, size_t size, + int (*f)(const void *, const void *)) +{ + unsigned pivot, head, tail; + char *data = vdata; + char tmp[size]; + +#define COMPARE(aa, bb) \ + ((aa) == (bb) ? 0 : f(data + (aa) * size, data + (bb) * size)) +#define EXCHANGE(aa, bb) \ + memcpy(tmp, data + (aa) * size, size); \ + memcpy(data + (aa) * size, data + (bb) * size, size); \ + memcpy(data + (bb) * size, tmp, size) + + + if (num <= 1) { + return; + } + if (num == 2) { + if (COMPARE(0, 1) > 0) { + EXCHANGE(0, 1); + return; + } + } + + /* + * 1. Pick a pivot value. For simplicity, always use the + * middle of the array. + */ + pivot = num / 2; + + /* + * 2. Shift all values less than or equal to the pivot value + * to the front of the array. + */ + head = 0; + tail = num - 1; + + while (head < tail) { + if (COMPARE(head, pivot) <= 0) { + head++; + } + else if (COMPARE(tail, pivot) > 0) { + tail--; + } + else { + EXCHANGE(head, tail); + if (pivot == head) { + pivot = tail; + } + else if (pivot == tail) { + pivot = head; + } + head++; + tail--; + } + } + + /* + * 3. If there's an even number of elements and we swapped the + * last two, the head and tail indexes will cross. In this + * case the first entry on the tail side is tail+1. If there's + * an odd number of elements, we stop with head == tail, and + * the first entry on the tail side is this value (hence, + * tail) if it's is greater than the pivot value, and the next + * element (hence, tail+1) if it's less than or equal to the + * pivot value. + * + * Henceforth use "tail" to hold the index of the first entry + * of the back portion of the array. + */ + if (head > tail || COMPARE(head, pivot) <= 0) { + tail++; + } + + /* + * 4. If we got a bad pivot that gave us only one partition, + * because of the order of the advances in the loop above it + * will always put everything in the front portion of the + * array (so tail == num). This happens if we picked the + * largest value. Move the pivot to the end, if necessary, lop + * off all values equal to it, and recurse on the rest. (If + * there is no rest, the array is already sorted and we're + * done.) + */ + if (tail == num) { + if (pivot < num - 1) { + if (COMPARE(pivot, num - 1) > 0) { + EXCHANGE(pivot, num - 1); + } + } + tail = num - 1; + while (tail > 0 && COMPARE(tail - 1, tail) == 0) { + tail--; + } + if (tail > 0) { + qsort(vdata, tail, size, f); + } + return; + } + assert(tail > 0 && tail < num); + + /* + * 5. Recurse on each subpart of the array. + */ + qsort(vdata, tail, size, f); + qsort((char *)vdata + tail * size, num - tail, size, f); +} diff --git a/userland/lib/libc/stdlib/random.c b/userland/lib/libc/stdlib/random.c new file mode 100644 index 0000000..7253813 --- /dev/null +++ b/userland/lib/libc/stdlib/random.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * From: + * NetBSD: random.c,v 1.19 2000/01/22 22:19:20 mycroft Exp + * + * Hacked gruesomely for OS/161. + */ + +#include +#include +#include + +/* + * For a thread-safe libc, declare a lock for this file and change + * these to be nonempty. + */ +#define LOCKME() +#define UNLOCKME() + +static void srandom_unlocked(unsigned long); +static long random_unlocked(void); + + +/* + * random.c: + * + * An improved random number generation package. In addition to the standard + * rand()/srand() like interface, this package also has a special state info + * interface. The initstate() routine is called with a seed, an array of + * bytes, and a count of how many bytes are being passed in; this array is + * then initialized to contain information for random number generation with + * that much state information. Good sizes for the amount of state + * information are 32, 64, 128, and 256 bytes. The state can be switched by + * calling the setstate() routine with the same array as was initiallized + * with initstate(). By default, the package runs with 128 bytes of state + * information and generates far better random numbers than a linear + * congruential generator. If the amount of state information is less than + * 32 bytes, a simple linear congruential R.N.G. is used. + * + * Internally, the state information is treated as an array of longs; the + * zeroeth element of the array is the type of R.N.G. being used (small + * integer); the remainder of the array is the state information for the + * R.N.G. Thus, 32 bytes of state information will give 7 longs worth of + * state information, which will allow a degree seven polynomial. (Note: + * the zeroeth word of state information also has some other information + * stored in it -- see setstate() for details). + * + * The random number generation technique is a linear feedback shift register + * approach, employing trinomials (since there are fewer terms to sum up that + * way). In this approach, the least significant bit of all the numbers in + * the state table will act as a linear feedback shift register, and will + * have period 2^deg - 1 (where deg is the degree of the polynomial being + * used, assuming that the polynomial is irreducible and primitive). The + * higher order bits will have longer periods, since their values are also + * influenced by pseudo-random carries out of the lower bits. The total + * period of the generator is approximately deg*(2**deg - 1); thus doubling + * the amount of state information has a vast influence on the period of the + * generator. Note: the deg*(2**deg - 1) is an approximation only good for + * large deg, when the period of the shift register is the dominant factor. + * With deg equal to seven, the period is actually much longer than the + * 7*(2**7 - 1) predicted by this formula. + * + * Modified 28 December 1994 by Jacob S. Rosenberg. + * The following changes have been made: + * All references to the type u_int have been changed to unsigned long. + * All references to type int have been changed to type long. Other + * cleanups have been made as well. A warning for both initstate and + * setstate has been inserted to the effect that on Sparc platforms + * the 'arg_state' variable must be forced to begin on word boundaries. + * This can be easily done by casting a long integer array to char *. + * The overall logic has been left STRICTLY alone. This software was + * tested on both a VAX and Sun SpacsStation with exactly the same + * results. The new version and the original give IDENTICAL results. + * The new version is somewhat faster than the original. As the + * documentation says: "By default, the package runs with 128 bytes of + * state information and generates far better random numbers than a linear + * congruential generator. If the amount of state information is less than + * 32 bytes, a simple linear congruential R.N.G. is used." For a buffer of + * 128 bytes, this new version runs about 19 percent faster and for a 16 + * byte buffer it is about 5 percent faster. + */ + +/* + * For each of the currently supported random number generators, we have a + * break value on the amount of state information (you need at least this + * many bytes of state info to support this random number generator), a degree + * for the polynomial (actually a trinomial) that the R.N.G. is based on, and + * the separation between the two lower order coefficients of the trinomial. + */ +#define TYPE_0 0 /* linear congruential */ +#define BREAK_0 8 +#define DEG_0 0 +#define SEP_0 0 + +#define TYPE_1 1 /* x**7 + x**3 + 1 */ +#define BREAK_1 32 +#define DEG_1 7 +#define SEP_1 3 + +#define TYPE_2 2 /* x**15 + x + 1 */ +#define BREAK_2 64 +#define DEG_2 15 +#define SEP_2 1 + +#define TYPE_3 3 /* x**31 + x**3 + 1 */ +#define BREAK_3 128 +#define DEG_3 31 +#define SEP_3 3 + +#define TYPE_4 4 /* x**63 + x + 1 */ +#define BREAK_4 256 +#define DEG_4 63 +#define SEP_4 1 + +/* + * Array versions of the above information to make code run faster -- + * relies on fact that TYPE_i == i. + */ +#define MAX_TYPES 5 /* max number of types above */ + +static const int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; +static const int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; + +/* + * Initially, everything is set up as if from: + * + * initstate(1, &randtbl, 128); + * + * Note that this initialization takes advantage of the fact that srandom() + * advances the front and rear pointers 10*rand_deg times, and hence the + * rear pointer which starts at 0 will also end up at zero; thus the zeroeth + * element of the state information, which contains info about the current + * position of the rear pointer is just + * + * MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3. + */ + +static long randtbl[DEG_3 + 1] = { + TYPE_3, + (long)0x9a319039L, (long)0x32d9c024L, (long)0x9b663182L, + (long)0x5da1f342L, (long)0xde3b81e0L, (long)0xdf0a6fb5L, + (long)0xf103bc02L, (long)0x48f340fbL, (long)0x7449e56bL, + (long)0xbeb1dbb0L, (long)0xab5c5918L, (long)0x946554fdL, + (long)0x8c2e680fL, (long)0xeb3d799fL, (long)0xb11ee0b7L, + (long)0x2d436b86L, (long)0xda672e2aL, (long)0x1588ca88L, + (long)0xe369735dL, (long)0x904f35f7L, (long)0xd7158fd6L, + (long)0x6fa6f051L, (long)0x616e6b96L, (long)0xac94efdcL, + (long)0x36413f93L, (long)0xc622c298L, (long)0xf5a42ab8L, + (long)0x8a88d77bL, (long)0xf5ad9d0eL, (long)0x8999220bL, + (long)0x27fb47b9L, +}; + +/* + * fptr and rptr are two pointers into the state info, a front and a rear + * pointer. These two pointers are always rand_sep places aparts, as they + * cycle cyclically through the state information. (Yes, this does mean we + * could get away with just one pointer, but the code for random() is more + * efficient this way). The pointers are left positioned as they would be + * from the call + * + * initstate(1, randtbl, 128); + * + * (The position of the rear pointer, rptr, is really 0 (as explained above + * in the initialization of randtbl) because the state table pointer is set + * to point to randtbl[1] (as explained below). + */ +static long *fptr = &randtbl[SEP_3 + 1]; +static long *rptr = &randtbl[1]; + +/* + * The following things are the pointer to the state information table, the + * type of the current generator, the degree of the current polynomial being + * used, and the separation between the two pointers. Note that for efficiency + * of random(), we remember the first location of the state information, not + * the zeroeth. Hence it is valid to access state[-1], which is used to + * store the type of the R.N.G. Also, we remember the last location, since + * this is more efficient than indexing every time to find the address of + * the last element to see if the front and rear pointers have wrapped. + */ +static long *state = &randtbl[1]; +static long rand_type = TYPE_3; +static int rand_deg = DEG_3; +static int rand_sep = SEP_3; +static long *end_ptr = &randtbl[DEG_3 + 1]; + +/* + * srandom: + * + * Initialize the random number generator based on the given seed. If the + * type is the trivial no-state-information type, just remember the seed. + * Otherwise, initializes state[] based on the given "seed" via a linear + * congruential generator. Then, the pointers are set to known locations + * that are exactly rand_sep places apart. Lastly, it cycles the state + * information a given number of times to get rid of any initial dependencies + * introduced by the L.C.R.N.G. Note that the initialization of randtbl[] + * for default usage relies on values produced by this routine. + */ +static +void +srandom_unlocked(unsigned long x) +{ + int i; + + if (rand_type == TYPE_0) + state[0] = x; + else { + state[0] = x; + for (i = 1; i < rand_deg; i++) + state[i] = 1103515245L * state[i - 1] + 12345L; + fptr = &state[rand_sep]; + rptr = &state[0]; + for (i = 0; i < 10 * rand_deg; i++) + (void)random_unlocked(); + } +} + +void +srandom(unsigned long x) +{ + + LOCKME(); + srandom_unlocked(x); + UNLOCKME(); +} + +/* + * initstate: + * + * Initialize the state information in the given array of n bytes for future + * random number generation. Based on the number of bytes we are given, and + * the break values for the different R.N.G.'s, we choose the best (largest) + * one we can and set things up for it. srandom() is then called to + * initialize the state information. + * + * Note that on return from srandom(), we set state[-1] to be the type + * multiplexed with the current value of the rear pointer; this is so + * successive calls to initstate() won't lose this information and will be + * able to restart with setstate(). + * + * Note: the first thing we do is save the current state, if any, just like + * setstate() so that it doesn't matter when initstate is called. + * + * Returns a pointer to the old state. + * + * Note: The Sparc platform requires that arg_state begin on a long + * word boundary; otherwise a bus error will occur. Even so, lint will + * complain about mis-alignment, but you should disregard these messages. + */ +char * +initstate( + unsigned long seed, /* seed for R.N.G. */ + char *arg_state, /* pointer to state array */ + size_t n) /* # bytes of state info */ +{ + void *ostate = (void *)(&state[-1]); + long *long_arg_state; + + assert(arg_state != NULL); + + long_arg_state = (long *)(void *)arg_state; + + LOCKME(); + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = MAX_TYPES * (rptr - state) + rand_type; + if (n < BREAK_0) { + UNLOCKME(); + return (NULL); + } else if (n < BREAK_1) { + rand_type = TYPE_0; + rand_deg = DEG_0; + rand_sep = SEP_0; + } else if (n < BREAK_2) { + rand_type = TYPE_1; + rand_deg = DEG_1; + rand_sep = SEP_1; + } else if (n < BREAK_3) { + rand_type = TYPE_2; + rand_deg = DEG_2; + rand_sep = SEP_2; + } else if (n < BREAK_4) { + rand_type = TYPE_3; + rand_deg = DEG_3; + rand_sep = SEP_3; + } else { + rand_type = TYPE_4; + rand_deg = DEG_4; + rand_sep = SEP_4; + } + state = (long *) (long_arg_state + 1); /* first location */ + end_ptr = &state[rand_deg]; /* must set end_ptr before srandom */ + srandom_unlocked(seed); + if (rand_type == TYPE_0) + long_arg_state[0] = rand_type; + else + long_arg_state[0] = MAX_TYPES * (rptr - state) + rand_type; + UNLOCKME(); + return((char *)ostate); +} + +/* + * setstate: + * + * Restore the state from the given state array. + * + * Note: it is important that we also remember the locations of the pointers + * in the current state information, and restore the locations of the pointers + * from the old state information. This is done by multiplexing the pointer + * location into the zeroeth word of the state information. + * + * Note that due to the order in which things are done, it is OK to call + * setstate() with the same state as the current state. + * + * Returns a pointer to the old state information. + * + * Note: The Sparc platform requires that arg_state begin on a long + * word boundary; otherwise a bus error will occur. Even so, lint will + * complain about mis-alignment, but you should disregard these messages. + */ +char * +setstate(char *arg_state) /* pointer to state array */ +{ + long *new_state; + int type; + int rear; + void *ostate = (void *)(&state[-1]); + + assert(arg_state != NULL); + + new_state = (long *)(void *)arg_state; + type = (int)(new_state[0] % MAX_TYPES); + rear = (int)(new_state[0] / MAX_TYPES); + + LOCKME(); + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = MAX_TYPES * (rptr - state) + rand_type; + switch(type) { + case TYPE_0: + case TYPE_1: + case TYPE_2: + case TYPE_3: + case TYPE_4: + rand_type = type; + rand_deg = degrees[type]; + rand_sep = seps[type]; + break; + default: + UNLOCKME(); + return (NULL); + } + state = (long *) (new_state + 1); + if (rand_type != TYPE_0) { + rptr = &state[rear]; + fptr = &state[(rear + rand_sep) % rand_deg]; + } + end_ptr = &state[rand_deg]; /* set end_ptr too */ + UNLOCKME(); + return((char *)ostate); +} + +/* + * random: + * + * If we are using the trivial TYPE_0 R.N.G., just do the old linear + * congruential bit. Otherwise, we do our fancy trinomial stuff, which is + * the same in all the other cases due to all the global variables that have + * been set up. The basic operation is to add the number at the rear pointer + * into the one at the front pointer. Then both pointers are advanced to + * the next location cyclically in the table. The value returned is the sum + * generated, reduced to 31 bits by throwing away the "least random" low bit. + * + * Note: the code takes advantage of the fact that both the front and + * rear pointers can't wrap on the same call by not testing the rear + * pointer if the front one has wrapped. + * + * Returns a 31-bit random number. + */ +static +long +random_unlocked(void) +{ + long i; + long *f, *r; + + if (rand_type == TYPE_0) { + i = state[0]; + state[0] = i = (i * 1103515245L + 12345L) & 0x7fffffff; + } else { + /* + * Use local variables rather than static variables for speed. + */ + f = fptr; r = rptr; + *f += *r; + /* chucking least random bit */ + i = ((unsigned long)*f >> 1) & 0x7fffffff; + if (++f >= end_ptr) { + f = state; + ++r; + } + else if (++r >= end_ptr) { + r = state; + } + + fptr = f; rptr = r; + } + return(i); +} + +long +random(void) +{ + long r; + + LOCKME(); + r = random_unlocked(); + UNLOCKME(); + return (r); +} diff --git a/userland/lib/libc/stdlib/system.c b/userland/lib/libc/stdlib/system.c new file mode 100644 index 0000000..bfb8a39 --- /dev/null +++ b/userland/lib/libc/stdlib/system.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +/* + * system(): ANSI C + * + * Run a command. + */ + +#define MAXCMDSIZE 2048 +#define MAXARGS 128 + +int +system(const char *cmd) +{ + /* + * Ordinarily, you call the shell to process the command. + * But we don't know that the shell can do that. So, do it + * ourselves. + */ + + char tmp[MAXCMDSIZE]; + char *argv[MAXARGS+1]; + int nargs=0; + char *s; + int pid, status; + + if (strlen(cmd) >= sizeof(tmp)) { + errno = E2BIG; + return -1; + } + strcpy(tmp, cmd); + + for (s = strtok(tmp, " \t"); s; s = strtok(NULL, " \t")) { + if (nargs < MAXARGS) { + argv[nargs++] = s; + } + else { + errno = E2BIG; + return 1; + } + } + + argv[nargs] = NULL; + + pid = fork(); + switch (pid) { + case -1: + return -1; + case 0: + /* child */ + execv(argv[0], argv); + /* exec only returns if it fails */ + _exit(255); + default: + /* parent */ + waitpid(pid, &status, 0); + return status; + } +} diff --git a/userland/lib/libc/string/memcmp.c b/userland/lib/libc/string/memcmp.c new file mode 100644 index 0000000..8c9b98e --- /dev/null +++ b/userland/lib/libc/string/memcmp.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * Standard C string function: compare two memory blocks and return + * their sort order. + */ + +int +memcmp(const void *av, const void *bv, size_t len) +{ + const unsigned char *a = av; + const unsigned char *b = bv; + size_t i; + + for (i=0; i +#include + +/* + * Standard C function to return a string for a given errno. + */ +const char * +strerror(int errcode) +{ + if (errcode>=0 && errcode < sys_nerr) { + return sys_errlist[errcode]; + } + return "Unknown error number"; +} diff --git a/userland/lib/libc/string/strtok.c b/userland/lib/libc/string/strtok.c new file mode 100644 index 0000000..0656000 --- /dev/null +++ b/userland/lib/libc/string/strtok.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +static char *__strtok_context; + +char * +strtok(char *str, const char *seps) +{ + return strtok_r(str, seps, &__strtok_context); +} diff --git a/userland/lib/libc/syscalls/gensyscalls.sh b/userland/lib/libc/syscalls/gensyscalls.sh new file mode 100755 index 0000000..bda25d0 --- /dev/null +++ b/userland/lib/libc/syscalls/gensyscalls.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# +# gensyscalls.sh +# Usage: ./gensyscalls.sh < syscalls.h +# +# Parses the kernel's syscalls.h into the body of syscalls.S +# + +# tabs to spaces, just in case +tr '\t' ' ' |\ +awk ' + # Do not read the parts of the file that are not between the markers. + /^\/\*CALLBEGIN\*\// { look=1; } + /^\/\*CALLEND\*\// { look=0; } + + # And, do not read lines that do not match the approximate right pattern. + look && /^#define SYS_/ && NF==3 { + sub("^SYS_", "", $2); + # print the name of the call and the number. + print $2, $3; + } +' | awk '{ + # output something simple that will work in syscalls.S. + printf "SYSCALL(%s, %s)\n", $1, $2; +}' diff --git a/userland/lib/libc/time/time.c b/userland/lib/libc/time/time.c new file mode 100644 index 0000000..e69a45a --- /dev/null +++ b/userland/lib/libc/time/time.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * POSIX C function: retrieve time in seconds since the epoch. + * Uses the OS/161 system call __time, which does the same thing + * but also returns nanoseconds. + */ + +time_t +time(time_t *t) +{ + return __time(t, NULL); +} diff --git a/userland/lib/libc/unix/__assert.c b/userland/lib/libc/unix/__assert.c new file mode 100644 index 0000000..0aa42d0 --- /dev/null +++ b/userland/lib/libc/unix/__assert.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +/* + * Function that gets called when an assert() fails. + * Print a message to stderr and bail out of the program. + */ + +void +__bad_assert(const char *file, int line, const char *expr) +{ + char buf[256]; + snprintf(buf, sizeof(buf), "Assertion failed: %s (%s line %d)\n", + expr, file, line); + + write(STDERR_FILENO, buf, strlen(buf)); + abort(); +} diff --git a/userland/lib/libc/unix/err.c b/userland/lib/libc/unix/err.c new file mode 100644 index 0000000..a4992d1 --- /dev/null +++ b/userland/lib/libc/unix/err.c @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * 4.4BSD error printing functions. + */ + +/* + * This is initialized by crt0, though it actually lives in errno.c + */ +extern char **__argv; + +/* + * Routine to print error message text to stderr. + */ +static +void +__senderr(void *junk, const char *data, size_t len) +{ + (void)junk; /* not needed or used */ + + write(STDERR_FILENO, data, len); +} + +/* + * Shortcut to call __senderr on a null-terminated string. + * (__senderr is set up to be called by __vprintf.) + */ +static +void +__senderrstr(const char *str) +{ + __senderr(NULL, str, strlen(str)); +} + +/* + * Common routine for all the *err* and *warn* functions. + */ +static +void +__printerr(int use_errno, const char *fmt, va_list ap) +{ + const char *errmsg; + const char *prog; + + /* + * Get the error message for the current errno. + * Do this early, before doing anything that might change the + * value in errno. + */ + errmsg = strerror(errno); + + /* + * Look up the program name. + * Strictly speaking we should pull off the rightmost + * path component of argv[0] and use that as the program + * name (this is how BSD err* prints) but it doesn't make + * much difference. + */ + if (__argv!=NULL && __argv[0]!=NULL) { + prog = __argv[0]; + } + else { + prog = "(program name unknown)"; + } + + /* print the program name */ + __senderrstr(prog); + __senderrstr(": "); + + /* process the printf format and args */ + __vprintf(__senderr, NULL, fmt, ap); + + /* if we're using errno, print the error string from above. */ + if (use_errno) { + __senderrstr(": "); + __senderrstr(errmsg); + } + + /* and always add a newline. */ + __senderrstr("\n"); +} + +/* + * The va_list versions of the warn/err functions. + */ + +/* warn/vwarn: use errno, don't exit */ +void +vwarn(const char *fmt, va_list ap) +{ + __printerr(1, fmt, ap); +} + +/* warnx/vwarnx: don't use errno, don't exit */ +void +vwarnx(const char *fmt, va_list ap) +{ + __printerr(0, fmt, ap); +} + +/* err/verr: use errno, then exit */ +void +verr(int exitcode, const char *fmt, va_list ap) +{ + __printerr(1, fmt, ap); + exit(exitcode); +} + +/* errx/verrx: don't use errno, but do then exit */ +void +verrx(int exitcode, const char *fmt, va_list ap) +{ + __printerr(0, fmt, ap); + exit(exitcode); +} + +/* + * The non-va_list versions of the warn/err functions. + * Just hand off to the va_list versions. + */ + +void +warn(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarn(fmt, ap); + va_end(ap); +} + +void +warnx(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarnx(fmt, ap); + va_end(ap); +} + +void +err(int exitcode, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verr(exitcode, fmt, ap); + va_end(ap); +} + +void +errx(int exitcode, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verrx(exitcode, fmt, ap); + va_end(ap); +} diff --git a/userland/lib/libc/unix/errno.c b/userland/lib/libc/unix/errno.c new file mode 100644 index 0000000..c8ae3e6 --- /dev/null +++ b/userland/lib/libc/unix/errno.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * Source file that declares the space for the global variable errno. + * + * We also declare the space for __argv, which is used by the err* + * functions, and __environ, which is used by getenv(). Since these + * are set by crt0, they are always referenced in every program; + * putting them here prevents gratuitously linking all the err* and + * warn* functions (and thus printf) into every program. + */ + +char **__argv; +char **__environ; + +int errno; diff --git a/userland/lib/libc/unix/execvp.c b/userland/lib/libc/unix/execvp.c new file mode 100644 index 0000000..6a68c60 --- /dev/null +++ b/userland/lib/libc/unix/execvp.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +/* + * POSIX C function: exec a program on the search path. Tries + * execv() repeatedly until one of the choices works. + */ +int +execvp(const char *prog, char *const *args) +{ + const char *searchpath, *s, *t; + char progpath[PATH_MAX]; + size_t len; + + if (strchr(prog, '/') != NULL) { + execv(prog, args); + return -1; + } + + searchpath = getenv("PATH"); + if (searchpath == NULL) { + errno = ENOENT; + return -1; + } + + for (s = searchpath; s != NULL; s = t) { + t = strchr(s, ':'); + if (t != NULL) { + len = t - s; + /* advance past the colon */ + t++; + } + else { + len = strlen(s); + } + if (len == 0) { + continue; + } + if (len >= sizeof(progpath)) { + continue; + } + memcpy(progpath, s, len); + snprintf(progpath + len, sizeof(progpath) - len, "/%s", prog); + execv(progpath, args); + switch (errno) { + case ENOENT: + case ENOTDIR: + case ENOEXEC: + /* routine errors, try next dir */ + break; + default: + /* oops, let's fail */ + return -1; + } + } + errno = ENOENT; + return -1; +} diff --git a/userland/lib/libc/unix/getcwd.c b/userland/lib/libc/unix/getcwd.c new file mode 100644 index 0000000..e8b6e08 --- /dev/null +++ b/userland/lib/libc/unix/getcwd.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include + +/* + * POSIX C function: retrieve current working directory. + * Uses the system call __getcwd(), which does essentially + * all the work. + */ + +char * +getcwd(char *buf, size_t buflen) +{ + int r; + + if (buflen < 1) { + errno = EINVAL; + return NULL; + } + + r = __getcwd(buf, buflen-1); + if (r < 0) { + return NULL; + } + + buf[r] = 0; + return buf; +} diff --git a/userland/lib/libtest/Makefile b/userland/lib/libtest/Makefile new file mode 100644 index 0000000..2752d19 --- /dev/null +++ b/userland/lib/libtest/Makefile @@ -0,0 +1,11 @@ +# +# libtest - library of common test support code +# + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +SRCS=triple.c +LIB=test + +.include "$(TOP)/mk/os161.lib.mk" diff --git a/userland/lib/libtest/triple.c b/userland/lib/libtest/triple.c new file mode 100644 index 0000000..f67a6d1 --- /dev/null +++ b/userland/lib/libtest/triple.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * triple.c + * + * Runs three copies of some subprogram. + */ + +#include +#include +#include +#include + +static +pid_t +spawnv(const char *prog, char **argv) +{ + pid_t pid = fork(); + switch (pid) { + case -1: + err(1, "fork"); + case 0: + /* child */ + execv(prog, argv); + err(1, "%s: execv", prog); + default: + /* parent */ + break; + } + return pid; +} + +static +int +dowait(int index, int pid) +{ + int status; + + if (waitpid(pid, &status, 0)<0) { + warn("waitpid for copy #%d (pid %d)", index, pid); + return 1; + } + else if (WIFSIGNALED(status)) { + warnx("copy #%d (pid %d): signal %d", index, pid, + WTERMSIG(status)); + return 1; + } + else if (WEXITSTATUS(status) != 0) { + warnx("copy #%d (pid %d): exit %d", index, pid, + WEXITSTATUS(status)); + return 1; + } + return 0; +} + +void +triple(const char *prog) +{ + pid_t pids[3]; + int i, failures = 0; + char *args[2]; + + /* set up the argv */ + args[0]=(char *)prog; + args[1]=NULL; + + warnx("Starting: running three copies of %s...", prog); + + for (i=0; i<3; i++) { + pids[i]=spawnv(args[0], args); + } + + for (i=0; i<3; i++) { + failures += dowait(i, pids[i]); + } + + if (failures > 0) { + warnx("%d failures", failures); + } + else { + warnx("Congratulations! You passed."); + } +} + diff --git a/userland/sbin/Makefile b/userland/sbin/Makefile new file mode 100644 index 0000000..6df5f6c --- /dev/null +++ b/userland/sbin/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for src/sbin (sources for programs installed in /sbin) +# + +TOP=../.. +.include "$(TOP)/mk/os161.config.mk" + +SUBDIRS=reboot halt poweroff mksfs dumpsfs sfsck + +.include "$(TOP)/mk/os161.subdir.mk" diff --git a/userland/sbin/dumpsfs/Makefile b/userland/sbin/dumpsfs/Makefile new file mode 100644 index 0000000..e28186e --- /dev/null +++ b/userland/sbin/dumpsfs/Makefile @@ -0,0 +1,15 @@ +# Makefile for dumpsfs + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=dumpsfs +SRCS=dumpsfs.c ../mksfs/disk.c ../mksfs/support.c +CFLAGS+=-I../mksfs +HOST_CFLAGS+=-I../mksfs +BINDIR=/sbin +HOSTBINDIR=/hostbin + + +.include "$(TOP)/mk/os161.prog.mk" +.include "$(TOP)/mk/os161.hostprog.mk" diff --git a/userland/sbin/dumpsfs/dumpsfs.c b/userland/sbin/dumpsfs/dumpsfs.c new file mode 100644 index 0000000..33cbc4e --- /dev/null +++ b/userland/sbin/dumpsfs/dumpsfs.c @@ -0,0 +1,607 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "support.h" +#include "kern/sfs.h" + + +#ifdef HOST +/* + * OS/161 runs natively on a big-endian platform, so we can + * conveniently use the byteswapping functions for network byte order. + */ +#include // for arpa/inet.h +#include // for ntohl +#include "hostcompat.h" +#define SWAP64(x) ntohll(x) +#define SWAP32(x) ntohl(x) +#define SWAP16(x) ntohs(x) + +extern const char *hostcompat_progname; + +#else + +#define SWAP64(x) (x) +#define SWAP32(x) (x) +#define SWAP16(x) (x) + +#endif + +#include "disk.h" + +#define ARRAYCOUNT(a) (sizeof(a) / sizeof((a)[0])) +#define DIVROUNDUP(a, b) (((a) + (b) - 1) / (b)) + +static bool dofiles, dodirs; +static bool doindirect; +static bool recurse; + +//////////////////////////////////////////////////////////// +// printouts + +static unsigned dumppos; + +static +void +dumpval(const char *desc, const char *val) +{ + size_t dlen, vlen, used; + + dlen = strlen(desc); + vlen = strlen(val); + + printf(" "); + + printf("%s: %s", desc, val); + + used = dlen + 2 + vlen; + for (; used < 36; used++) { + putchar(' '); + } + + if (dumppos % 2 == 1) { + printf("\n"); + } + dumppos++; +} + +static +void +dumpvalf(const char *desc, const char *valf, ...) +{ + va_list ap; + char buf[128]; + + va_start(ap, valf); + vsnprintf(buf, sizeof(buf), valf, ap); + va_end(ap); + dumpval(desc, buf); +} + +static +void +dumplval(const char *desc, const char *lval) +{ + if (dumppos % 2 == 1) { + printf("\n"); + dumppos++; + } + printf(" %s: %s\n", desc, lval); + dumppos += 2; +} + +//////////////////////////////////////////////////////////// +// fs structures + +static void dumpinode(uint32_t ino, const char *name); + +static +uint32_t +readsb(void) +{ + struct sfs_superblock sb; + + diskread(&sb, SFS_SUPER_BLOCK); + if (SWAP32(sb.sb_magic) != SFS_MAGIC) { + errx(1, "Not an sfs filesystem"); + } + return SWAP32(sb.sb_nblocks); +} + +static +void +dumpsb(void) +{ + struct sfs_superblock sb; + unsigned i; + + diskread(&sb, SFS_SUPER_BLOCK); + sb.sb_volname[sizeof(sb.sb_volname)-1] = 0; + + printf("Superblock\n"); + printf("----------\n"); + dumpvalf("Magic", "0x%8x", SWAP32(sb.sb_magic)); + dumpvalf("Size", "%u blocks", SWAP32(sb.sb_nblocks)); + dumpvalf("Freemap size", "%u blocks", + SFS_FREEMAPBLOCKS(SWAP32(sb.sb_nblocks))); + dumpvalf("Block size", "%u bytes", SFS_BLOCKSIZE); + dumplval("Volume name", sb.sb_volname); + + for (i=0; i= fsblocks) { + if (data[j] & mask) { + putchar('x'); + } + else { + putchar('!'); + } + } + else { + if (data[j] & mask) { + putchar('*'); + } + else { + putchar('.'); + } + } + } + if (j % 8 == 7) { + printf("\n"); + } + else { + printf(" "); + } + } + } + printf("\n"); +} + +static +void +dumpindirect(uint32_t block) +{ + uint32_t ib[SFS_BLOCKSIZE/sizeof(uint32_t)]; + char tmp[128]; + unsigned i; + + if (block == 0) { + return; + } + printf("Indirect block %u\n", block); + + diskread(ib, block); + for (i=0; isfi_size), SFS_BLOCKSIZE); + + fileblock = 0; + for (i=0; isfi_direct[i])); + } + if (fileblock < numblocks) { + fileblock = traverse_ib(fileblock, numblocks, + SWAP32(sfi->sfi_indirect), doblock); + } + assert(fileblock == numblocks); +} + +static +void +dumpdirblock(uint32_t fileblock, uint32_t diskblock) +{ + struct sfs_direntry sds[SFS_BLOCKSIZE/sizeof(struct sfs_direntry)]; + int nsds = SFS_BLOCKSIZE/sizeof(struct sfs_direntry); + int i; + + (void)fileblock; + if (diskblock == 0) { + printf(" [block %u - empty]\n", diskblock); + return; + } + diskread(&sds, diskblock); + + printf(" [block %u]\n", diskblock); + for (i=0; isfi_size) / sizeof(struct sfs_direntry); + if (SWAP32(sfi->sfi_size) % sizeof(struct sfs_direntry) != 0) { + warnx("Warning: dir size is not a multiple of dir entry size"); + } + printf("Directory contents for inode %u: %d entries\n", ino, nentries); + traverse(sfi, dumpdirblock); +} + +static +void +recursedirblock(uint32_t fileblock, uint32_t diskblock) +{ + struct sfs_direntry sds[SFS_BLOCKSIZE/sizeof(struct sfs_direntry)]; + int nsds = SFS_BLOCKSIZE/sizeof(struct sfs_direntry); + int i; + + (void)fileblock; + if (diskblock == 0) { + return; + } + diskread(&sds, diskblock); + + for (i=0; isfi_size) / sizeof(struct sfs_direntry); + printf("Reading files in directory %u: %d entries\n", ino, nentries); + traverse(sfi, recursedirblock); + printf("Done with directory %u\n", ino); +} + +static +void dumpfileblock(uint32_t fileblock, uint32_t diskblock) +{ + uint8_t data[SFS_BLOCKSIZE]; + unsigned i, j; + char tmp[128]; + + if (diskblock == 0) { + printf(" 0x%6x [sparse]\n", fileblock * SFS_BLOCKSIZE); + return; + } + + diskread(data, diskblock); + for (i=0; i 126) { + putchar('.'); + } + else { + putchar(data[j]); + } + } + printf("\n"); + } + } +} + +static +void +dumpfile(uint32_t ino, const struct sfs_dinode *sfi) +{ + printf("File contents for inode %u:\n", ino); + traverse(sfi, dumpfileblock); +} + +static +void +dumpinode(uint32_t ino, const char *name) +{ + struct sfs_dinode sfi; + const char *typename; + char tmp[128]; + unsigned i; + + diskread(&sfi, ino); + + printf("Inode %u", ino); + if (name != NULL) { + printf(" (%s)", name); + } + printf("\n"); + printf("--------------\n"); + + switch (SWAP16(sfi.sfi_type)) { + case SFS_TYPE_FILE: typename = "regular file"; break; + case SFS_TYPE_DIR: typename = "directory"; break; + default: typename = "invalid"; break; + } + dumpvalf("Type", "%u (%s)", SWAP16(sfi.sfi_type), typename); + dumpvalf("Size", "%u", SWAP32(sfi.sfi_size)); + dumpvalf("Link count", "%u", SWAP16(sfi.sfi_linkcount)); + printf("\n"); + + printf(" Direct blocks:\n"); + for (i=0; i 64K sectors (which + * would be 32M) but is < 1024K sectors (512M) so we + * need up to 5 hex digits for a block number. And + * assume it's actually < 1 million sectors so we need + * only up to 6 decimal digits. The complete block + * number print then needs up to 16 digits. + */ + snprintf(tmp, sizeof(tmp), "%u (0x%x)", + SWAP32(sfi.sfi_direct[i]), SWAP32(sfi.sfi_direct[i])); + printf(" %-16s", tmp); + if (i % 4 == 3) { + printf("\n"); + } + } + if (i % 4 != 0) { + printf("\n"); + } + printf(" Indirect block: %u (0x%x)\n", + SWAP32(sfi.sfi_indirect), SWAP32(sfi.sfi_indirect)); + for (i=0; i + +/* + * halt - shut down system, do not reboot, do not turn off power. + * Usage: halt + * + * Just calls reboot() with the RB_HALT flag. + */ + +int +main(void) +{ + reboot(RB_HALT); + return 0; +} diff --git a/userland/sbin/mksfs/Makefile b/userland/sbin/mksfs/Makefile new file mode 100644 index 0000000..85b4408 --- /dev/null +++ b/userland/sbin/mksfs/Makefile @@ -0,0 +1,13 @@ +# Makefile for mksfs + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=mksfs +SRCS=mksfs.c disk.c support.c +BINDIR=/sbin +HOSTBINDIR=/hostbin + + +.include "$(TOP)/mk/os161.prog.mk" +.include "$(TOP)/mk/os161.hostprog.mk" diff --git a/userland/sbin/mksfs/disk.c b/userland/sbin/mksfs/disk.c new file mode 100644 index 0000000..dbfe436 --- /dev/null +++ b/userland/sbin/mksfs/disk.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "support.h" +#include "disk.h" + +#define HOSTSTRING "System/161 Disk Image" +#define BLOCKSIZE 512 + +#ifndef EINTR +#define EINTR 0 +#endif + +static int fd=-1; +static uint32_t nblocks; + +/* + * Open a disk. If we're built for the host OS, check that it's a + * System/161 disk image, and then ignore the header block. + */ +void +opendisk(const char *path) +{ + struct stat statbuf; + + assert(fd<0); + fd = open(path, O_RDWR); + if (fd<0) { + err(1, "%s", path); + } + if (fstat(fd, &statbuf)) { + err(1, "%s: fstat", path); + } + + nblocks = statbuf.st_size / BLOCKSIZE; + +#ifdef HOST + nblocks--; + + { + char buf[64]; + int len; + + do { + len = read(fd, buf, sizeof(buf)-1); + if (len < 0 && (errno==EINTR || errno==EAGAIN)) { + continue; + } + } while (0); + + buf[len] = 0; + buf[strlen(HOSTSTRING)] = 0; + + if (strcmp(buf, HOSTSTRING)) { + errx(1, "%s: Not a System/161 disk image", path); + } + } +#endif +} + +/* + * Return the block size. (This is fixed, but still...) + */ +uint32_t +diskblocksize(void) +{ + assert(fd>=0); + return BLOCKSIZE; +} + +/* + * Return the device/image size in blocks. + */ +uint32_t +diskblocks(void) +{ + assert(fd>=0); + return nblocks; +} + +/* + * Write a block. + */ +void +diskwrite(const void *data, uint32_t block) +{ + const char *cdata = data; + uint32_t tot=0; + int len; + + assert(fd>=0); + +#ifdef HOST + // skip over disk file header + block++; +#endif + + if (lseek(fd, block*BLOCKSIZE, SEEK_SET)<0) { + err(1, "lseek"); + } + + while (tot < BLOCKSIZE) { + len = write(fd, cdata + tot, BLOCKSIZE - tot); + if (len < 0) { + if (errno==EINTR || errno==EAGAIN) { + continue; + } + err(1, "write"); + } + if (len==0) { + err(1, "write returned 0?"); + } + tot += len; + } +} + +/* + * Read a block. + */ +void +diskread(void *data, uint32_t block) +{ + char *cdata = data; + uint32_t tot=0; + int len; + + assert(fd>=0); + +#ifdef HOST + // skip over disk file header + block++; +#endif + + if (lseek(fd, block*BLOCKSIZE, SEEK_SET)<0) { + err(1, "lseek"); + } + + while (tot < BLOCKSIZE) { + len = read(fd, cdata + tot, BLOCKSIZE - tot); + if (len < 0) { + if (errno==EINTR || errno==EAGAIN) { + continue; + } + err(1, "read"); + } + if (len==0) { + err(1, "unexpected EOF in mid-sector"); + } + tot += len; + } +} + +/* + * Close the disk. + */ +void +closedisk(void) +{ + assert(fd>=0); + if (close(fd)) { + err(1, "close"); + } + fd = -1; +} diff --git a/userland/sbin/mksfs/disk.h b/userland/sbin/mksfs/disk.h new file mode 100644 index 0000000..0e9a014 --- /dev/null +++ b/userland/sbin/mksfs/disk.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +void opendisk(const char *path); + +uint32_t diskblocksize(void); +uint32_t diskblocks(void); + +void diskwrite(const void *data, uint32_t block); +void diskread(void *data, uint32_t block); + +void closedisk(void); diff --git a/userland/sbin/mksfs/mksfs.c b/userland/sbin/mksfs/mksfs.c new file mode 100644 index 0000000..5e32252 --- /dev/null +++ b/userland/sbin/mksfs/mksfs.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "support.h" +#include "kern/sfs.h" + + +#ifdef HOST + +#include // for arpa/inet.h +#include // for ntohl +#include "hostcompat.h" +#define SWAP64(x) ntohll(x) +#define SWAP32(x) ntohl(x) +#define SWAP16(x) ntohs(x) + +#else + +#define SWAP64(x) (x) +#define SWAP32(x) (x) +#define SWAP16(x) (x) + +#endif + +#include "disk.h" + +/* Maximum size of freemap we support */ +#define MAXFREEMAPBLOCKS 32 + +/* Free block bitmap */ +static char freemapbuf[MAXFREEMAPBLOCKS * SFS_BLOCKSIZE]; + +/* + * Assert that the on-disk data structures are correctly sized. + */ +static +void +check(void) +{ + assert(sizeof(struct sfs_superblock)==SFS_BLOCKSIZE); + assert(sizeof(struct sfs_dinode)==SFS_BLOCKSIZE); + assert(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0); +} + +/* + * Mark a block allocated. + */ +static +void +allocblock(uint32_t block) +{ + uint32_t mapbyte = block/CHAR_BIT; + unsigned char mask = (1<<(block % CHAR_BIT)); + + assert((freemapbuf[mapbyte] & mask) == 0); + freemapbuf[mapbyte] |= mask; +} + +/* + * Initialize the free block bitmap. + */ +static +void +initfreemap(uint32_t fsblocks) +{ + uint32_t freemapbits = SFS_FREEMAPBITS(fsblocks); + uint32_t freemapblocks = SFS_FREEMAPBLOCKS(fsblocks); + uint32_t i; + + if (freemapblocks > MAXFREEMAPBLOCKS) { + errx(1, "Filesystem too large -- " + "increase MAXFREEMAPBLOCKS and recompile"); + } + + /* mark the superblock and root inode in use */ + allocblock(SFS_SUPER_BLOCK); + allocblock(SFS_ROOTDIR_INO); + + /* the freemap blocks must be in use */ + for (i=0; i= SFS_VOLNAME_SIZE) { + errx(1, "Volume name %s too long", volname); + } + + /* Initialize the superblock structure */ + sb.sb_magic = SWAP32(SFS_MAGIC); + sb.sb_nblocks = SWAP32(nblocks); + strcpy(sb.sb_volname, volname); + + /* and write it out. */ + diskwrite(&sb, SFS_SUPER_BLOCK); +} + +/* + * Write out the free block bitmap. + */ +static +void +writefreemap(uint32_t fsblocks) +{ + uint32_t freemapblocks; + char *ptr; + uint32_t i; + + /* Write out each of the blocks in the free block bitmap. */ + freemapblocks = SFS_FREEMAPBLOCKS(fsblocks); + for (i=0; i + +/* + * poweroff - shut down system and turn off power. + * Usage: poweroff + * + * Just calls reboot() with the RB_POWEROFF flag. + */ + +int +main(void) +{ + reboot(RB_POWEROFF); + return 0; +} diff --git a/userland/sbin/reboot/Makefile b/userland/sbin/reboot/Makefile new file mode 100644 index 0000000..7573910 --- /dev/null +++ b/userland/sbin/reboot/Makefile @@ -0,0 +1,11 @@ +# Makefile for reboot + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=reboot +SRCS=reboot.c +BINDIR=/sbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/sbin/reboot/reboot.c b/userland/sbin/reboot/reboot.c new file mode 100644 index 0000000..61e9301 --- /dev/null +++ b/userland/sbin/reboot/reboot.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +/* + * reboot - shut down system and reboot it. + * Usage: reboot + * + * Just calls reboot() with the RB_REBOOT flag. + */ + +int +main(void) +{ + reboot(RB_REBOOT); + return 0; +} diff --git a/userland/sbin/sfsck/Makefile b/userland/sbin/sfsck/Makefile new file mode 100644 index 0000000..ceb4c1e --- /dev/null +++ b/userland/sbin/sfsck/Makefile @@ -0,0 +1,18 @@ +# Makefile for sfsck + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=sfsck +SRCS=\ + main.c pass1.c pass2.c \ + inode.c freemap.c sb.c \ + sfs.c utils.c \ + ../mksfs/disk.c ../mksfs/support.c +CFLAGS+=-I../mksfs +HOST_CFLAGS+=-I../mksfs +BINDIR=/sbin +HOSTBINDIR=/hostbin + +.include "$(TOP)/mk/os161.prog.mk" +.include "$(TOP)/mk/os161.hostprog.mk" diff --git a/userland/sbin/sfsck/compat.h b/userland/sbin/sfsck/compat.h new file mode 100644 index 0000000..e5ae6de --- /dev/null +++ b/userland/sbin/sfsck/compat.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef SFSCK_H +#define SFSCK_H + +/* + * Compat definitions. + */ + +/* get uint32_t and friends */ +#include + +/* get the additional compat stuff shared with mksfs */ +#include "support.h" + +#ifdef HOST +/* + * OS/161 runs natively on a big-endian platform, so we can + * conveniently use the byteswapping functions for network byte order. + */ +#include // for arpa/inet.h +#include // for ntohl +#include "hostcompat.h" +#define SWAP64(x) ntohll(x) +#define SWAP32(x) ntohl(x) +#define SWAP16(x) ntohs(x) + +#else + +#define SWAP64(x) (x) +#define SWAP32(x) (x) +#define SWAP16(x) (x) +#define NO_REALLOC + +#endif /* HOST */ + +#endif /* SFSCK_H */ diff --git a/userland/sbin/sfsck/freemap.c b/userland/sbin/sfsck/freemap.c new file mode 100644 index 0000000..842a60f --- /dev/null +++ b/userland/sbin/sfsck/freemap.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013, 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include /* for CHAR_BIT */ +#include /* also for CHAR_BIT */ +#include +#include +#include +#include + +#include "compat.h" +#include + +#include "utils.h" +#include "sfs.h" +#include "sb.h" +#include "freemap.h" +#include "main.h" + +static unsigned long blocksinuse = 0; +static uint8_t *freemapdata; +static uint8_t *tofreedata; + +/* + * Allocate space to keep track of the free block bitmap. This is + * called after the superblock is loaded so we can ask how big the + * volume is. + */ +void +freemap_setup(void) +{ + size_t i, mapbytes; + uint32_t fsblocks, mapblocks; + + fsblocks = sb_totalblocks(); + mapblocks = sb_freemapblocks(); + mapbytes = mapblocks * SFS_BLOCKSIZE; + + freemapdata = domalloc(mapbytes * sizeof(uint8_t)); + tofreedata = domalloc(mapbytes * sizeof(uint8_t)); + for (i=0; i INOMAX_D) got partially completed. + */ +void +freemap_blockfree(uint32_t block) +{ + unsigned index = block/8; + uint8_t mask = ((uint8_t)1)<<(block%8); + + if (tofreedata[index] & mask) { + /* already marked to free once, ignore */ + return; + } + if (freemapdata[index] & mask) { + /* block is used elsewhere, ignore */ + return; + } + tofreedata[index] |= mask; +} + +/* + * Count the number of bits set. + */ +static +int +countbits(uint8_t val) +{ + uint8_t x; + int ct=0; + + for (x=1; x; x<<=1) { + if (val & x) ct++; + } + return ct; +} + +/* + * Print a complaint about freemap bits being wrong. + * + * FREEMAPBLOCK is the block number within the freemap; BYTE is the + * byte offset within that block; VAL is the byte value; WHAT is a + * string indicating what happened. + */ +static +void +reportfreemap(uint32_t mapblock, uint32_t byte, uint8_t val, const char *what) +{ + uint8_t x, y; + uint32_t blocknum; + + for (x=1, y=0; x; x<<=1, y++) { + if (val & x) { + blocknum = mapblock*SFS_BITSPERBLOCK + + byte*CHAR_BIT + y; + warnx("Block %lu erroneously shown %s in freemap", + (unsigned long) blocknum, what); + } + } +} + +/* + * Scan the freemap. + * + * This is called after (at the end of) pass 1, when we've recursively + * found all the reachable blocks and marked them. + */ +void +freemap_check(void) +{ + uint8_t actual[SFS_BLOCKSIZE], *expected, *tofree, tmp; + uint32_t alloccount=0, freecount=0, i, j; + int bchanged; + uint32_t bitblocks; + + bitblocks = sb_freemapblocks(); + + for (i=0; i 0) { + warnx("%lu blocks erroneously shown free in freemap (fixed)", + (unsigned long) alloccount); + setbadness(EXIT_RECOV); + } + if (freecount > 0) { + warnx("%lu blocks erroneously shown used in freemap (fixed)", + (unsigned long) freecount); + setbadness(EXIT_RECOV); + } +} + +/* + * Return the total number of blocks in use, which we count during + * pass 1. + */ +unsigned long +freemap_blocksused(void) +{ + return blocksinuse; +} diff --git a/userland/sbin/sfsck/freemap.h b/userland/sbin/sfsck/freemap.h new file mode 100644 index 0000000..3fabc59 --- /dev/null +++ b/userland/sbin/sfsck/freemap.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef FREEMAP_H +#define FREEMAP_H + +/* + * The freemap module accumulates information about the free block + * bitmap as other checks are made, and then uses that information + * to check and correct it. + */ + +#include + +typedef enum { + B_SUPERBLOCK, /* Block that is the superblock */ + B_FREEMAPBLOCK, /* Block used by free-block bitmap */ + B_INODE, /* Block that is an inode */ + B_IBLOCK, /* Indirect (or doubly-indirect etc.) block */ + B_DIRDATA, /* Data block of a directory */ + B_DATA, /* Data block */ + B_PASTEND, /* Block off the end of the fs */ +} blockusage_t; + +/* Call this after loading the superblock but before doing any checks. */ +void freemap_setup(void); + +/* Call this to note that a block has been found in use. */ +void freemap_blockinuse(uint32_t block, blockusage_t how, uint32_t howdesc); + +/* Note that a block has been found where it should be dropped. */ +void freemap_blockfree(uint32_t block); + +/* Call this after all checks that call freemap_block{inuse,free}. */ +void freemap_check(void); + +/* Return the number of blocks in use. Valid after freemap_check(). */ +unsigned long freemap_blocksused(void); + + +#endif /* FREEMAP_H */ diff --git a/userland/sbin/sfsck/ibmacros.h b/userland/sbin/sfsck/ibmacros.h new file mode 100644 index 0000000..4f62d3f --- /dev/null +++ b/userland/sbin/sfsck/ibmacros.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef IBMACROS_H +#define IBMACROS_H + +/* + * Indirect block access macros + * + * These are macros for working with the direct and indirect block + * pointers in the inode. The scheme here supports a range of possible + * configurations, because sometimes adding large file support to SFS + * is part of an assignment; there is and should be no obligation to + * pick any particular layout, and we'd like sfsck to build and run + * seamlessly provided that the values declared in kern/sfs.h are + * correct. + * + * SFS_NDIRECT, SFS_NINDIRECT, SFS_NDINDIRECT, and SFS_NTINDIRECT + * should always be defined. If zero, no corresponding field is + * assumed to exist in the inode. If one, the field is assumed to + * be a single value and not an array. If greater than one, the + * field is assumed to be an array. + */ + +#ifndef SFS_NDIRECT +#error "SFS_NDIRECT not defined" +#endif +#ifndef SFS_NINDIRECT +#error "SFS_NINDIRECT not defined" +#endif +#ifndef SFS_NDINDIRECT +#error "SFS_NDINDIRECT not defined" +#endif +#ifndef SFS_NTINDIRECT +#error "SFS_NTINDIRECT not defined" +#endif + +/* + * For x in D, I, II, III (direct, indirect, 2x/3x indirect) we + * provide: + * + * NUM_x the number of blocks of this type + * GET_x retrieve the i'th block of this type + * SET_x lvalue for the i'th block of this type + * RANGE_x size of the block range mapped with one block of this type + * INOMAX_x maximum block number mapped by using this type in the inode + * + * It is important that the accessor macros (SET_x/GET_x) not refer to + * a nonexistent field of the inode in the case where there are zero + * blocks of that type, as that will lead to compile failure. Hence the + * lengthy definitions. So far I haven't thought any useful cpp hackery + * to make them more concise. + */ + +/* numbers */ + +#define NUM_D SFS_NDIRECT +#define NUM_I SFS_NINDIRECT +#define NUM_II SFS_NDINDIRECT +#define NUM_III SFS_NTINDIRECT + +/* blocks */ + +#if NUM_D == 0 +#define GET_D(sfi, i) GET0_x(sfi, sfi_direct, i) +#define SET_D(sfi, i) SET0_x(sfi, sfi_direct, i) +#elif NUM_D == 1 +#define GET_D(sfi, i) GET1_x(sfi, sfi_direct, i) +#define SET_D(sfi, i) SET1_x(sfi, sfi_direct, i) +#else +#define GET_D(sfi, i) GETN_x(sfi, sfi_direct, i) +#define SET_D(sfi, i) SETN_x(sfi, sfi_direct, i) +#endif + +#if NUM_I == 0 +#define GET_I(sfi, i) GET0_x(sfi, sfi_indirect, i) +#define SET_I(sfi, i) SET0_x(sfi, sfi_indirect, i) +#elif NUM_I == 1 +#define GET_I(sfi, i) GET1_x(sfi, sfi_indirect, i) +#define SET_I(sfi, i) SET1_x(sfi, sfi_indirect, i) +#else +#define GET_I(sfi, i) GETN_x(sfi, sfi_indirect, i) +#define SET_I(sfi, i) SETN_x(sfi, sfi_indirect, i) +#endif + +#if NUM_II == 0 +#define GET_II(sfi, i) GET0_x(sfi, sfi_dindirect, i) +#define SET_II(sfi, i) SET0_x(sfi, sfi_dindirect, i) +#elif NUM_II == 1 +#define GET_II(sfi, i) GET1_x(sfi, sfi_dindirect, i) +#define SET_II(sfi, i) SET1_x(sfi, sfi_dindirect, i) +#else +#define GET_II(sfi, i) GETN_x(sfi, sfi_dindirect, i) +#define SET_II(sfi, i) SETN_x(sfi, sfi_dindirect, i) +#endif + +#if NUM_III == 0 +#define GET_III(sfi, i) GET0_x(sfi, sfi_tindirect, i) +#define SET_III(sfi, i) SET0_x(sfi, sfi_tindirect, i) +#elif NUM_III == 1 +#define GET_III(sfi, i) GET1_x(sfi, sfi_tindirect, i) +#define SET_III(sfi, i) SET1_x(sfi, sfi_tindirect, i) +#else +#define GET_III(sfi, i) GETN_x(sfi, sfi_tindirect, i) +#define SET_III(sfi, i) SETN_x(sfi, sfi_tindirect, i) +#endif + +/* the generic forms of the block macros */ + +#define GET0_x(sfi, field, i) ((void)(i), (void)(sfi), 0) +#define GET1_x(sfi, field, i) ((void)(i), (sfi)->field) +#define GETN_x(sfi, field, i) ((sfi)->field[(i)]) + +#define SET0_x(sfi, field, i) (*((void)(i), (void)(sfi), (uint32_t *)NULL)) +#define SET1_x(sfi, field, i) (*((void)(i), &(sfi)->field)) +#define SETN_x(sfi, field, i) ((sfi)->field[(i)]) + +/* region sizes */ + +#define RANGE_D 1 +#define RANGE_I (RANGE_D * SFS_DBPERIDB) +#define RANGE_II (RANGE_I * SFS_DBPERIDB) +#define RANGE_III (RANGE_II * SFS_DBPERIDB) + +/* max blocks */ + +#define INOMAX_D NUM_D +#define INOMAX_I (INOMAX_D + SFS_DBPERIDB * NUM_I) +#define INOMAX_II (INOMAX_I + SFS_DBPERIDB * NUM_II) +#define INOMAX_III (INOMAX_II + SFS_DBPERIDB * NUM_III) + + +#endif /* IBMACROS_H */ diff --git a/userland/sbin/sfsck/inode.c b/userland/sbin/sfsck/inode.c new file mode 100644 index 0000000..2ca1a51 --- /dev/null +++ b/userland/sbin/sfsck/inode.c @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "compat.h" +#include + +#include "utils.h" +#include "sfs.h" +#include "freemap.h" +#include "inode.h" +#include "main.h" + +/* + * Stuff we remember about inodes. + * FUTURE: should count the number of blocks allocated to this inode + */ +struct inodeinfo { + uint32_t ino; + uint32_t linkcount; /* files only */ + int visited; /* dirs only */ + int type; +}; + +/* Table of inodes found. */ +static struct inodeinfo *inodes = NULL; +static unsigned ninodes = 0, maxinodes = 0; + +/* Whether the table is sorted and can be looked up with binary search. */ +static int inodes_sorted = 0; + +//////////////////////////////////////////////////////////// +// inode table ops + +/* + * Add an entry to the inode table, realloc'ing it if needed. + */ +static +void +inode_addtable(uint32_t ino, int type) +{ + unsigned newmax; + + assert(ninodes <= maxinodes); + if (ninodes == maxinodes) { + newmax = maxinodes ? maxinodes * 2 : 4; + inodes = dorealloc(inodes, maxinodes * sizeof(inodes[0]), + newmax * sizeof(inodes[0])); + maxinodes = newmax; + } + inodes[ninodes].ino = ino; + inodes[ninodes].linkcount = 0; + inodes[ninodes].visited = 0; + inodes[ninodes].type = type; + ninodes++; + inodes_sorted = 0; +} + +/* + * Compare function for inodes. + */ +static +int +inode_compare(const void *av, const void *bv) +{ + const struct inodeinfo *a = av; + const struct inodeinfo *b = bv; + + if (a->ino < b->ino) { + return -1; + } + if (a->ino > b->ino) { + return 1; + } + /* + * There should be no duplicates in the table! But C99 makes + * no guarantees about whether the implementation of qsort can + * ask us to compare an element to itself. Assert that this is + * what happened. + */ + assert(av == bv); + return 0; +} + +/* + * After pass1, we sort the inode table for faster access. + */ +void +inode_sorttable(void) +{ + qsort(inodes, ninodes, sizeof(inodes[0]), inode_compare); + inodes_sorted = 1; +} + +/* + * Find an inode by binary search. + * + * This will error out if asked for an inode not in the table; that's + * not supposed to happen. (This might need to change; if we improve + * the handling of crosslinked directories as suggested in comments in + * pass2.c, we'll need to be able to ask if an inode number is valid + * and names a directory.) + */ +static +struct inodeinfo * +inode_find(uint32_t ino) +{ + unsigned min, max, i; + + assert(inodes_sorted); + assert(ninodes > 0); + + min = 0; + max = ninodes; + while (1) { + assert(min <= max); + if (min == max) { + errx(EXIT_UNRECOV, "FATAL: inode %u wasn't found in my inode table", ino); + } + i = min + (max - min)/2; + if (inodes[i].ino < ino) { + min = i + 1; + } + else if (inodes[i].ino > ino) { + max = i; + } + else { + assert(inodes[i].ino == ino); + return &inodes[i]; + } + } + /* NOTREACHED */ +} + +//////////////////////////////////////////////////////////// +// inode ops + +/* + * Add an inode; returns 1 if we've already seen it. + * + * Uses linear search because we only sort the table for faster access + * after all inodes have been added. In the FUTURE this could be + * changed to a better data structure. + */ +int +inode_add(uint32_t ino, int type) +{ + unsigned i; + + for (i=0; itype == SFS_TYPE_DIR); + assert(inf->linkcount == 0); + if (inf->visited) { + return 1; + } + inf->visited = 1; + return 0; +} + +/* + * Count a link. Only for regular files because that's what the caller + * does. (And that, in turn, is because the link count of a directory + * is a local property.) + */ +void +inode_addlink(uint32_t ino) +{ + struct inodeinfo *inf; + + inf = inode_find(ino); + assert(inf->type == SFS_TYPE_FILE); + assert(inf->visited == 0); + inf->linkcount++; +} + +/* + * Correct link counts. This is effectively pass3. (FUTURE: change the + * name accordingly.) + */ +void +inode_adjust_filelinks(void) +{ + struct sfs_dinode sfi; + unsigned i; + + for (i=0; i 0); + + sfs_readinode(inodes[i].ino, &sfi); + assert(sfi.sfi_type == SFS_TYPE_FILE); + + if (sfi.sfi_linkcount != inodes[i].linkcount) { + warnx("File %lu link count %lu should be %lu (fixed)", + (unsigned long) inodes[i].ino, + (unsigned long) sfi.sfi_linkcount, + (unsigned long) inodes[i].linkcount); + sfi.sfi_linkcount = inodes[i].linkcount; + setbadness(EXIT_RECOV); + sfs_writeinode(inodes[i].ino, &sfi); + } + } +} + diff --git a/userland/sbin/sfsck/inode.h b/userland/sbin/sfsck/inode.h new file mode 100644 index 0000000..7a69311 --- /dev/null +++ b/userland/sbin/sfsck/inode.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef INODE_H +#define INODE_H + +/* + * The inode module accumulates non-local information about files and + * directories as other checks are made, and then updates inodes + * accordingly after the other checks are done. + */ + +/* Add an inode. Returns 1 if we've seen this inode before. */ +int inode_add(uint32_t ino, int type); + +/* Sort the inode table for faster lookup once all inode_add() done. */ +void inode_sorttable(void); + +/* + * Remember that we've seen a particular directory. Returns nonzero if + * we've seen this directory before, which means the directory is + * crosslinked. Requires inode_sorttable() first. + */ +int inode_visitdir(uint32_t ino); + +/* + * Count a link to a regular file. (Not called for directories.) + * Requires inode_sorttable() first. + */ +void inode_addlink(uint32_t ino); + +/* + * Correct the link counts of regular files, once all inode_addlink() + * done. + */ +void inode_adjust_filelinks(void); + + +#endif /* INODE_H */ diff --git a/userland/sbin/sfsck/main.c b/userland/sbin/sfsck/main.c new file mode 100644 index 0000000..1e50fcf --- /dev/null +++ b/userland/sbin/sfsck/main.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "compat.h" + +#include "disk.h" +#include "sfs.h" +#include "sb.h" +#include "freemap.h" +#include "inode.h" +#include "passes.h" +#include "main.h" + +static int badness=0; + +/* + * Update the badness state. (codes are in main.h) + * + * The badness state only gets worse, and is ultimately the process + * exit code. + */ +void +setbadness(int code) +{ + if (badness < code) { + badness = code; + } +} + +/* + * Main. + */ +int +main(int argc, char **argv) +{ +#ifdef HOST + hostcompat_init(argc, argv); +#endif + + /* FUTURE: add -n option */ + if (argc!=2) { + errx(EXIT_USAGE, "Usage: sfsck device/diskfile"); + } + + opendisk(argv[1]); + + sfs_setup(); + sb_load(); + sb_check(); + freemap_setup(); + + printf("Phase 1 -- check blocks and sizes\n"); + pass1(); + freemap_check(); + + printf("Phase 2 -- check directory tree\n"); + inode_sorttable(); + pass2(); + + printf("Phase 3 -- check reference counts\n"); + inode_adjust_filelinks(); + + closedisk(); + + warnx("%lu blocks used (of %lu); %lu directories; %lu files", + freemap_blocksused(), (unsigned long)sb_totalblocks(), + pass1_founddirs(), pass1_foundfiles()); + + switch (badness) { + case EXIT_USAGE: + case EXIT_FATAL: + default: + /* not supposed to happen here */ + assert(0); + break; + case EXIT_UNRECOV: + warnx("WARNING - unrecoverable errors. Maybe try again?"); + break; + case EXIT_RECOV: + warnx("Caution - filesystem modified. Run again for luck."); + break; + case EXIT_CLEAN: + break; + } + + return badness; +} diff --git a/userland/sbin/sfsck/main.h b/userland/sbin/sfsck/main.h new file mode 100644 index 0000000..1fde332 --- /dev/null +++ b/userland/sbin/sfsck/main.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef MAIN_H +#define MAIN_H + +/* + * Levels of problems that we can encounter. + * + * setbadness() records the maximum level seen so far; this is + * the ultimate exit code of sfsck. + */ + +#define EXIT_USAGE 4 +#define EXIT_FATAL 3 +#define EXIT_UNRECOV 2 +#define EXIT_RECOV 1 +#define EXIT_CLEAN 0 + +void setbadness(int code); + +#endif /* MAIN_H */ diff --git a/userland/sbin/sfsck/pass1.c b/userland/sbin/sfsck/pass1.c new file mode 100644 index 0000000..3d53662 --- /dev/null +++ b/userland/sbin/sfsck/pass1.c @@ -0,0 +1,496 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "compat.h" +#include + +#include "disk.h" +#include "utils.h" +#include "ibmacros.h" +#include "sfs.h" +#include "sb.h" +#include "freemap.h" +#include "inode.h" +#include "passes.h" +#include "main.h" + +static unsigned long count_dirs=0, count_files=0; + +/* + * State for checking indirect blocks. + */ +struct ibstate { + uint32_t ino; /* inode we're doing (constant) */ + uint32_t curfileblock; /* current block offset in the file */ + uint32_t fileblocks; /* file size in blocks (constant) */ + uint32_t volblocks; /* volume size in blocks (constant) */ + unsigned pasteofcount; /* number of blocks found past eof */ + blockusage_t usagetype; /* how to call freemap_blockinuse() */ +}; + +/* + * Traverse an indirect block, recording blocks that are in use, + * dropping any entries that are past EOF, and clearing any entries + * that point outside the volume. + * + * XXX: this should be extended to be able to recover from crosslinked + * blocks. Currently it just complains in freemap.c and sets + * EXIT_UNRECOV. + * + * The traversal is recursive; the state is maintained in IBS (as + * described above). IENTRY is a pointer to the entry in the parent + * indirect block (or the inode) that names the block we're currently + * scanning. IECHANGEDP should be set to 1 if *IENTRY is changed. + * INDIRECTION is the indirection level of this block (1, 2, or 3). + */ +static +void +check_indirect_block(struct ibstate *ibs, uint32_t *ientry, int *iechangedp, + int indirection) +{ + uint32_t entries[SFS_DBPERIDB]; + uint32_t i, ct; + uint32_t coveredblocks; + int localchanged = 0; + int j; + + if (*ientry > 0 && *ientry < ibs->volblocks) { + sfs_readindirect(*ientry, entries); + freemap_blockinuse(*ientry, B_IBLOCK, ibs->ino); + } + else { + if (*ientry >= ibs->volblocks) { + setbadness(EXIT_RECOV); + warnx("Inode %lu: indirect block pointer (level %d) " + "for block %lu outside of volume: %lu " + "(cleared)\n", + (unsigned long)ibs->ino, indirection, + (unsigned long)ibs->curfileblock, + (unsigned long)*ientry); + *ientry = 0; + *iechangedp = 1; + } + coveredblocks = 1; + for (j=0; jcurfileblock += coveredblocks; + return; + } + + if (indirection > 1) { + for (i=0; i= ibs->volblocks) { + setbadness(EXIT_RECOV); + warnx("Inode %lu: direct block pointer for " + "block %lu outside of volume: %lu " + "(cleared)\n", + (unsigned long)ibs->ino, + (unsigned long)ibs->curfileblock, + (unsigned long)entries[i]); + entries[i] = 0; + localchanged = 1; + } + else if (entries[i] != 0) { + if (ibs->curfileblock < ibs->fileblocks) { + freemap_blockinuse(entries[i], + ibs->usagetype, + ibs->ino); + } + else { + setbadness(EXIT_RECOV); + ibs->pasteofcount++; + freemap_blockfree(entries[i]); + entries[i] = 0; + localchanged = 1; + } + } + ibs->curfileblock++; + } + } + + ct=0; + for (i=ct=0; ipasteofcount++;*/ + *iechangedp = 1; + freemap_blockfree(*ientry); + *ientry = 0; + } + } + else { + assert(*ientry != 0); + if (localchanged) { + sfs_writeindirect(*ientry, entries); + } + } +} + +/* + * Check the blocks belonging to inode INO, whose inode has already + * been loaded into SFI. ISDIR is a shortcut telling us if the inode + * is a directory. + * + * Returns nonzero if SFI has been modified and needs to be written + * back. + */ +static +int +check_inode_blocks(uint32_t ino, struct sfs_dinode *sfi, int isdir) +{ + struct ibstate ibs; + uint32_t size, datablock; + int changed; + int i; + + size = SFS_ROUNDUP(sfi->sfi_size, SFS_BLOCKSIZE); + + ibs.ino = ino; + /*ibs.curfileblock = 0;*/ + ibs.fileblocks = size/SFS_BLOCKSIZE; + ibs.volblocks = sb_totalblocks(); + ibs.pasteofcount = 0; + ibs.usagetype = isdir ? B_DIRDATA : B_DATA; + + changed = 0; + + for (ibs.curfileblock=0; ibs.curfileblock= ibs.volblocks) { + setbadness(EXIT_RECOV); + warnx("Inode %lu: direct block pointer for " + "block %lu outside of volume: %lu " + "(cleared)\n", + (unsigned long)ibs.ino, + (unsigned long)ibs.curfileblock, + (unsigned long)datablock); + SET_D(sfi, ibs.curfileblock) = 0; + changed = 1; + } + else if (datablock > 0) { + if (ibs.curfileblock < ibs.fileblocks) { + freemap_blockinuse(datablock, ibs.usagetype, + ibs.ino); + } + else { + setbadness(EXIT_RECOV); + ibs.pasteofcount++; + changed = 1; + freemap_blockfree(datablock); + SET_D(sfi, ibs.curfileblock) = 0; + } + } + } + + for (i=0; i 0) { + warnx("Inode %lu: %u blocks after EOF (freed)", + (unsigned long) ibs.ino, ibs.pasteofcount); + setbadness(EXIT_RECOV); + } + + return changed; +} + +/* + * Do the pass1 inode-level checks on inode INO, which has already + * been loaded into SFI. Note that sfi_type has already been + * validated. + * + * Returns nonzero if SFI has been modified and needs to be written + * back. + */ +static +int +pass1_inode(uint32_t ino, struct sfs_dinode *sfi, int alreadychanged) +{ + int changed = alreadychanged; + int isdir = sfi->sfi_type == SFS_TYPE_DIR; + + if (inode_add(ino, sfi->sfi_type)) { + /* Already been here. */ + assert(changed == 0); + return 1; + } + + freemap_blockinuse(ino, B_INODE, ino); + + if (checkzeroed(sfi->sfi_waste, sizeof(sfi->sfi_waste))) { + warnx("Inode %lu: sfi_waste section not zeroed (fixed)", + (unsigned long) ino); + setbadness(EXIT_RECOV); + changed = 1; + } + + if (check_inode_blocks(ino, sfi, isdir)) { + changed = 1; + } + + if (changed) { + sfs_writeinode(ino, sfi); + } + return 0; +} + +/* + * Check the directory entry in SFD. INDEX is its offset, and PATH is + * its name; these are used for printing messages. + */ +static +int +pass1_direntry(const char *path, uint32_t index, struct sfs_direntry *sfd) +{ + int dchanged = 0; + uint32_t nblocks; + + nblocks = sb_totalblocks(); + + if (sfd->sfd_ino == SFS_NOINO) { + if (sfd->sfd_name[0] != 0) { + setbadness(EXIT_RECOV); + warnx("Directory %s entry %lu has name but no file", + path, (unsigned long) index); + sfd->sfd_name[0] = 0; + dchanged = 1; + } + } + else if (sfd->sfd_ino >= nblocks) { + setbadness(EXIT_RECOV); + warnx("Directory %s entry %lu has out of range " + "inode (cleared)", + path, (unsigned long) index); + sfd->sfd_ino = SFS_NOINO; + sfd->sfd_name[0] = 0; + dchanged = 1; + } + else { + if (sfd->sfd_name[0] == 0) { + /* XXX: what happens if FSCK.n.m already exists? */ + snprintf(sfd->sfd_name, sizeof(sfd->sfd_name), + "FSCK.%lu.%lu", + (unsigned long) sfd->sfd_ino, + (unsigned long) uniqueid()); + setbadness(EXIT_RECOV); + warnx("Directory %s entry %lu has file but " + "no name (fixed: %s)", + path, (unsigned long) index, + sfd->sfd_name); + dchanged = 1; + } + if (checknullstring(sfd->sfd_name, sizeof(sfd->sfd_name))) { + setbadness(EXIT_RECOV); + warnx("Directory %s entry %lu not " + "null-terminated (fixed)", + path, (unsigned long) index); + dchanged = 1; + } + if (checkbadstring(sfd->sfd_name)) { + setbadness(EXIT_RECOV); + warnx("Directory %s entry %lu contains invalid " + "characters (fixed)", + path, (unsigned long) index); + dchanged = 1; + } + } + return dchanged; +} + +/* + * Check a directory. INO is the inode number; PATHSOFAR is the path + * to this directory. This traverses the volume directory tree + * recursively. + */ +static +void +pass1_dir(uint32_t ino, const char *pathsofar) +{ + struct sfs_dinode sfi; + struct sfs_direntry *direntries; + uint32_t ndirentries, i; + int ichanged=0, dchanged=0; + + sfs_readinode(ino, &sfi); + + if (sfi.sfi_size % sizeof(struct sfs_direntry) != 0) { + setbadness(EXIT_RECOV); + warnx("Directory %s has illegal size %lu (fixed)", + pathsofar, (unsigned long) sfi.sfi_size); + sfi.sfi_size = SFS_ROUNDUP(sfi.sfi_size, + sizeof(struct sfs_direntry)); + ichanged = 1; + } + count_dirs++; + + if (pass1_inode(ino, &sfi, ichanged)) { + /* been here before; crosslinked dir, sort it out in pass 2 */ + return; + } + + ndirentries = sfi.sfi_size/sizeof(struct sfs_direntry); + direntries = domalloc(sfi.sfi_size); + + sfs_readdir(&sfi, direntries, ndirentries); + + for (i=0; i +#include +#include +#include +#include +#include + +#include "compat.h" +#include + +#include "disk.h" +#include "utils.h" +#include "ibmacros.h" +#include "sfs.h" +#include "sb.h" +#include "freemap.h" +#include "inode.h" +#include "passes.h" +#include "main.h" + +/* + * Process a directory. INO is the inode number; PARENTINO is the + * parent's inode number; PATHSOFAR is the path to this directory. + * + * Recursively checks its subdirs. + * + * In the FUTURE we might want to improve the handling of crosslinked + * directories so it picks the parent that the .. entry points to, + * instead of the first entry we recursively find. Beware of course + * that the .. entry might not point to anywhere valid at all... + */ +static +int +pass2_dir(uint32_t ino, uint32_t parentino, const char *pathsofar) +{ + struct sfs_dinode sfi; + struct sfs_direntry *direntries; + int *sortvector; + uint32_t dirsize, ndirentries, maxdirentries, subdircount, i; + int ichanged=0, dchanged=0, dotseen=0, dotdotseen=0; + + if (inode_visitdir(ino)) { + /* crosslinked dir; tell parent to remove the entry */ + return 1; + } + + /* Load the inode. */ + sfs_readinode(ino, &sfi); + + /* + * Load the directory. If there is any leftover room in the + * last block, allocate space for it in case we want to insert + * entries. + */ + + ndirentries = sfi.sfi_size/sizeof(struct sfs_direntry); + maxdirentries = SFS_ROUNDUP(ndirentries, + SFS_BLOCKSIZE/sizeof(struct sfs_direntry)); + dirsize = maxdirentries * sizeof(struct sfs_direntry); + direntries = domalloc(dirsize); + + sortvector = domalloc(ndirentries * sizeof(int)); + + sfs_readdir(&sfi, direntries, ndirentries); + for (i=ndirentries; isfd_ino == SFS_NOINO || d2->sfd_ino == SFS_NOINO) { + /* sfsdir_sort puts these last */ + continue; + } + + if (!strcmp(d1->sfd_name, d2->sfd_name)) { + if (d1->sfd_ino == d2->sfd_ino) { + setbadness(EXIT_RECOV); + warnx("Directory %s: Duplicate entries for " + "%s (merged)", + pathsofar, d1->sfd_name); + d1->sfd_ino = SFS_NOINO; + d1->sfd_name[0] = 0; + } + else { + /* XXX: what if FSCK.n.m already exists? */ + snprintf(d1->sfd_name, sizeof(d1->sfd_name), + "FSCK.%lu.%lu", + (unsigned long) d1->sfd_ino, + (unsigned long) uniqueid()); + setbadness(EXIT_RECOV); + warnx("Directory %s: Duplicate names %s " + "(one renamed: %s)", + pathsofar, d2->sfd_name, d1->sfd_name); + } + dchanged = 1; + } + } + + /* + * Look for the . and .. entries. + */ + + for (i=0; i only one . here */ + assert(dotseen==0); + dotseen = 1; + } + else if (!strcmp(direntries[i].sfd_name, "..")) { + if (direntries[i].sfd_ino != parentino) { + setbadness(EXIT_RECOV); + warnx("Directory %s: Incorrect `..' entry " + "(fixed)", pathsofar); + direntries[i].sfd_ino = parentino; + dchanged = 1; + } + /* duplicates are checked above -> only one .. here */ + assert(dotdotseen==0); + dotdotseen = 1; + } + } + + /* + * If no . entry, try to insert one. + */ + + if (!dotseen) { + if (sfsdir_tryadd(direntries, ndirentries, ".", ino)==0) { + setbadness(EXIT_RECOV); + warnx("Directory %s: No `.' entry (added)", + pathsofar); + dchanged = 1; + } + else if (sfsdir_tryadd(direntries, maxdirentries, ".", + ino)==0) { + setbadness(EXIT_RECOV); + warnx("Directory %s: No `.' entry (added)", + pathsofar); + ndirentries++; + dchanged = 1; + sfi.sfi_size += sizeof(struct sfs_direntry); + ichanged = 1; + } + else { + setbadness(EXIT_UNRECOV); + warnx("Directory %s: No `.' entry (NOT FIXED)", + pathsofar); + } + } + + /* + * If no .. entry, try to insert one. + */ + + if (!dotdotseen) { + if (sfsdir_tryadd(direntries, ndirentries, "..", + parentino)==0) { + setbadness(EXIT_RECOV); + warnx("Directory %s: No `..' entry (added)", + pathsofar); + dchanged = 1; + } + else if (sfsdir_tryadd(direntries, maxdirentries, "..", + parentino)==0) { + setbadness(EXIT_RECOV); + warnx("Directory %s: No `..' entry (added)", + pathsofar); + ndirentries++; + dchanged = 1; + sfi.sfi_size += sizeof(struct sfs_direntry); + ichanged = 1; + } + else { + setbadness(EXIT_UNRECOV); + warnx("Directory %s: No `..' entry (NOT FIXED)", + pathsofar); + } + } + + /* + * Now load each inode in the directory. + * + * For regular files, count the number of links we see; for + * directories, recurse. Count the number of subdirs seen + * so we can correct our own link count if necessary. + */ + + subdircount=0; + for (i=0; i /* for CHAR_BIT */ +#include /* also for CHAR_BIT */ +#include +#include +#include + +#include "compat.h" +#include + +#include "utils.h" +#include "sfs.h" +#include "sb.h" +#include "freemap.h" +#include "main.h" + +static struct sfs_superblock sb; + +/* + * Load the superblock. + */ +void +sb_load(void) +{ + sfs_readsb(SFS_SUPER_BLOCK, &sb); + if (sb.sb_magic != SFS_MAGIC) { + errx(EXIT_FATAL, "Not an sfs filesystem"); + } + + assert(sb.sb_nblocks > 0); + assert(SFS_FREEMAPBLOCKS(sb.sb_nblocks) > 0); +} + +/* + * Validate the superblock. + */ +void +sb_check(void) +{ + int schanged=0; + + /* + * FUTURE: should we check sb.sb_nblocks against diskblocks()? + */ + + /* Check the superblock fields */ + + if (checknullstring(sb.sb_volname, sizeof(sb.sb_volname))) { + warnx("Volume name not null-terminated (fixed)"); + setbadness(EXIT_RECOV); + schanged = 1; + } + if (checkbadstring(sb.sb_volname)) { + warnx("Volume name contains illegal characters (fixed)"); + setbadness(EXIT_RECOV); + schanged = 1; + } + if (checkzeroed(sb.reserved, sizeof(sb.reserved))) { + warnx("Reserved section of superblock not zeroed (fixed)"); + setbadness(EXIT_RECOV); + schanged = 1; + } + + /* Write the superblock back if necessary */ + if (schanged) { + sfs_writesb(SFS_SUPER_BLOCK, &sb); + } +} + +/* + * Return the total number of blocks in the volume. + */ +uint32_t +sb_totalblocks(void) +{ + return sb.sb_nblocks; +} + +/* + * Return the number of freemap blocks. + * (this function probably ought to go away) + */ +uint32_t +sb_freemapblocks(void) +{ + return SFS_FREEMAPBLOCKS(sb.sb_nblocks); +} + +/* + * Return the volume name. + */ +const char * +sb_volname(void) +{ + return sb.sb_volname; +} diff --git a/userland/sbin/sfsck/sb.h b/userland/sbin/sfsck/sb.h new file mode 100644 index 0000000..39e335b --- /dev/null +++ b/userland/sbin/sfsck/sb.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef SB_H +#define SB_H + +/* + * The superblock module checks the superblock and provides + * information from the superblock to other modules. + */ + +#include + +/* Load the superblock. Should be done before virtually anything else. */ +void sb_load(void); + +/* After the superblock is loaded: return volume size. */ +uint32_t sb_totalblocks(void); + +/* After the superblock is loaded: return number of freemap blocks. */ +uint32_t sb_freemapblocks(void); + +/* After the superblock is loaded: return volume name. */ +const char *sb_volname(void); + +/* Check the superblock. Must load it first. */ +void sb_check(void); + +#endif /* SB_H */ diff --git a/userland/sbin/sfsck/sfs.c b/userland/sbin/sfsck/sfs.c new file mode 100644 index 0000000..a2469ff --- /dev/null +++ b/userland/sbin/sfsck/sfs.c @@ -0,0 +1,464 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "compat.h" +#include + +#include "disk.h" +#include "utils.h" +#include "ibmacros.h" +#include "sfs.h" +#include "main.h" + +//////////////////////////////////////////////////////////// +// global setup + +void +sfs_setup(void) +{ + assert(sizeof(struct sfs_superblock)==SFS_BLOCKSIZE); + assert(sizeof(struct sfs_dinode)==SFS_BLOCKSIZE); + assert(SFS_BLOCKSIZE % sizeof(struct sfs_direntry) == 0); +} + +//////////////////////////////////////////////////////////// +// byte-swap functions + +static +void +swapsb(struct sfs_superblock *sb) +{ + sb->sb_magic = SWAP32(sb->sb_magic); + sb->sb_nblocks = SWAP32(sb->sb_nblocks); +} + +static +void +swapbits(uint8_t *bits) +{ + /* nothing to do */ + (void)bits; +} + +static +void +swapinode(struct sfs_dinode *sfi) +{ + int i; + + sfi->sfi_size = SWAP32(sfi->sfi_size); + sfi->sfi_type = SWAP16(sfi->sfi_type); + sfi->sfi_linkcount = SWAP16(sfi->sfi_linkcount); + + for (i=0; isfd_ino = SWAP32(sfd->sfd_ino); +} + +static +void +swapindir(uint32_t *entries) +{ + int i; + for (i=0; i 1) { + uint32_t index = offset / entrysize; + offset %= entrysize; + return ibmap(entries[index], offset, entrysize/SFS_DBPERIDB); + } + else { + assert(offset < SFS_DBPERIDB); + return entries[offset]; + } +} + +/* + * bmap() for SFS. + * + * Given an inode and a file block, returns a disk block. + */ +static +uint32_t +bmap(const struct sfs_dinode *sfi, uint32_t fileblock) +{ + uint32_t iblock, offset; + + if (fileblock < INOMAX_D) { + return GET_D(sfi, fileblock); + } + else if (fileblock < INOMAX_I) { + iblock = (fileblock - INOMAX_D) / RANGE_I; + offset = (fileblock - INOMAX_D) % RANGE_I; + return ibmap(GET_I(sfi, iblock), offset, RANGE_D); + } + else if (fileblock < INOMAX_II) { + iblock = (fileblock - INOMAX_I) / RANGE_II; + offset = (fileblock - INOMAX_I) % RANGE_II; + return ibmap(GET_II(sfi, iblock), offset, RANGE_I); + } + else if (fileblock < INOMAX_III) { + iblock = (fileblock - INOMAX_II) / RANGE_III; + offset = (fileblock - INOMAX_II) % RANGE_III; + return ibmap(GET_III(sfi, iblock), offset, RANGE_II); + } + return 0; +} + +//////////////////////////////////////////////////////////// +// superblock, free block bitmap, and inode I/O + +/* + * superblock - blocknum is a disk block number. + */ + +void +sfs_readsb(uint32_t blocknum, struct sfs_superblock *sb) +{ + diskread(sb, blocknum); + swapsb(sb); +} + +void +sfs_writesb(uint32_t blocknum, struct sfs_superblock *sb) +{ + swapsb(sb); + diskwrite(sb, blocknum); + swapsb(sb); +} + +/* + * freemap blocks - whichblock is a block number within the free block + * bitmap. + */ + +void +sfs_readfreemapblock(uint32_t whichblock, uint8_t *bits) +{ + diskread(bits, SFS_FREEMAP_START + whichblock); + swapbits(bits); +} + +void +sfs_writefreemapblock(uint32_t whichblock, uint8_t *bits) +{ + swapbits(bits); + diskwrite(bits, SFS_FREEMAP_START + whichblock); + swapbits(bits); +} + +/* + * inodes - ino is an inode number, which is a disk block number. + */ + +void +sfs_readinode(uint32_t ino, struct sfs_dinode *sfi) +{ + diskread(sfi, ino); + swapinode(sfi); +} + +void +sfs_writeinode(uint32_t ino, struct sfs_dinode *sfi) +{ + swapinode(sfi); + diskwrite(sfi, ino); + swapinode(sfi); +} + +/* + * indirect blocks - blocknum is a disk block number. + */ + +void +sfs_readindirect(uint32_t blocknum, uint32_t *entries) +{ + diskread(entries, blocknum); + swapindir(entries); +} + +void +sfs_writeindirect(uint32_t blocknum, uint32_t *entries) +{ + swapindir(entries); + diskwrite(entries, blocknum); + swapindir(entries); +} + +//////////////////////////////////////////////////////////// +// directory I/O + +/* + * Read the directory block at DISKBLOCK into D. + */ +static +void +sfs_readdirblock(struct sfs_direntry *d, uint32_t diskblock) +{ + const unsigned atonce = SFS_BLOCKSIZE/sizeof(struct sfs_direntry); + unsigned j; + + if (diskblock != 0) { + diskread(d, diskblock); + for (j=0; jsfd_ino == SFS_NOINO && bd->sfd_ino == SFS_NOINO) { + return 0; + } + if (ad->sfd_ino == SFS_NOINO) { + return 1; + } + if (bd->sfd_ino == SFS_NOINO) { + return -1; + } + + return strcmp(ad->sfd_name, bd->sfd_name); +} + +/* + * Sort the directory contents in D (with ND entries) by producing a + * permutation vector into VECTOR, which should be allocated to hold + * ND ints. + */ +void +sfsdir_sort(struct sfs_direntry *d, unsigned nd, int *vector) +{ + unsigned i; + + for (i=0; i + +struct sfs_superblock; +struct sfs_dinode; +struct sfs_direntry; + +/* Call this before anything else in this module */ +void sfs_setup(void); + +/* + * Read and write ops for SFS structures + */ + +/* superblock */ +void sfs_readsb(uint32_t blocknum, struct sfs_superblock *sb); +void sfs_writesb(uint32_t blocknum, struct sfs_superblock *sb); + +/* freemap blocks; whichblock is the freemap block number (starts at 0) */ +void sfs_readfreemapblock(uint32_t whichblock, uint8_t *bits); +void sfs_writefreemapblock(uint32_t whichblock, uint8_t *bits); + +/* inode */ +void sfs_readinode(uint32_t inum, struct sfs_dinode *sfi); +void sfs_writeinode(uint32_t inum, struct sfs_dinode *sfi); + +/* indirect block (any indirection level) */ +void sfs_readindirect(uint32_t blocknum, uint32_t *entries); +void sfs_writeindirect(uint32_t blocknum, uint32_t *entries); + +/* directory - ND should be the number of directory entries D points to */ +void sfs_readdir(struct sfs_dinode *sfi, struct sfs_direntry *d, unsigned nd); +void sfs_writedir(const struct sfs_dinode *sfi, + struct sfs_direntry *d, unsigned nd); + +/* Try to add an entry to a directory. */ +int sfsdir_tryadd(struct sfs_direntry *d, int nd, + const char *name, uint32_t ino); + +/* Sort a directory by creating a permutation vector. */ +void sfsdir_sort(struct sfs_direntry *d, unsigned nd, int *vector); + + +#endif /* SFS_H */ diff --git a/userland/sbin/sfsck/utils.c b/userland/sbin/sfsck/utils.c new file mode 100644 index 0000000..05d2adc --- /dev/null +++ b/userland/sbin/sfsck/utils.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, 2013 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "compat.h" +#include "utils.h" +#include "main.h" + +/* + * Wrapper around malloc. + */ +void * +domalloc(size_t len) +{ + void *x; + x = malloc(len); + if (x==NULL) { + errx(EXIT_FATAL, "Out of memory"); + } + return x; +} + +/* + * Wrapper around realloc. OSZ is the old block size, which we need if + * we're going to emulate realloc with malloc. + */ +void * +dorealloc(void *op, size_t osz, size_t nsz) +{ + void *np; +#ifdef NO_REALLOC + size_t copysz; + + np = domalloc(nsz); + if (op != NULL) { + copysz = osz < nsz ? osz : nsz; + memcpy(np, op, copysz); + free(op); + } +#else + (void)osz; + np = realloc(op, nsz); + if (np == NULL) { + errx(EXIT_FATAL, "Out of memory"); + } +#endif + return np; +} + +/* + * Get a unique id number. (unique as in for this run of sfsck...) + */ +uint32_t +uniqueid(void) +{ + static uint32_t uniquecounter; + + return uniquecounter++; +} + +/* + * Check if BUF, a string field of length MAXLEN, contains a null + * terminator. If not, slam one in and return 1. + */ +int +checknullstring(char *buf, size_t maxlen) +{ + size_t i; + for (i=0; i /* for size_t */ +#include /* for uint32_t */ + +/* non-failing wrapper around malloc */ +void *domalloc(size_t len); +void *dorealloc(void *op, size_t osz, size_t nsz); + +/* return a fresh id number */ +uint32_t uniqueid(void); + +/* ensure that BUF (of size MAXLEN) is terminated; return 1 if changed */ +int checknullstring(char *buf, size_t maxlen); + +/* check for illegal filename characters; if found, zap them and return 1 */ +int checkbadstring(char *buf); + +/* check for nonzero bytes in a zeroed area; if found, zap and return 1 */ +int checkzeroed(void *buf, size_t len); + +#endif /* UTILS_H */ diff --git a/userland/testbin/Makefile b/userland/testbin/Makefile new file mode 100644 index 0000000..647f229 --- /dev/null +++ b/userland/testbin/Makefile @@ -0,0 +1,19 @@ +# +# Makefile for src/testbin (sources for programs installed in /testbin) +# + +TOP=../.. +.include "$(TOP)/mk/os161.config.mk" + +SUBDIRS=add argtest badcall bigexec bigfile bigfork bigseek bloat conman \ + crash ctest dirconc dirseek dirtest f_test factorial farm faulter \ + filetest forkbomb forktest frack hash hog huge \ + malloctest matmult multiexec palin parallelvm poisondisk psort \ + randcall redirect rmdirtest rmtest \ + sbrktest schedpong sort sparsefile tail tictac triplehuge \ + triplemat triplesort usemtest zero + +# But not: +# userthreads (no support in kernel API in base system) + +.include "$(TOP)/mk/os161.subdir.mk" diff --git a/userland/testbin/add/Makefile b/userland/testbin/add/Makefile new file mode 100644 index 0000000..d2bb59f --- /dev/null +++ b/userland/testbin/add/Makefile @@ -0,0 +1,11 @@ +# Makefile for add + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=add +SRCS=add.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/add/add.c b/userland/testbin/add/add.c new file mode 100644 index 0000000..856e4ec --- /dev/null +++ b/userland/testbin/add/add.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Simple program to add two numbers (given in as arguments). Used to + * test argument passing to child processes. + * + * Intended for the basic system calls assignment; this should work + * once execv() argument handling is implemented. + */ + +#include +#include +#include + +int +main(int argc, char *argv[]) +{ + int i, j; + + if (argc != 3) { + errx(1, "Usage: add num1 num2"); + } + + i = atoi(argv[1]); + j = atoi(argv[2]); + + printf("Answer: %d\n", i+j); + + return 0; +} diff --git a/userland/testbin/argtest/Makefile b/userland/testbin/argtest/Makefile new file mode 100644 index 0000000..8db8b84 --- /dev/null +++ b/userland/testbin/argtest/Makefile @@ -0,0 +1,11 @@ +# Makefile for argtest + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=argtest +SRCS=argtest.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/argtest/argtest.c b/userland/testbin/argtest/argtest.c new file mode 100644 index 0000000..7ed552e --- /dev/null +++ b/userland/testbin/argtest/argtest.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Program to test argument passing: it displays the argc and all + * of argv, and then exits. + * + * Intended for the basic system calls assignment. This may help + * debugging the argument handling of execv(). + */ + +#include + +int +main(int argc, char *argv[]) +{ + const char *tmp; + int i; + + printf("argc: %d\n", argc); + + for (i=0; i<=argc; i++) { + tmp = argv[i]; + if (tmp==NULL) { + tmp = "[NULL]"; + } + printf("argv[%d]: %s\n", i, tmp); + } + + return 0; +} diff --git a/userland/testbin/badcall/Makefile b/userland/testbin/badcall/Makefile new file mode 100644 index 0000000..d0ef650 --- /dev/null +++ b/userland/testbin/badcall/Makefile @@ -0,0 +1,43 @@ +# Makefile for badcall + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +SRCS=\ + bad_execv.c \ + bad_waitpid.c \ + bad_open.c \ + bad_read.c \ + bad_write.c \ + bad_close.c \ + bad_reboot.c \ + bad_sbrk.c \ + bad_ioctl.c \ + bad_lseek.c \ + bad_fsync.c \ + bad_ftruncate.c \ + bad_stat.c \ + bad_remove.c \ + bad_rename.c \ + bad_link.c \ + bad_mkdir.c \ + bad_rmdir.c \ + bad_chdir.c \ + bad_getdirentry.c \ + bad_symlink.c \ + bad_readlink.c \ + bad_dup2.c \ + bad_pipe.c \ + bad_time.c \ + bad_getcwd.c \ + common_buf.c \ + common_fds.c \ + common_path.c \ + report.c \ + driver.c + +PROG=badcall +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/badcall/bad_chdir.c b/userland/testbin/badcall/bad_chdir.c new file mode 100644 index 0000000..cf98845 --- /dev/null +++ b/userland/testbin/badcall/bad_chdir.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Invalid calls to chdir() + */ + +#include +#include +#include + +#include "test.h" + +static +void +chdir_empty(void) +{ + int rv; + + /* + * This is actually valid by some interpretations. + */ + + report_begin("chdir to empty string"); + rv = chdir(""); + report_check2(rv, errno, EINVAL, 0); +} + +void +test_chdir(void) +{ + test_chdir_path(); + chdir_empty(); +} + diff --git a/userland/testbin/badcall/bad_close.c b/userland/testbin/badcall/bad_close.c new file mode 100644 index 0000000..6d70e66 --- /dev/null +++ b/userland/testbin/badcall/bad_close.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Invalid calls to close() + */ + +#include "test.h" + +void +test_close(void) +{ + test_close_fd(); +} diff --git a/userland/testbin/badcall/bad_dup2.c b/userland/testbin/badcall/bad_dup2.c new file mode 100644 index 0000000..db3a216 --- /dev/null +++ b/userland/testbin/badcall/bad_dup2.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Invalid calls to dup2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +static +void +dup2_fd2(int fd, const char *desc) +{ + int rv; + + report_begin("%s", desc); + rv = dup2(STDIN_FILENO, fd); + report_check(rv, errno, EBADF); + + if (rv != -1) { + close(fd); /* just in case */ + } +} + +static +void +dup2_self(void) +{ + struct stat sb; + int rv; + int testfd; + + /* use fd that isn't in use */ + testfd = CLOSED_FD; + + report_begin("copying stdin to test with"); + + rv = dup2(STDIN_FILENO, testfd); + if (rv == -1) { + report_result(rv, errno); + report_aborted(); + return; + } + + report_begin("dup2 to same fd"); + rv = dup2(testfd, testfd); + if (rv == testfd) { + report_passed(); + } + else if (rv<0) { + report_result(rv, errno); + report_failure(); + } + else { + report_warnx("returned %d instead", rv); + report_failure(); + } + + report_begin("fstat fd after dup2 to itself"); + rv = fstat(testfd, &sb); + if (errno == ENOSYS) { + report_saw_enosys(); + } + report_result(rv, errno); + if (rv==0) { + report_passed(); + } + else if (errno != ENOSYS) { + report_failure(); + } + else { + report_skipped(); + /* no support for fstat; try lseek */ + report_begin("lseek fd after dup2 to itself"); + rv = lseek(testfd, 0, SEEK_CUR); + report_result(rv, errno); + if (rv==0 || (rv==-1 && errno==ESPIPE)) { + report_passed(); + } + else { + report_failure(); + } + } + + close(testfd); +} + +void +test_dup2(void) +{ + /* This does the first fd. */ + test_dup2_fd(); + + /* Any interesting cases added here should also go in common_fds.c */ + dup2_fd2(-1, "dup2 to -1"); + dup2_fd2(-5, "dup2 to -5"); + dup2_fd2(IMPOSSIBLE_FD, "dup2 to impossible fd"); +#ifdef OPEN_MAX + dup2_fd2(OPEN_MAX, "dup2 to OPEN_MAX"); +#else + warnx("Warning: OPEN_MAX not defined - test skipped"); +#endif + + dup2_self(); +} diff --git a/userland/testbin/badcall/bad_execv.c b/userland/testbin/badcall/bad_execv.c new file mode 100644 index 0000000..24ad1cb --- /dev/null +++ b/userland/testbin/badcall/bad_execv.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * bad calls to execv() + */ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +static +int +exec_common_fork(void) +{ + int pid, rv, status, err; + + /* + * This does not happen in a test context (from the point of + * view of report.c) so we have to fiddle a bit. + */ + + pid = fork(); + if (pid<0) { + err = errno; + report_begin("forking for test"); + report_result(pid, err); + report_aborted(); + return -1; + } + + if (pid==0) { + /* child */ + return 0; + } + + rv = waitpid(pid, &status, 0); + if (rv == -1) { + err = errno; + report_begin("waiting for test subprocess"); + report_result(rv, err); + report_failure(); + return -1; + } + if (WIFEXITED(status) && WEXITSTATUS(status) == MAGIC_STATUS) { + return 1; + } + /* Oops... */ + report_begin("exit code of subprocess; should be %d", MAGIC_STATUS); + if (WIFSIGNALED(status)) { + report_warnx("signal %d", WTERMSIG(status)); + } + else { + report_warnx("exit %d", WEXITSTATUS(status)); + } + report_failure(); + return -1; +} + +static +void +exec_badprog(const void *prog, const char *desc) +{ + int rv; + char *args[2]; + args[0] = (char *)"foo"; + args[1] = NULL; + + if (exec_common_fork() != 0) { + return; + } + + report_begin(desc); + rv = execv(prog, args); + report_check(rv, errno, EFAULT); + exit(MAGIC_STATUS); +} + +static +void +exec_emptyprog(void) +{ + int rv; + char *args[2]; + args[0] = (char *)"foo"; + args[1] = NULL; + + if (exec_common_fork() != 0) { + return; + } + + report_begin("exec the empty string"); + rv = execv("", args); + report_check2(rv, errno, EINVAL, EISDIR); + exit(MAGIC_STATUS); +} + +static +void +exec_badargs(void *args, const char *desc) +{ + int rv; + + if (exec_common_fork() != 0) { + return; + } + + report_begin(desc); + rv = execv("/bin/true", args); + report_check(rv, errno, EFAULT); + exit(MAGIC_STATUS); +} + +static +void +exec_onearg(void *ptr, const char *desc) +{ + int rv; + + char *args[3]; + args[0] = (char *)"foo"; + args[1] = (char *)ptr; + args[2] = NULL; + + if (exec_common_fork() != 0) { + return; + } + + report_begin(desc); + rv = execv("/bin/true", args); + report_check(rv, errno, EFAULT); + exit(MAGIC_STATUS); +} + +void +test_execv(void) +{ + exec_badprog(NULL, "exec with NULL program"); + exec_badprog(INVAL_PTR, "exec with invalid pointer program"); + exec_badprog(KERN_PTR, "exec with kernel pointer program"); + + exec_emptyprog(); + + exec_badargs(NULL, "exec with NULL arglist"); + exec_badargs(INVAL_PTR, "exec with invalid pointer arglist"); + exec_badargs(KERN_PTR, "exec with kernel pointer arglist"); + + exec_onearg(INVAL_PTR, "exec with invalid pointer arg"); + exec_onearg(KERN_PTR, "exec with kernel pointer arg"); +} diff --git a/userland/testbin/badcall/bad_fsync.c b/userland/testbin/badcall/bad_fsync.c new file mode 100644 index 0000000..fd67384 --- /dev/null +++ b/userland/testbin/badcall/bad_fsync.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * fsync + */ + +#include "test.h" + +void +test_fsync(void) +{ + test_fsync_fd(); +} + diff --git a/userland/testbin/badcall/bad_ftruncate.c b/userland/testbin/badcall/bad_ftruncate.c new file mode 100644 index 0000000..f88d7c8 --- /dev/null +++ b/userland/testbin/badcall/bad_ftruncate.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * ftruncate + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +static +void +ftruncate_fd_device(void) +{ + int rv, fd; + + report_begin("ftruncate on device"); + + fd = open("null:", O_RDWR); + if (fd<0) { + report_warn("opening null: failed"); + report_aborted(); + return; + } + + rv = ftruncate(fd, 6); + report_check(rv, errno, EINVAL); + + close(fd); +} + +static +void +ftruncate_size_neg(void) +{ + int rv, fd; + + report_begin("ftruncate to negative size"); + + fd = open_testfile(NULL); + if (fd<0) { + report_aborted(); + return; + } + + rv = ftruncate(fd, -60); + report_check(rv, errno, EINVAL); + + close(fd); + remove(TESTFILE); +} + +void +test_ftruncate(void) +{ + test_ftruncate_fd(); + + ftruncate_fd_device(); + ftruncate_size_neg(); +} diff --git a/userland/testbin/badcall/bad_getcwd.c b/userland/testbin/badcall/bad_getcwd.c new file mode 100644 index 0000000..4f94ba1 --- /dev/null +++ b/userland/testbin/badcall/bad_getcwd.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * __getcwd + */ + +#include "test.h" + +void +test_getcwd(void) +{ + test_getcwd_buf(); +} diff --git a/userland/testbin/badcall/bad_getdirentry.c b/userland/testbin/badcall/bad_getdirentry.c new file mode 100644 index 0000000..02806d2 --- /dev/null +++ b/userland/testbin/badcall/bad_getdirentry.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * getdirentry + */ + +#include "test.h" + +void +test_getdirentry(void) +{ + test_getdirentry_fd(); + test_getdirentry_buf(); +} diff --git a/userland/testbin/badcall/bad_ioctl.c b/userland/testbin/badcall/bad_ioctl.c new file mode 100644 index 0000000..8ce38bc --- /dev/null +++ b/userland/testbin/badcall/bad_ioctl.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * ioctl + */ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +static +void +one_ioctl_badbuf(int fd, int code, const char *codename, + void *ptr, const char *ptrdesc) +{ + int rv; + + report_begin("ioctl %s with %s", codename, ptrdesc); + rv = ioctl(fd, code, ptr); + report_check(rv, errno, EFAULT); +} + +static +void +any_ioctl_badbuf(int fd, int code, const char *codename) +{ + one_ioctl_badbuf(fd, code, codename, NULL, "NULL pointer"); + one_ioctl_badbuf(fd, code, codename, INVAL_PTR, "invalid pointer"); + one_ioctl_badbuf(fd, code, codename, KERN_PTR, "kernel pointer"); +} + +#define IOCTL(fd, sym) any_ioctl_badbuf(fd, sym, #sym) + +static +void +ioctl_badbuf(void) +{ + /* + * Since we don't actually define any ioctls, this code won't + * actually run. But if you do define ioctls, turn these tests + * on for those that actually use the data buffer argument for + * anything. + */ + + /* IOCTL(STDIN_FILENO, TIOCGETA); */ + + + /* suppress gcc warning */ + (void)any_ioctl_badbuf; +} + +static +void +ioctl_badcode(void) +{ + int rv; + + report_begin("invalid ioctl"); + rv = ioctl(STDIN_FILENO, NONEXIST_IOCTL, NULL); + report_check(rv, errno, EIOCTL); +} + +void +test_ioctl(void) +{ + test_ioctl_fd(); + + /* Since we don't actually define any ioctls, this is not meaningful */ + ioctl_badcode(); + ioctl_badbuf(); +} diff --git a/userland/testbin/badcall/bad_link.c b/userland/testbin/badcall/bad_link.c new file mode 100644 index 0000000..63ecc15 --- /dev/null +++ b/userland/testbin/badcall/bad_link.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * link + */ + +#include +#include + +#include "test.h" + +static +void +link_dir(void) +{ + int rv; + + report_begin("hard link of ."); + rv = link(".", TESTDIR); + report_check(rv, errno, EINVAL); + if (rv==0) { + /* this might help recover... maybe */ + remove(TESTDIR); + } +} + +static +void +link_empty1(void) +{ + int rv; + + report_begin("hard link of empty string"); + rv = link("", TESTDIR); + report_check(rv, errno, EINVAL); +} + +static +void +link_empty2(void) +{ + int rv; + + report_begin("hard link to empty string"); + if (create_testdir()<0) { + /*report_aborted();*/ /* XXX in create_testdir */ + return; + } + rv = link(TESTDIR, ""); + report_check(rv, errno, EINVAL); + rmdir(TESTDIR); +} + +void +test_link(void) +{ + test_link_paths(); + link_dir(); + link_empty1(); + link_empty2(); +} diff --git a/userland/testbin/badcall/bad_lseek.c b/userland/testbin/badcall/bad_lseek.c new file mode 100644 index 0000000..a521754 --- /dev/null +++ b/userland/testbin/badcall/bad_lseek.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * lseek + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +static +void +lseek_fd_device(void) +{ + int fd, rv; + + report_begin("lseek on device"); + + fd = open("null:", O_RDONLY); + if (fd<0) { + report_warn("opening null: failed"); + report_aborted(); + return; + } + + rv = lseek(fd, 309, SEEK_SET); + report_check(rv, errno, ESPIPE); + + close(fd); +} + +static +void +lseek_file_stdin(void) +{ + int fd, fd2, rv, status; + const char slogan[] = "There ain't no such thing as a free lunch"; + size_t len = strlen(slogan); + pid_t pid; + + report_begin("lseek stdin when open on file"); + + /* fork so we don't affect our own stdin */ + pid = fork(); + if (pid<0) { + report_warn("fork failed"); + report_aborted(); + return; + } + else if (pid!=0) { + /* parent */ + rv = waitpid(pid, &status, 0); + if (rv<0) { + report_warn("waitpid failed"); + report_aborted(); + } + if (WIFSIGNALED(status)) { + report_warnx("subprocess exited with signal %d", + WTERMSIG(status)); + report_aborted(); + } + else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { + report_warnx("subprocess exited with code %d", + WEXITSTATUS(status)); + report_aborted(); + } + return; + } + + /* child */ + + fd = open_testfile(NULL); + if (fd<0) { + _exit(0); + } + + /* + * Move file to stdin. + * Use stdin (rather than stdout or stderr) to maximize the + * chances of detecting any special-case handling of fds 0-2. + * (Writing to stdin is fine as long as it's open for write, + * and it will be.) + */ + fd2 = dup2(fd, STDIN_FILENO); + if (fd2<0) { + report_warn("dup2 to stdin failed"); + close(fd); + remove(TESTFILE); + _exit(1); + } + if (fd2 != STDIN_FILENO) { + report_warn("dup2 returned wrong file handle"); + close(fd); + remove(TESTFILE); + _exit(1); + } + close(fd); + + rv = write(STDIN_FILENO, slogan, len); + if (rv<0) { + report_warn("write to %s (via stdin) failed", TESTFILE); + remove(TESTFILE); + _exit(1); + } + + if ((unsigned)rv != len) { + report_warnx("write to %s (via stdin) got short count", + TESTFILE); + remove(TESTFILE); + _exit(1); + } + + /* blah */ + report_skipped(); + + rv = lseek(STDIN_FILENO, 0, SEEK_SET); + report_begin("try 1: SEEK_SET"); + report_check(rv, errno, 0); + + rv = lseek(STDIN_FILENO, 0, SEEK_END); + report_begin("try 2: SEEK_END"); + report_check(rv, errno, 0); + + remove(TESTFILE); + _exit(0); +} + +static +void +lseek_loc_negative(void) +{ + int fd, rv; + + report_begin("lseek to negative offset"); + + fd = open_testfile(NULL); + if (fd<0) { + report_aborted(); + return; + } + + rv = lseek(fd, -309, SEEK_SET); + report_check(rv, errno, EINVAL); + + close(fd); + remove(TESTFILE); +} + +static +void +lseek_whence_inval(void) +{ + int fd, rv; + + report_begin("lseek with invalid whence code"); + + fd = open_testfile(NULL); + if (fd<0) { + report_aborted(); + return; + } + + rv = lseek(fd, 0, 3594); + report_check(rv, errno, EINVAL); + + close(fd); + remove(TESTFILE); +} + +static +void +lseek_loc_pasteof(void) +{ + const char *message = "blahblah"; + int fd; + off_t pos; + + report_begin("seek past/to EOF"); + + fd = open_testfile(message); + if (fd<0) { + report_aborted(); + return; + } + + pos = lseek(fd, 5340, SEEK_SET); + if (pos == -1) { + report_warn("lseek past EOF failed"); + report_failure(); + goto out; + } + if (pos != 5340) { + report_warnx("lseek to 5340 got offset %lld", (long long) pos); + report_failure(); + goto out; + } + + pos = lseek(fd, -50, SEEK_CUR); + if (pos == -1) { + report_warn("small seek beyond EOF failed"); + report_failure(); + goto out; + } + if (pos != 5290) { + report_warnx("SEEK_CUR to 5290 got offset %lld", + (long long) pos); + report_failure(); + goto out; + } + + pos = lseek(fd, 0, SEEK_END); + if (pos == -1) { + report_warn("seek to EOF failed"); + report_failure(); + goto out; + } + + if (pos != (off_t) strlen(message)) { + report_warnx("seek to EOF got %lld (should be %zu)", + (long long) pos, strlen(message)); + report_failure(); + goto out; + } + + report_passed(); + + out: + close(fd); + remove(TESTFILE); + return; +} + +void +test_lseek(void) +{ + test_lseek_fd(); + + lseek_fd_device(); + lseek_file_stdin(); + lseek_loc_negative(); + lseek_loc_pasteof(); + lseek_whence_inval(); +} diff --git a/userland/testbin/badcall/bad_mkdir.c b/userland/testbin/badcall/bad_mkdir.c new file mode 100644 index 0000000..4500dbd --- /dev/null +++ b/userland/testbin/badcall/bad_mkdir.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * mkdir + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +static +void +mkdir_dot(void) +{ + int rv; + + report_begin("mkdir ."); + rv = mkdir(".", 0775); + report_check(rv, errno, EEXIST); +} + +static +void +mkdir_dotdot(void) +{ + int rv; + + report_begin("mkdir .."); + rv = mkdir("..", 0775); + report_check(rv, errno, EEXIST); +} + +static +void +mkdir_empty(void) +{ + int rv; + + report_begin("mkdir of empty string"); + rv = mkdir("", 0775); + report_check(rv, errno, EINVAL); +} + +void +test_mkdir(void) +{ + test_mkdir_path(); + + mkdir_dot(); + mkdir_dotdot(); + mkdir_empty(); +} diff --git a/userland/testbin/badcall/bad_open.c b/userland/testbin/badcall/bad_open.c new file mode 100644 index 0000000..3d317ed --- /dev/null +++ b/userland/testbin/badcall/bad_open.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * invalid calls to open() + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +static +void +open_badflags(void) +{ + int fd; + + report_begin("open null: with bad flags"); + fd = open("null:", 309842); + report_check(fd, errno, EINVAL); +} + +static +void +open_empty(void) +{ + int rv; + + report_begin("open empty string"); + rv = open("", O_RDONLY); + report_check(rv, errno, EINVAL); + if (rv>=0) { + close(rv); + } +} + +void +test_open(void) +{ + test_open_path(); + + open_badflags(); + open_empty(); +} diff --git a/userland/testbin/badcall/bad_pipe.c b/userland/testbin/badcall/bad_pipe.c new file mode 100644 index 0000000..172579c --- /dev/null +++ b/userland/testbin/badcall/bad_pipe.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * pipe + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +static +void +pipe_badptr(void *ptr, const char *desc) +{ + int rv; + + report_begin("%s", desc); + rv = pipe(ptr); + report_check(rv, errno, EFAULT); +} + +static +void +pipe_unaligned(void) +{ + int fds[3], rv; + char *ptr; + + report_begin("pipe with unaligned pointer"); + + ptr = (char *)&fds[0]; + ptr++; + + rv = pipe((int *)ptr); + report_survival(rv, errno); + if (rv == 0) { + memmove(fds, ptr, 2*sizeof(int)); + close(fds[0]); + close(fds[1]); + } +} + +void +test_pipe(void) +{ + pipe_badptr(NULL, "pipe with NULL pointer"); + pipe_badptr(INVAL_PTR, "pipe with invalid pointer"); + pipe_badptr(KERN_PTR, "pipe with kernel pointer"); + + pipe_unaligned(); +} diff --git a/userland/testbin/badcall/bad_read.c b/userland/testbin/badcall/bad_read.c new file mode 100644 index 0000000..c4e3215 --- /dev/null +++ b/userland/testbin/badcall/bad_read.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Invalid calls to read() + */ + +#include "test.h" + +void +test_read(void) +{ + test_read_fd(); + test_read_buf(); +} + diff --git a/userland/testbin/badcall/bad_readlink.c b/userland/testbin/badcall/bad_readlink.c new file mode 100644 index 0000000..4399851 --- /dev/null +++ b/userland/testbin/badcall/bad_readlink.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * readlink + */ + +#include +#include + +#include "test.h" + +static +void +readlink_file(void) +{ + char buf[128]; + int fd, rv; + + report_begin("readlink on file"); + fd = open_testfile("the question contains an invalid assumption"); + if (fd<0) { + report_aborted(); + return; + } + close(fd); + rv = readlink(TESTFILE, buf, sizeof(buf)); + report_check(rv, errno, EINVAL); + remove(TESTFILE); +} + +static +void +readlink_dir(void) +{ + char buf[128]; + int rv; + + report_begin("readlink on ."); + rv = readlink(".", buf, sizeof(buf)); + report_check(rv, errno, EISDIR); +} + +static +void +readlink_empty(void) +{ + char buf[128]; + int rv; + + report_begin("readlink on empty string"); + rv = readlink("", buf, sizeof(buf)); + report_check2(rv, errno, EISDIR, EINVAL); +} + +void +test_readlink(void) +{ + test_readlink_path(); + test_readlink_buf(); + + readlink_file(); + readlink_dir(); + readlink_empty(); +} + diff --git a/userland/testbin/badcall/bad_reboot.c b/userland/testbin/badcall/bad_reboot.c new file mode 100644 index 0000000..add8fb9 --- /dev/null +++ b/userland/testbin/badcall/bad_reboot.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Invalid calls to reboot() + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +static +void +reboot_badflags(void) +{ + int rv; + + printf("(This should not kill the system...)\n"); + report_begin("reboot with invalid flags"); + rv = reboot(15353); + report_check(rv, errno, EINVAL); +} + +void +test_reboot(void) +{ + reboot_badflags(); +} diff --git a/userland/testbin/badcall/bad_remove.c b/userland/testbin/badcall/bad_remove.c new file mode 100644 index 0000000..02621ac --- /dev/null +++ b/userland/testbin/badcall/bad_remove.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * remove + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +static +void +remove_dir(void) +{ + int rv; + + report_begin("remove() on a directory"); + + if (create_testdir() < 0) { + /*report_aborted();*/ /* XXX in create_testdir */ + return; + } + + rv = remove(TESTDIR); + report_check(rv, errno, EISDIR); + rmdir(TESTDIR); +} + +static +void +remove_dot(void) +{ + int rv; + + report_begin("remove() on ."); + rv = remove("."); + report_check2(rv, errno, EISDIR, EINVAL); +} + +static +void +remove_dotdot(void) +{ + int rv; + + report_begin("remove() on .."); + rv = remove(".."); + report_check2(rv, errno, EISDIR, EINVAL); +} + +static +void +remove_empty(void) +{ + int rv; + + report_begin("remove() on empty string"); + rv = remove(""); + report_check2(rv, errno, EISDIR, EINVAL); +} + +void +test_remove(void) +{ + test_remove_path(); + + remove_dir(); + remove_dot(); + remove_dotdot(); + remove_empty(); +} diff --git a/userland/testbin/badcall/bad_rename.c b/userland/testbin/badcall/bad_rename.c new file mode 100644 index 0000000..814dcb6 --- /dev/null +++ b/userland/testbin/badcall/bad_rename.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * rename + */ + +#include +#include + +#include "test.h" + +static +void +rename_dot(void) +{ + int rv; + + report_begin("rename ."); + + rv = rename(".", TESTDIR); + report_check(rv, errno, EINVAL); + if (rv==0) { + /* oops... put it back */ + rename(TESTDIR, "."); + } +} + +static +void +rename_dotdot(void) +{ + int rv; + + report_begin("rename .."); + rv = rename("..", TESTDIR); + report_check(rv, errno, EINVAL); + if (rv==0) { + /* oops... put it back */ + rename(TESTDIR, ".."); + } +} + +static +void +rename_empty1(void) +{ + int rv; + + report_begin("rename empty string"); + rv = rename("", TESTDIR); + report_check2(rv, errno, EISDIR, EINVAL); + if (rv==0) { + /* don't try to remove it */ + rename(TESTDIR, TESTDIR "-foo"); + } +} + +static +void +rename_empty2(void) +{ + int rv; + + report_begin("rename to empty string"); + if (create_testdir()<0) { + /*report_aborted();*/ /* XXX in create_testdir */ + return; + } + rv = rename(TESTDIR, ""); + report_check2(rv, errno, EISDIR, EINVAL); + rmdir(TESTDIR); +} + +void +test_rename(void) +{ + test_rename_paths(); + + rename_dot(); + rename_dotdot(); + rename_empty1(); + rename_empty2(); +} + diff --git a/userland/testbin/badcall/bad_rmdir.c b/userland/testbin/badcall/bad_rmdir.c new file mode 100644 index 0000000..b1f6883 --- /dev/null +++ b/userland/testbin/badcall/bad_rmdir.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * rmdir + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +static +void +rmdir_file(void) +{ + int rv; + + report_begin("rmdir a file"); + if (create_testfile()<0) { + report_aborted(); + return; + } + rv = rmdir(TESTFILE); + report_check(rv, errno, ENOTDIR); + remove(TESTFILE); +} + +static +void +rmdir_dot(void) +{ + int rv; + + report_begin("rmdir ."); + rv = rmdir("."); + report_check(rv, errno, EINVAL); +} + +static +void +rmdir_dotdot(void) +{ + int rv; + + report_begin("rmdir .."); + rv = rmdir(".."); + report_check2(rv, errno, EINVAL, ENOTEMPTY); +} + +static +void +rmdir_empty(void) +{ + int rv; + + report_begin("rmdir empty string"); + rv = rmdir(""); + report_check(rv, errno, EINVAL); +} + +void +test_rmdir(void) +{ + test_rmdir_path(); + + rmdir_file(); + rmdir_dot(); + rmdir_dotdot(); + rmdir_empty(); +} diff --git a/userland/testbin/badcall/bad_sbrk.c b/userland/testbin/badcall/bad_sbrk.c new file mode 100644 index 0000000..b482a92 --- /dev/null +++ b/userland/testbin/badcall/bad_sbrk.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * sbrk + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +/* + * typing wrapper around sbrk + */ +static +int +try_sbrk(long val) +{ + void *rv; + rv = sbrk(val); + if (rv==(void *)-1) { + return -1; + } + return 0; +} + +static +void +enforce_sbrk(long val, const char *desc, int err) +{ + int result; + + report_begin("sbrk %s", desc); + + result = try_sbrk(val); + report_check(result, errno, err); +} + +static +void +sbrk_bigpos(void) +{ + enforce_sbrk(4096*1024*256, "huge positive", ENOMEM); +} + +static +void +sbrk_bigneg(void) +{ + enforce_sbrk(-4096*1024*256, "huge negative", EINVAL); +} + +static +void +sbrk_neg(void) +{ + enforce_sbrk(-8192, "too-large negative", EINVAL); +} + +static +void +sbrk_unalignedpos(void) +{ + int result; + + report_begin("sbrk unaligned positive"); + result = try_sbrk(17); + report_check2(result, errno, 0, EINVAL); +} + +static +void +sbrk_unalignedneg(void) +{ + int result; + + report_begin("sbrk unaligned negative"); + result = try_sbrk(-17); + report_check2(result, errno, 0, EINVAL); +} + +void +test_sbrk(void) +{ + sbrk_neg(); + sbrk_bigpos(); + sbrk_bigneg(); + sbrk_unalignedpos(); + sbrk_unalignedneg(); +} + diff --git a/userland/testbin/badcall/bad_stat.c b/userland/testbin/badcall/bad_stat.c new file mode 100644 index 0000000..726f9b1 --- /dev/null +++ b/userland/testbin/badcall/bad_stat.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Bad calls to fstat, lstat, and stat + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +//////////////////////////////////////////////////////////// + +static +int +badbuf_fstat(struct stat *sb) +{ + return fstat(STDIN_FILENO, sb); +} + +static +int +badbuf_lstat(struct stat *sb) +{ + return lstat("null:", sb); +} + +static +int +badbuf_stat(struct stat *sb) +{ + return stat("null:", sb); +} + +static +void +common_badbuf(int (*statfunc)(struct stat *), void *ptr, + const char *call, const char *ptrdesc) +{ + int rv; + + report_begin("%s with %s buf", call, ptrdesc); + rv = statfunc(ptr); + report_check(rv, errno, EFAULT); +} + +static +void +any_badbuf(int (*statfunc)(struct stat *), const char *call) +{ + common_badbuf(statfunc, NULL, call, "NULL"); + common_badbuf(statfunc, INVAL_PTR, call, "invalid pointer"); + common_badbuf(statfunc, KERN_PTR, call, "kernel pointer"); +} + +//////////////////////////////////////////////////////////// + +static +void +any_empty(int (*statfunc)(const char *, struct stat *), const char *call) +{ + struct stat sb; + int rv; + + report_begin("%s on empty string", call); + rv = statfunc("", &sb); + report_check2(rv, errno, 0, EINVAL); +} + +//////////////////////////////////////////////////////////// + +void +test_fstat(void) +{ + test_fstat_fd(); + any_badbuf(badbuf_fstat, "fstat"); +} + +void +test_lstat(void) +{ + test_lstat_path(); + any_empty(lstat, "lstat"); + any_badbuf(badbuf_lstat, "lstat"); +} + +void +test_stat(void) +{ + test_stat_path(); + any_empty(stat, "stat"); + any_badbuf(badbuf_stat, "stat"); +} + diff --git a/userland/testbin/badcall/bad_symlink.c b/userland/testbin/badcall/bad_symlink.c new file mode 100644 index 0000000..68a3463 --- /dev/null +++ b/userland/testbin/badcall/bad_symlink.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * symlink + */ + +#include +#include + +#include "test.h" + +static +void +symlink_empty1(void) +{ + int rv; + + report_begin("symlink -> empty string"); + rv = symlink("", TESTLINK); + report_check2(rv, errno, 0, EINVAL); + remove(TESTLINK); +} + +static +void +symlink_empty2(void) +{ + int rv; + + report_begin("symlink named empty string"); + rv = symlink("foo", ""); + report_check(rv, errno, EINVAL); +} + +void +test_symlink(void) +{ + test_symlink_paths(); + symlink_empty1(); + symlink_empty2(); +} diff --git a/userland/testbin/badcall/bad_time.c b/userland/testbin/badcall/bad_time.c new file mode 100644 index 0000000..c5df61c --- /dev/null +++ b/userland/testbin/badcall/bad_time.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * __time + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +static +void +time_badsecs(void *ptr, const char *desc) +{ + int rv; + + report_begin("%s", desc); + rv = __time(ptr, NULL); + report_check(rv, errno, EFAULT); +} + +static +void +time_badnsecs(void *ptr, const char *desc) +{ + int rv; + + report_begin("%s", desc); + rv = __time(NULL, ptr); + report_check(rv, errno, EFAULT); +} + +void +test_time(void) +{ + time_badsecs(INVAL_PTR, "__time with invalid seconds pointer"); + time_badsecs(KERN_PTR, "__time with kernel seconds pointer"); + + time_badnsecs(INVAL_PTR, "__time with invalid nsecs pointer"); + time_badnsecs(KERN_PTR, "__time with kernel nsecs pointer"); +} diff --git a/userland/testbin/badcall/bad_waitpid.c b/userland/testbin/badcall/bad_waitpid.c new file mode 100644 index 0000000..f9bbd0d --- /dev/null +++ b/userland/testbin/badcall/bad_waitpid.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * bad calls to waitpid() + */ + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +static +void +wait_badpid(pid_t pid, const char *desc) +{ + pid_t rv; + int x; + int err; + + report_begin(desc); + rv = waitpid(pid, &x, 0); + err = errno; + /* Allow ENOSYS for 0 or negative values of pid only */ + if (pid <= 0 && rv == -1 && err == ENOSYS) { + err = ESRCH; + } + else if (err == ENOSYS) { + report_saw_enosys(); + } + report_check2(rv, err, ESRCH, ECHILD); +} + +static +void +wait_nullstatus(void) +{ + pid_t pid, rv; + int x; + + report_begin("wait with NULL status"); + + pid = fork(); + if (pid<0) { + report_warn("fork failed"); + report_aborted(); + return; + } + if (pid==0) { + exit(0); + } + + /* POSIX explicitly says passing NULL for status is allowed */ + rv = waitpid(pid, NULL, 0); + report_check(rv, errno, 0); + waitpid(pid, &x, 0); +} + +static +void +wait_badstatus(void *ptr, const char *desc) +{ + pid_t pid, rv; + int x; + + report_begin(desc); + + pid = fork(); + if (pid<0) { + report_warn("fork failed"); + report_aborted(); + return; + } + if (pid==0) { + exit(0); + } + + rv = waitpid(pid, ptr, 0); + report_check(rv, errno, EFAULT); + waitpid(pid, &x, 0); +} + +static +void +wait_unaligned(void) +{ + pid_t pid, rv; + int x; + int status[2]; /* will have integer alignment */ + char *ptr; + + report_begin("wait with unaligned status"); + + pid = fork(); + if (pid<0) { + report_warn("fork failed"); + report_aborted(); + return; + } + if (pid==0) { + exit(0); + } + + /* start with proper integer alignment */ + ptr = (char *)(&status[0]); + + /* generate improper alignment on platforms with restrictions */ + ptr++; + + rv = waitpid(pid, (int *)ptr, 0); + report_survival(rv, errno); + if (rv<0) { + waitpid(pid, &x, 0); + } +} + +static +void +wait_badflags(void) +{ + pid_t pid, rv; + int x; + + report_begin("wait with bad flags"); + + pid = fork(); + if (pid<0) { + report_warn("fork failed"); + report_aborted(); + return; + } + if (pid==0) { + exit(0); + } + + rv = waitpid(pid, &x, 309429); + report_check(rv, errno, EINVAL); + waitpid(pid, &x, 0); +} + +static +void +wait_self(void) +{ + pid_t rv; + int x; + + report_begin("wait for self"); + + rv = waitpid(getpid(), &x, 0); + report_survival(rv, errno); +} + +static +void +wait_parent(void) +{ + pid_t mypid, childpid, rv; + int x; + + report_begin("wait for parent"); + report_hassubs(); + + mypid = getpid(); + childpid = fork(); + if (childpid<0) { + report_warn("can't fork"); + report_aborted(); + return; + } + if (childpid==0) { + /* Child. Wait for parent. */ + rv = waitpid(mypid, &x, 0); + report_beginsub("from child:"); + report_survival(rv, errno); + _exit(0); + } + rv = waitpid(childpid, &x, 0); + report_beginsub("from parent:"); + report_survival(rv, errno); +} + +//////////////////////////////////////////////////////////// + +static +void +wait_siblings_child(const char *semname) +{ + pid_t pids[2], mypid, otherpid; + int rv, fd, semfd, x; + char c; + + mypid = getpid(); + + /* + * Get our own handle for the semaphore, in case naive + * file-level synchronization causes concurrent use to + * deadlock. + */ + semfd = open(semname, O_RDONLY); + if (semfd < 0) { + report_warn("child process (pid %d) can't open %s", + mypid, semname); + } + else { + if (read(semfd, &c, 1) < 0) { + report_warn("in pid %d: %s: read", mypid, semname); + } + close(semfd); + } + + fd = open(TESTFILE, O_RDONLY); + if (fd<0) { + report_warn("child process (pid %d) can't open %s", + mypid, TESTFILE); + return; + } + + /* + * In case the semaphore above didn't work, as a backup + * busy-wait until the parent writes the pids into the + * file. If the semaphore did work, this shouldn't loop. + */ + do { + rv = lseek(fd, 0, SEEK_SET); + if (rv<0) { + report_warn("child process (pid %d) lseek error", + mypid); + return; + } + rv = read(fd, pids, sizeof(pids)); + if (rv<0) { + report_warn("child process (pid %d) read error", + mypid); + return; + } + } while (rv < (int)sizeof(pids)); + + if (mypid==pids[0]) { + otherpid = pids[1]; + } + else if (mypid==pids[1]) { + otherpid = pids[0]; + } + else { + report_warn("child process (pid %d) got garbage in comm file", + mypid); + return; + } + close(fd); + + rv = waitpid(otherpid, &x, 0); + report_beginsub("sibling (pid %d)", mypid); + report_survival(rv, errno); +} + +static +void +wait_siblings(void) +{ + pid_t pids[2]; + int rv, fd, semfd, x; + int bad = 0; + char semname[32]; + + /* This test may also blow up if FS synchronization is substandard */ + + report_begin("siblings wait for each other"); + report_hassubs(); + + snprintf(semname, sizeof(semname), "sem:badcall.%d", (int)getpid()); + semfd = open(semname, O_WRONLY|O_CREAT|O_TRUNC, 0664); + if (semfd < 0) { + report_warn("can't make semaphore"); + report_aborted(); + return; + } + + fd = open_testfile(NULL); + if (fd<0) { + report_aborted(); + close(semfd); + remove(semname); + return; + } + + pids[0] = fork(); + if (pids[0]<0) { + report_warn("can't fork"); + report_aborted(); + close(fd); + close(semfd); + remove(semname); + return; + } + if (pids[0]==0) { + close(fd); + close(semfd); + wait_siblings_child(semname); + _exit(0); + } + + pids[1] = fork(); + if (pids[1]<0) { + report_warn("can't fork"); + report_aborted(); + /* abandon the other child process :( */ + close(fd); + close(semfd); + remove(semname); + return; + } + if (pids[1]==0) { + close(fd); + close(semfd); + wait_siblings_child(semname); + _exit(0); + } + + rv = write(fd, pids, sizeof(pids)); + if (rv < 0) { + report_warn("write error on %s", TESTFILE); + report_aborted(); + /* abandon child procs :( */ + close(fd); + close(semfd); + remove(semname); + return; + } + if (rv != (int)sizeof(pids)) { + report_warnx("write error on %s: short count", TESTFILE); + report_aborted(); + /* abandon child procs :( */ + close(fd); + close(semfd); + remove(semname); + return; + } + + /* gate the child procs */ + rv = write(semfd, " ", 2); + if (rv < 0) { + report_warn("%s: write", semname); + bad = 1; + } + + report_beginsub("overall"); + rv = waitpid(pids[0], &x, 0); + if (rv<0) { + report_warn("error waiting for child 0 (pid %d)", pids[0]); + bad = 1; + } + rv = waitpid(pids[1], &x, 0); + if (rv<0) { + report_warn("error waiting for child 1 (pid %d)", pids[1]); + bad = 1; + } + if (bad) { + /* XXX: aborted, or failure, or what? */ + report_aborted(); + } + else { + report_passed(); + } + close(fd); + close(semfd); + remove(semname); + remove(TESTFILE); +} + +//////////////////////////////////////////////////////////// + +void +test_waitpid(void) +{ + wait_badpid(-8, "wait for pid -8"); + wait_badpid(-1, "wait for pid -1"); + wait_badpid(0, "pid zero"); + wait_badpid(NONEXIST_PID, "nonexistent pid"); + + wait_nullstatus(); + wait_badstatus(INVAL_PTR, "wait with invalid pointer status"); + wait_badstatus(KERN_PTR, "wait with kernel pointer status"); + + wait_unaligned(); + + wait_badflags(); + + wait_self(); + wait_parent(); + wait_siblings(); +} diff --git a/userland/testbin/badcall/bad_write.c b/userland/testbin/badcall/bad_write.c new file mode 100644 index 0000000..8a79803 --- /dev/null +++ b/userland/testbin/badcall/bad_write.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Invalid calls to write() + */ + +#include "test.h" + +void +test_write(void) +{ + test_write_fd(); + test_write_buf(); +} diff --git a/userland/testbin/badcall/common_buf.c b/userland/testbin/badcall/common_buf.c new file mode 100644 index 0000000..37f7eaa --- /dev/null +++ b/userland/testbin/badcall/common_buf.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Calls with invalid transfer buffers + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +static int buf_fd; + +struct buftest { + int (*setup)(void); + int (*op)(void *); + void (*cleanup)(void); + const char *name; +}; + +//////////////////////////////////////////////////////////// + +static +int +read_setup(void) +{ + buf_fd = open_testfile("i do not like green eggs and ham"); + if (buf_fd<0) { + return -1; + } + return 0; +} + +static +int +read_badbuf(void *buf) +{ + return read(buf_fd, buf, 128); +} + +static +void +read_cleanup(void) +{ + close(buf_fd); + remove(TESTFILE); +} + +////////// + +static +int +write_setup(void) +{ + buf_fd = open_testfile(NULL); + if (buf_fd<0) { + return -1; + } + return 0; +} + +static +int +write_badbuf(void *ptr) +{ + return write(buf_fd, ptr, 128); +} + +static +void +write_cleanup(void) +{ + close(buf_fd); + remove(TESTFILE); +} + +////////// + +static +int +getdirentry_setup(void) +{ + buf_fd = open(".", O_RDONLY); + if (buf_fd < 0) { + warn("UH-OH: couldn't open ."); + return -1; + } + return 0; +} + +static +int +getdirentry_badbuf(void *ptr) +{ + return getdirentry(buf_fd, ptr, 1024); +} + +static +void +getdirentry_cleanup(void) +{ + close(buf_fd); +} + +////////// + +static +int +readlink_setup(void) +{ + return create_testlink(); +} + +static +int +readlink_badbuf(void *buf) +{ + return readlink(TESTLINK, buf, 168); +} + +static +void +readlink_cleanup(void) +{ + remove(TESTLINK); +} + +////////// + +static int getcwd_setup(void) { return 0; } +static void getcwd_cleanup(void) {} + +static +int +getcwd_badbuf(void *buf) +{ + return __getcwd(buf, 408); +} + +//////////////////////////////////////////////////////////// + +static +void +common_badbuf(struct buftest *info, void *buf, const char *bufdesc) +{ + int rv; + + + report_begin("%s with %s buffer", info->name, bufdesc); + info->setup(); + rv = info->op(buf); + report_check(rv, errno, EFAULT); + info->cleanup(); +} + +static +void +any_badbuf(struct buftest *info) +{ + common_badbuf(info, NULL, "NULL"); + common_badbuf(info, INVAL_PTR, "invalid"); + common_badbuf(info, KERN_PTR, "kernel-space"); +} + +//////////////////////////////////////////////////////////// + +#define T(call) \ + void \ + test_##call##_buf(void) \ + { \ + static struct buftest info = { \ + call##_setup, \ + call##_badbuf, \ + call##_cleanup, \ + #call, \ + }; \ + any_badbuf(&info); \ + } + +T(read); +T(write); +T(getdirentry); +T(readlink); +T(getcwd); diff --git a/userland/testbin/badcall/common_fds.c b/userland/testbin/badcall/common_fds.c new file mode 100644 index 0000000..173db73 --- /dev/null +++ b/userland/testbin/badcall/common_fds.c @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Calls with invalid fds + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + + +enum rwtestmodes { + RW_TEST_NONE, + RW_TEST_RDONLY, + RW_TEST_WRONLY, +}; + +static +int +read_badfd(int fd) +{ + char buf[128]; + return read(fd, buf, sizeof(buf)); +} + +static +int +write_badfd(int fd) +{ + char buf[128]; + memset(buf, 'a', sizeof(buf)); + return write(fd, buf, sizeof(buf)); +} + + +static +int +close_badfd(int fd) +{ + return close(fd); +} + +static +int +ioctl_badfd(int fd) +{ + return ioctl(fd, 0, NULL); +} + +static +int +lseek_badfd(int fd) +{ + return lseek(fd, 0, SEEK_SET); +} + +static +int +fsync_badfd(int fd) +{ + return fsync(fd); +} + +static +int +ftruncate_badfd(int fd) +{ + return ftruncate(fd, 60); +} + +static +int +fstat_badfd(int fd) +{ + struct stat sb; + return fstat(fd, &sb); +} + +static +int +getdirentry_badfd(int fd) +{ + char buf[32]; + return getdirentry(fd, buf, sizeof(buf)); +} + +static +int +dup2_badfd(int fd) +{ + /* use the +1 to avoid doing dup2(CLOSED_FD, CLOSED_FD) */ + return dup2(fd, CLOSED_FD+1); +} + +static +void +dup2_cleanup(void) +{ + close(CLOSED_FD+1); +} + +//////////////////////////////////////////////////////////// + +static +void +any_badfd(int (*func)(int fd), void (*cleanup)(void), const char *callname, + int fd, const char *fddesc) +{ + int rv; + + report_begin("%s using %s", callname, fddesc); + rv = func(fd); + report_check(rv, errno, EBADF); + if (cleanup) { + cleanup(); + } +} + +static +void +runtest(int (*func)(int fd), void (*cleanup)(void), const char *callname, + enum rwtestmodes rw) +{ + int fd; + + /* + * If adding cases, also see bad_dup2.c + */ + + /* basic invalid case: fd -1 */ + any_badfd(func, cleanup, callname, -1, "fd -1"); + + /* also try -5 in case -1 is special somehow */ + any_badfd(func, cleanup, callname, -5, "fd -5"); + + /* try a fd we know is closed */ + any_badfd(func, cleanup, callname, CLOSED_FD, "closed fd"); + + /* try a positive fd we know is out of range */ + any_badfd(func, cleanup, callname, IMPOSSIBLE_FD, "impossible fd"); + + /* test for off-by-one errors */ +#ifdef OPEN_MAX + any_badfd(func, cleanup, callname, OPEN_MAX, "fd OPEN_MAX"); +#else + warnx("Warning: OPEN_MAX not defined, test skipped"); +#endif + + if (rw == RW_TEST_RDONLY) { + fd = reopen_testfile(O_RDONLY|O_CREAT); + if (fd < 0) { + /* already printed a message */ + } + else { + any_badfd(func, cleanup, callname, fd, + "fd opened read-only"); + } + close(fd); + } + if (rw == RW_TEST_WRONLY) { + fd = reopen_testfile(O_WRONLY|O_CREAT); + if (fd < 0) { + /* already printed a message */ + } + else { + any_badfd(func, cleanup, callname, fd, + "fd opened write-only"); + } + close(fd); + } +} + +//////////////////////////////////////////////////////////// + +#define T(call, rw) \ + void \ + test_##call##_fd(void) \ + { \ + runtest(call##_badfd, NULL, #call, rw); \ + } + +#define TC(call, rw) \ + void \ + test_##call##_fd(void) \ + { \ + runtest(call##_badfd, call##_cleanup, #call, rw);\ + } + +T(read, RW_TEST_WRONLY); +T(write, RW_TEST_RDONLY); +T(close, RW_TEST_NONE); +T(ioctl, RW_TEST_NONE); +T(lseek, RW_TEST_NONE); +T(fsync, RW_TEST_NONE); +T(ftruncate, RW_TEST_RDONLY); +T(fstat, RW_TEST_NONE); +T(getdirentry, RW_TEST_WRONLY); +TC(dup2, RW_TEST_NONE); diff --git a/userland/testbin/badcall/common_path.c b/userland/testbin/badcall/common_path.c new file mode 100644 index 0000000..1a8ff9d --- /dev/null +++ b/userland/testbin/badcall/common_path.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Calls with invalid pathnames + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +static +int +open_badpath(const char *path) +{ + return open(path, O_RDONLY); +} + +static +int +remove_badpath(const char *path) +{ + return remove(path); +} + +static +int +rename_badpath1(const char *path) +{ + return rename(path, TESTFILE); +} + +static +int +rename_badpath2(const char *path) +{ + return rename(TESTFILE, path); +} + +static +int +link_badpath1(const char *path) +{ + return link(path, TESTFILE); +} + +static +int +link_badpath2(const char *path) +{ + return link(TESTFILE, path); +} + +static +int +mkdir_badpath(const char *path) +{ + return mkdir(path, 0775); +} + +static +int +rmdir_badpath(const char *path) +{ + return rmdir(path); +} + +static +int +chdir_badpath(const char *path) +{ + return chdir(path); +} + +static +int +symlink_badpath1(const char *path) +{ + return symlink(path, TESTFILE); +} + +static +int +symlink_badpath2(const char *path) +{ + return symlink(TESTFILE, path); +} + +static +int +readlink_badpath(const char *path) +{ + char buf[128]; + return readlink(path, buf, sizeof(buf)); +} + +static +int +lstat_badpath(const char *name) +{ + struct stat sb; + return lstat(name, &sb); +} + +static +int +stat_badpath(const char *name) +{ + struct stat sb; + return stat(name, &sb); +} + +//////////////////////////////////////////////////////////// + +static +void +common_badpath(int (*func)(const char *path), int mk, int rm, const char *path, + const char *call, const char *pathdesc) +{ + int rv; + + report_begin("%s with %s path", call, pathdesc); + + if (mk) { + if (create_testfile()<0) { + report_aborted(); + return; + } + } + + rv = func(path); + report_check(rv, errno, EFAULT); + + if (mk || rm) { + remove(TESTFILE); + } +} + +static +void +any_badpath(int (*func)(const char *path), const char *call, int mk, int rm) +{ + common_badpath(func, mk, rm, NULL, call, "NULL"); + common_badpath(func, mk, rm, INVAL_PTR, call, "invalid-pointer"); + common_badpath(func, mk, rm, KERN_PTR, call, "kernel-pointer"); +} + +//////////////////////////////////////////////////////////// + +/* functions with one pathname */ +#define T(call) \ + void \ + test_##call##_path(void) \ + { \ + any_badpath(call##_badpath, #call, 0, 0); \ + } + +T(open); +T(remove); +T(mkdir); +T(rmdir); +T(chdir); +T(readlink); +T(stat); +T(lstat); + +/* functions with two pathnames */ +#define T2(call) \ + void \ + test_##call##_paths(void) \ + { \ + any_badpath(call##_badpath1, #call "(arg1)", 0, 1); \ + any_badpath(call##_badpath2, #call "(arg2)", 1, 1); \ + } + +T2(rename); +T2(link); +T2(symlink); diff --git a/userland/testbin/badcall/config.h b/userland/testbin/badcall/config.h new file mode 100644 index 0000000..68d9d8f --- /dev/null +++ b/userland/testbin/badcall/config.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Note: if the assumptions in the constants below are violated by + * your system design, please change the values as necessary. Don't + * change stuff in the .c files, or disable tests, without consulting + * the course staff first. + */ + +#if defined(__mips__) +#define KERN_PTR ((void *)0x80000000) /* addr within kernel */ +#define INVAL_PTR ((void *)0x40000000) /* addr not part of program */ +#else +#error "Please fix this" +#endif + +/* + * We assume CLOSED_FD is a legal fd that won't be open when we're running. + * CLOSED_FD+1 should also be legal and not open. + */ +#define CLOSED_FD 10 + +/* We assume IMPOSSIBLE_FD is a fd that is completely not allowed. */ +#define IMPOSSIBLE_FD 1234567890 + +/* We assume this pid won't exist while we're running. Change as needed. */ +#define NONEXIST_PID 34000 + +/* An arbitrary process exit code that hopefully won't occur by accident */ +#define MAGIC_STATUS 107 + +/* An ioctl that doesn't exist */ +#define NONEXIST_IOCTL 12345 diff --git a/userland/testbin/badcall/driver.c b/userland/testbin/badcall/driver.c new file mode 100644 index 0000000..31142f0 --- /dev/null +++ b/userland/testbin/badcall/driver.c @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +//////////////////////////////////////////////////////////// + +int +open_testfile(const char *string) +{ + int fd, rv; + size_t len; + + fd = open(TESTFILE, O_RDWR|O_CREAT|O_TRUNC, 0664); + if (fd<0) { + report_warn("creating %s: failed", TESTFILE); + return -1; + } + + if (string) { + len = strlen(string); + rv = write(fd, string, len); + if (rv<0) { + report_warn("write to %s failed", TESTFILE); + close(fd); + remove(TESTFILE); + return -1; + } + if ((unsigned)rv != len) { + report_warn("write to %s got short count", TESTFILE); + close(fd); + remove(TESTFILE); + return -1; + } + rv = lseek(fd, 0, SEEK_SET); + if (rv<0) { + report_warn("rewind of %s failed", TESTFILE); + close(fd); + remove(TESTFILE); + return -1; + } + } + return fd; +} + +int +create_testfile(void) +{ + int fd, rv; + + fd = open_testfile(NULL); + if (fd<0) { + return -1; + } + + rv = close(fd); + if (rv<0) { + report_warn("closing %s failed", TESTFILE); + return -1; + } + + return 0; +} + +int +reopen_testfile(int openflags) +{ + int fd; + + fd = open(TESTFILE, openflags, 0664); + if (fd < 0) { + report_warn("reopening %s: failed", TESTFILE); + return -1; + } + return fd; +} + +/* + * Note: unlike everything else this calls skipped/aborted, because + * otherwise it has to communicate to the caller which to call and + * that's a pain. + */ +int +create_testdir(void) +{ + int rv; + rv = mkdir(TESTDIR, 0775); + if (rv<0) { + if (errno == ENOSYS) { + report_saw_enosys(); + report_warnx("mkdir unimplemented; cannot run test"); + report_skipped(); + } + else { + report_warn("mkdir %s failed", TESTDIR); + report_aborted(); + } + return -1; + } + return 0; +} + +int +create_testlink(void) +{ + int rv; + rv = symlink("blahblah", TESTLINK); + if (rv<0) { + report_warn("making symlink %s failed", TESTLINK); + return -1; + } + return 0; +} + +//////////////////////////////////////////////////////////// + +static +struct { + int ch; + int asst; + const char *name; + void (*f)(void); +} ops[] = { + { 'a', 2, "execv", test_execv }, + { 'b', 2, "waitpid", test_waitpid }, + { 'c', 2, "open", test_open }, + { 'd', 2, "read", test_read }, + { 'e', 2, "write", test_write }, + { 'f', 2, "close", test_close }, + { 'g', 0, "reboot", test_reboot }, + { 'h', 3, "sbrk", test_sbrk }, + { 'i', 5, "ioctl", test_ioctl }, + { 'j', 2, "lseek", test_lseek }, + { 'k', 4, "fsync", test_fsync }, + { 'l', 4, "ftruncate", test_ftruncate }, + { 'm', 4, "fstat", test_fstat }, + { 'n', 4, "remove", test_remove }, + { 'o', 4, "rename", test_rename }, + { 'p', 5, "link", test_link }, + { 'q', 4, "mkdir", test_mkdir }, + { 'r', 4, "rmdir", test_rmdir }, + { 's', 2, "chdir", test_chdir }, + { 't', 4, "getdirentry", test_getdirentry }, + { 'u', 5, "symlink", test_symlink }, + { 'v', 5, "readlink", test_readlink }, + { 'w', 2, "dup2", test_dup2 }, + { 'x', 5, "pipe", test_pipe }, + { 'y', 5, "__time", test_time }, + { 'z', 2, "__getcwd", test_getcwd }, + { '{', 5, "stat", test_stat }, + { '|', 5, "lstat", test_lstat }, + { 0, 0, NULL, NULL } +}; + +#define LOWEST 'a' +#define HIGHEST '|' + +static +void +menu(void) +{ + int i; + for (i=0; ops[i].name; i++) { + printf("[%c] %-24s", ops[i].ch, ops[i].name); + if (i%2==1) { + printf("\n"); + } + } + if (i%2==1) { + printf("\n"); + } + printf("[1] %-24s", "asst1"); + printf("[2] %-24s\n", "asst2"); + printf("[3] %-24s", "asst3"); + printf("[4] %-24s\n", "asst4"); + printf("[*] %-24s", "all"); + printf("[!] %-24s\n", "quit"); +} + +static +void +runit(int op) +{ + int i, k; + + if (op=='!') { + exit(0); + } + + if (op=='?') { + menu(); + return; + } + + if (op=='*') { + for (i=0; ops[i].name; i++) { + printf("[%s]\n", ops[i].name); + ops[i].f(); + } + return; + } + + if (op>='1' && op <= '4') { + k = op-'0'; + for (i=0; ops[i].name; i++) { + if (ops[i].asst <= k) { + printf("[%s]\n", ops[i].name); + ops[i].f(); + } + } + return; + } + + if (op < LOWEST || op > HIGHEST) { + printf("Invalid request %c\n", op); + return; + } + + ops[op-'a'].f(); +} + +int +main(int argc, char **argv) +{ + int op, i, j; + + printf("[%c-%c, 1-4, *, ?=menu, !=quit]\n", LOWEST, HIGHEST); + + if (argc > 1) { + for (i=1; i +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "test.h" + +#define RESULT_COLUMN 72 + +/* current screen column (0-based) */ +static size_t horizpos; + +/* saved screen column for subreports */ +static size_t subpos; + +/* pending output buffer */ +static char outbuf[256]; +static size_t outbufpos; + +//////////////////////////////////////////////////////////// + +/* + * Print things. + */ +static +void +vsay(const char *fmt, va_list ap) +{ + size_t begin, i; + + assert(outbufpos < sizeof(outbuf)); + + begin = outbufpos; + vsnprintf(outbuf + outbufpos, sizeof(outbuf) - outbufpos, fmt, ap); + outbufpos = strlen(outbuf); + + for (i=begin; i +#include +#include +#include +#include +#include +#include + +#define _PATH_MYSELF "/testbin/bigexec" + +//////////////////////////////////////////////////////////// +// words + +static const char word8[] = "Dalemark"; +static char word4050[4051]; +static char word16320[16321]; +static char word65500[65501]; + +static +void +fill(char *buf, size_t buflen) +{ + static const char *const names[22] = { + "Alhammitt", "Biffa", "Cennoreth", "Dastgandlen", "Enblith", + "Fenna", "Gull", "Hern", "Hildrida", "Kankredin", "Kialan", + "Lenina", "Manaliabrid", "Mayelbridwen", "Noreth", "Osfameron", + "Robin", "Tanamil", "Tanamoril", "Tanaqui", "Ynen", "Ynynen" + }; + + const char *name; + size_t len; + + while (buflen > 4) { + name = names[random()%22]; + len = strlen(name); + if (len < buflen) { + strcpy(buf, name); + buf += len; + buflen -= len; + if (buflen > 1) { + *buf = ' '; + buf++; + buflen--; + } + } + } + while (buflen > 1) { + *buf = '.'; + buf++; + buflen--; + } + *buf = 0; +} + +static +void +prepwords(void) +{ + srandom(16581); + fill(word4050, sizeof(word4050)); + fill(word16320, sizeof(word16320)); + fill(word65500, sizeof(word65500)); +} + +//////////////////////////////////////////////////////////// +// execing/checking + +static +void +try(const char *first, ...) +{ + const char *args[20]; + const char *s; + va_list ap; + int num; + + assert(first != NULL); + args[0] = _PATH_MYSELF; + args[1] = first; + num = 2; + + va_start(ap, first); + while (1) { + s = va_arg(ap, const char *); + if (s == NULL) { + break; + } + assert(num < 20); + args[num++] = s; + } + assert(num < 20); + args[num] = NULL; + execv(_PATH_MYSELF, (char **)args); + err(1, "execv"); +} + +static +void +trymany(int num, const char *word) +{ + const char *args[num+2]; + int i; + + args[0] = _PATH_MYSELF; + for (i=0; i= 65536); + + if (argv == NULL || argc == 0 || argc == 1) { + /* no args -- start the test */ + warnx("Starting."); + + /* + * 1. Should always fit no matter what. + */ + warnx("1. Execing with one 8-letter word."); + try(word8, NULL); + } + else if (check(argc, argv, word8, NULL)) { + /* + * 2. Fits in one page. + */ + warnx("2. Execing with one 4050-letter word."); + try(word4050, NULL); + } + else if (check(argc, argv, word4050, NULL)) { + /* + * 3. Requires two pages but each word fits on a page. + */ + warnx("3. Execing with two 4050-letter words."); + try(word4050, word4050, NULL); + } + else if (check(argc, argv, word4050, word4050, NULL)) { + /* + * 4. Requires the full 64K argv buffer, in large + * chunks, with a little space for slop. Each word + * fits on a page though. With null terminators and + * 4-byte pointers the size is 4085*16 = 65360, and + * with 8-byte pointers it would become 65424. + * + * Don't forget that argv[0] will be another 21 or 25 + * bytes and some implementations may reasonably need + * to stash an ending NULL in the buffer too. + */ + warnx("4. Execing with 16 4050-letter words."); + try(word4050, word4050, word4050, word4050, + word4050, word4050, word4050, word4050, + word4050, word4050, word4050, word4050, + word4050, word4050, word4050, word4050, + NULL); + } + else if (check(argc, argv, + word4050, word4050, word4050, word4050, + word4050, word4050, word4050, word4050, + word4050, word4050, word4050, word4050, + word4050, word4050, word4050, word4050, + NULL)) { + /* + * 5. Requires more than one page for a single word. + */ + warnx("5. Execing with one 16320-letter word."); + try(word16320, NULL); + } + else if (check(argc, argv, word16320, NULL)) { + /* + * 6. Ditto but makes sure it works with two of them. + */ + warnx("6. Execing with two 16320-letter words."); + try(word16320, word16320, NULL); + } + else if (check(argc, argv, word16320, word16320, NULL)) { + /* + * 7. Requires the full 64K argv buffer. + */ + warnx("7. Execing with four 16320-letter words."); + try(word16320, word16320, word16320, word16320, + NULL); + } + else if (check(argc, argv, word16320, word16320, + word16320, word16320, NULL)) { + /* + * 8. Also requires the full 64K argv buffer, but with + * only one huge word. + */ + warnx("8. Execing with one 65500-letter word."); + try(word65500, NULL); + } + else if (check(argc, argv, word65500, NULL)) { + /* + * 9. This fits on one page. Given 4-byte pointers, + * (8+1+4)*300 = 3900. With 8-byte pointers, it + * doesn't, but we aren't doing that. (Update this if + * we ever move to a 64-bit platform.) + */ + assert((8+1+sizeof(char *))*300 < 4096); + warnx("9. Execing with 300 8-letter words."); + trymany(300, word8); + } + else if (checkmany(argc, argv, 300, word8)) { +#if 1 /* enforce the full size */ + /* + * 10. This requires the full 64K argv buffer. + * With 4-byte pointers, (8+1+4)*5020 = 65260. + * It also doesn't fit with 8-byte pointers. + * + * XXX for the time being, we'll allow less efficient + * implementations that use two pointers per word. + * Hence, (8+1+4+4)*3850 = 65450. + */ + assert((8+1+sizeof(char *))*5020 < 65536); + assert((8+1+2*sizeof(char *))*3850 < 65536); + warnx("10. Execing with 3850 8-letter words."); + trymany(3850, word8); + } + else if (checkmany(argc, argv, 3850, word8)) { +#else + /* + * 10a. This requires more than one page using small + * words. With 4-byte pointers, (8+1+4)*1000 = 13000. + */ + warnx("10. Execing with 1000 8-letter words."); + trymany(1000, word8); + } + else if (checkmany(argc, argv, 1000, word8)) { +#endif + warnx("Complete."); + return 0; + } + else { + warnx("Received unknown/unexpected args:"); + dumpargs(argc, argv); + return 1; + } +} diff --git a/userland/testbin/bigfile/Makefile b/userland/testbin/bigfile/Makefile new file mode 100644 index 0000000..fb58749 --- /dev/null +++ b/userland/testbin/bigfile/Makefile @@ -0,0 +1,11 @@ +# Makefile for bigfile + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=bigfile +SRCS=bigfile.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/bigfile/bigfile.c b/userland/testbin/bigfile/bigfile.c new file mode 100644 index 0000000..6dc7b55 --- /dev/null +++ b/userland/testbin/bigfile/bigfile.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Create a large file in small increments. + * + * Should work on emufs (emu0:) once the basic system calls are done, + * and should work on SFS when the file system assignment is + * done. Sufficiently small files should work on SFS even before that + * assignment. + */ + +#include +#include +#include +#include +#include + +static char buffer[8192 + 1]; + +int +main(int argc, char *argv[]) +{ + const char *filename; + char *s; + size_t i, size, chunksize, offset; + ssize_t len; + int fd; + + if (argc != 3) { + warnx("Usage: bigfile "); + errx(1, " or: bigfile /"); + } + + filename = argv[1]; + s = strchr(argv[2], '/'); + if (s != NULL) { + *s++ = 0; + chunksize = atoi(s); + if (chunksize >= sizeof(buffer)) { + chunksize = sizeof(buffer) - 1; + } + if (chunksize == 0) { + errx(1, "Really?"); + } + } + else { + chunksize = 10; + } + size = atoi(argv[2]); + + /* round size up */ + size = ((size + chunksize - 1) / chunksize) * chunksize; + + printf("Creating a file of size %d in %d-byte chunks\n", + size, chunksize); + + fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC); + if (fd < 0) { + err(1, "%s: create", filename); + } + + i=0; + while (i +#include +#include +#include +#include + +#define BRANCHES 6 + +/* + * 6 branches gives 64 procs at the final stage, and we want this to + * use about 4M. So each proc's memory load should be about 1/16M or + * 64K. Which is 16384 ints, or four 64x64 matrixes. + */ +#define DIM 64 + +static int m1[DIM*DIM], m2[DIM*DIM], m3[DIM*DIM], m4[DIM*DIM]; +static const int right[BRANCHES] = { + 536763422, + 478946723, + 375722852, + 369910585, + 328220902, + 62977821, +}; +static unsigned failures; + +static +void +init(void) +{ + unsigned i, j; + + srandom(73771); + for (i=0; i 0) { + failures += WEXITSTATUS(status); + } + } +} + +static +void +dotest(void) +{ + unsigned i, me; + pid_t pids[BRANCHES]; + int t; + char msg[128]; + + me = 0; + for (i=0; i 0; ) { + dowait(pids[i]); + } + if (failures > 0) { + printf("%u failures.\n", failures); + } + else { + printf("Done.\n"); + } +} + +int +main(void) +{ + init(); + dotest(); + return 0; +} diff --git a/userland/testbin/bigseek/Makefile b/userland/testbin/bigseek/Makefile new file mode 100644 index 0000000..d62d465 --- /dev/null +++ b/userland/testbin/bigseek/Makefile @@ -0,0 +1,11 @@ +# Makefile for bigseek + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=bigseek +SRCS=bigseek.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/bigseek/bigseek.c b/userland/testbin/bigseek/bigseek.c new file mode 100644 index 0000000..aab4601 --- /dev/null +++ b/userland/testbin/bigseek/bigseek.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * Test for seek positions > 2^32. + * + * This test is a bit hamstrung because neither emufs nor sfs supports + * files larger than 2^32. (In fact, because sfs has 512-byte blocks, + * to support a file of size 2^32 you'd need a quadruple-indirect + * block, not just triple. But even with that it won't work because + * the file size is a uint32_t.) + * + * We do, however, want to check if lseek is manipulating its 64-bit + * argument correctly. The fs-independent code you're supposed to + * write should be using off_t, which is 64 bits wide, to hold the + * seek position. So seeking to positions past 2^32 should work, and + * it should be possible to read back the seek position we set even if + * it's past 2^32. + * + * Actually reading past 2^32 should behave the same as reading beyond + * EOF anywhere else (produces EOF) and writing past 2^32 should yield + * EFBIG. + * + * We also test between 2^31 and 2^32 in case values in that range are + * getting truncated to a signed 32-bit value and then rejected for + * being negative. + */ + +#define TESTFILE "bigseekfile" + +static const char *slogans[] = { + "QUO USQUE TANDEM ABUTERE CATILINA PATENTIA NOSTRA", + "QUEM IN FINEM SESE EFFRENATA IACTABIT AUDACIA" +}; + +static +void +write_slogan(int fd, unsigned which, bool failok) +{ + size_t len; + ssize_t r; + + len = strlen(slogans[which]); + r = write(fd, slogans[which], len); + if (r < 0) { + if (failok && errno == EFBIG) { + return; + } + err(1, "write"); + } + if (failok) { + errx(1, "write: expected failure but wrote %zd bytes", r); + } + if ((size_t)r != len) { + errx(1, "write: result %zd bytes, expected %zu", r, len); + } +} + +static +void +check_slogan(int fd, unsigned which) +{ + char buf[256]; + size_t len; + ssize_t r; + unsigned i, wrongcount; + + r = read(fd, buf, sizeof(buf)); + if (r < 0) { + err(1, "read"); + } + if (r == 0) { + errx(1, "read: Unexpected EOF"); + } + + /* we should get either a full buffer or the length of the slogan */ + len = strlen(slogans[which]); + if ((size_t)r != sizeof(buf) && (size_t)r != len) { + errx(1, "read: result %zd bytes, expected %zu or %zu", + r, sizeof(buf), len); + } + + /* slogan should match */ + if (memcmp(buf, slogans[which], len) != 0) { + warnx("read: got wrong data"); + warnx("expected: %s", slogans[which]); + buf[sizeof(buf) - 1] = 0; + errx(1, "found: %s", buf); + } + + /* bytes past the slogan (if any) should be 0 */ + wrongcount = 0; + for (i=len; i<(size_t)r; i++) { + if (buf[i] != 0) { + warnx("read: buf[%zu] was 0x%x, expected 0", i, + (unsigned char)buf[i]); + wrongcount++; + } + } + if (wrongcount > 0) { + errx(1, "%u bytes of trash in file", wrongcount); + } +} + +static +void +try_reading(int fd) +{ + char buf[16]; + ssize_t r; + + r = read(fd, buf, sizeof(buf)); + if (r == 0) { + /* expected EOF */ + return; + } + if (r < 0) { + err(1, "read"); + } + errx(1, "read: Expected EOF but got %zd bytes", r); +} + +static +void +try_writing(int fd) +{ + write_slogan(fd, 1, true); +} + +static +void +dolseek(int fd, off_t pos, int whence, const char *whencestr, off_t expected) +{ + off_t result; + + result = lseek(fd, pos, whence); + if (result == -1) { + err(1, "lseek(fd, 0x%llx, %s)", pos, whencestr); + } + if (result != expected) { + errx(1, "lseek(fd, 0x%llx, %s): Wrong return value" + " (got 0x%llx, expected 0x%llx)", pos, whencestr, + result, expected); + } +} + +static +void +try_seeking(int fd, off_t pos, off_t cursize) +{ + printf("Seeking to (and near) 0x%llx\n", pos); + + /* Go to the place. */ + dolseek(fd, pos, SEEK_SET, "SEEK_SET", pos); + + /* Go to where we already are. */ + dolseek(fd, 0, SEEK_CUR, "SEEK_CUR", pos); + + if (pos >= 10) { + /* Back up a little. */ + dolseek(fd, -10, SEEK_CUR, "SEEK_CUR", pos - 10); + + /* Forward a little. */ + dolseek(fd, 20, SEEK_CUR, "SEEK_CUR", pos + 10); + } + else { + /* Just forward a little. */ + dolseek(fd, 10, SEEK_CUR, "SEEK_CUR", pos + 10); + } + + /* Via SEEK_END. */ + dolseek(fd, pos, SEEK_END, "SEEK_END", pos + cursize); + + /* Go back to the exact place. */ + dolseek(fd, pos, SEEK_SET, "SEEK_SET", pos); +} + +int +main(void) +{ + off_t cursize; + int fd; + + printf("Creating file...\n"); + fd = open(TESTFILE, O_RDWR|O_CREAT|O_TRUNC, 0664); + if (fd < 0) { + err(1, "%s", TESTFILE); + } + + printf("Writing something at offset 0\n"); + write_slogan(fd, 0, false); + cursize = strlen(slogans[0]); + + try_seeking(fd, (off_t)0x1000LL, cursize); + + printf("Writing something else\n"); + write_slogan(fd, 1, false); + cursize = (off_t)0x1000LL + strlen(slogans[1]); + + try_seeking(fd, (off_t)0, cursize); + + /* If seek is totally bust, this will fail. */ + printf("Checking what we wrote\n"); + check_slogan(fd, 0); + + try_seeking(fd, (off_t)0x1000LL, cursize); + printf("Checking the other thing we wrote\n"); + check_slogan(fd, 1); + + try_seeking(fd, (off_t)0x20LL, cursize); + try_seeking(fd, (off_t)0x7fffffffLL, cursize); + try_seeking(fd, (off_t)0x80000000LL, cursize); + try_seeking(fd, (off_t)0x80000020LL, cursize); + try_seeking(fd, (off_t)0x100000000LL, cursize); + try_seeking(fd, (off_t)0x100000020LL, cursize); + try_seeking(fd, (off_t)0x180000000LL, cursize); + try_seeking(fd, (off_t)0x180000020LL, cursize); + + printf("Now trying to read (should get EOF)\n"); + try_reading(fd); + + printf("Now trying to write (should get EFBIG)\n"); + try_writing(fd); + + try_seeking(fd, (off_t)0x100000000LL, cursize); + + /* If seek truncates to 32 bits, this might read the slogan instead */ + printf("Trying to read again (should get EOF)\n"); + try_reading(fd); + + printf("Passed.\n"); + + close(fd); + remove(TESTFILE); + return 0; +} diff --git a/userland/testbin/bloat/Makefile b/userland/testbin/bloat/Makefile new file mode 100644 index 0000000..5d5e060 --- /dev/null +++ b/userland/testbin/bloat/Makefile @@ -0,0 +1,11 @@ +# Makefile for bloat + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=bloat +SRCS=bloat.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/bloat/bloat.c b/userland/testbin/bloat/bloat.c new file mode 100644 index 0000000..ed5aca7 --- /dev/null +++ b/userland/testbin/bloat/bloat.c @@ -0,0 +1,204 @@ +/* + * bloat - waste memory. + * + * This test allocates memory a page at a time and keeps going until + * it runs out. It gets the memory directly with sbrk to avoid malloc- + * related overheads, which as long as OS/161 has a dumb userlevel + * malloc is important for performance. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* OS/161 doesn't currently have a way to get this from the kernel. */ +#define PAGE_SIZE 4096 + +/* the memory we've gotten */ +static void *firstpage; +static void *lastpage; + +/* number of page allocations per cycle */ +static unsigned allocs; + +/* number of pages to touch every cycle */ +static unsigned touchpages; + +/* when touching pages, the extent to which we favor the middle of the range */ +static unsigned bias; + + +static +void +moremem(void) +{ + static unsigned totalpages; + + void *ptr; + unsigned i; + + for (i=0; i= numpages) { + mnum = numpages; + } + moffset = numpages / 2 - mnum / 2; + + assert(bias >= 1); + span = (mnum + bias - 1) / bias; + + do { + val = 0; + for (i=0; i= mnum); + return moffset + val; +} + +static +void +touchmem(void) +{ + unsigned i, num; + + num = (((uintptr_t)lastpage - (uintptr_t)firstpage) / PAGE_SIZE) + 1; + + if (num % 256 == 0) { + warnx("%u pages", num); + } + + for (i=0; i +#include + +int +main(void) +{ + char ch=0; + int len; + + while (ch!='q') { + len = read(STDIN_FILENO, &ch, 1); + if (len < 0) { + err(1, "stdin: read"); + } + if (len==0) { + /* EOF */ + break; + } + write(STDOUT_FILENO, &ch, 1); + } + return 0; +} diff --git a/userland/testbin/crash/Makefile b/userland/testbin/crash/Makefile new file mode 100644 index 0000000..e7ab480 --- /dev/null +++ b/userland/testbin/crash/Makefile @@ -0,0 +1,11 @@ +# Makefile for crash + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=crash +SRCS=crash.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/crash/crash.c b/userland/testbin/crash/crash.c new file mode 100644 index 0000000..57406aa --- /dev/null +++ b/userland/testbin/crash/crash.c @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * crash.c + * + * Commit a variety of exceptions, primarily address faults. + * + * Once the basic system calls assignment is complete, none of these + * should crash the kernel. + * + * They should all, however, terminate this program, except for the + * one that writes to the code segment. (That one won't cause program + * termination until/unless you implement read-only segments in your + * VM system.) + */ + +#include +#include +#include +#include +#include + +#if defined(__mips__) +#define KERNEL_ADDR 0x80000000 +#define INVAL_ADDR 0x40000000 +#define INSN_TYPE uint32_t +#define INVAL_INSN 0x0000003f +#else +#error "Please fix this" +#endif + +#define MAGIC 123456 + +typedef void (*func)(void); + +static int forking = 1; + +static +void +read_from_null(void) +{ + int *null = NULL; + volatile int x; + + x = *null; + + // gcc 4.8 improperly demands this + (void)x; +} + +static +void +read_from_inval(void) +{ + int *ptr = (int *) INVAL_ADDR; + volatile int x; + + x = *ptr; + + // gcc 4.8 improperly demands this + (void)x; +} + +static +void +read_from_kernel(void) +{ + int *ptr = (int *) KERNEL_ADDR; + volatile int x; + + x = *ptr; + + // gcc 4.8 improperly demands this + (void)x; +} + +static +void +write_to_null(void) +{ + int *null = NULL; + *null = 6; +} + +static +void +write_to_inval(void) +{ + int *ptr = (int *) INVAL_ADDR; + *ptr = 8; +} + +static +void +write_to_code(void) +{ + INSN_TYPE *x = (INSN_TYPE *)write_to_code; + *x = INVAL_INSN; +} + +static +void +write_to_kernel(void) +{ + int *ptr = (int *) KERNEL_ADDR; + *ptr = 8; +} + +static +void +jump_to_null(void) +{ + func f = NULL; + f(); +} + +static +void +jump_to_inval(void) +{ + func f = (func) INVAL_ADDR; + f(); +} + +static +void +jump_to_kernel(void) +{ + func f = (func) KERNEL_ADDR; + f(); +} + + +static +void +illegal_instruction(void) +{ +#if defined(__mips__) + asm(".long 0x0000003f"); +#else +#error "Please fix this" +#endif +} + +static +void +alignment_error(void) +{ + int x; + int *ptr, *badptr; + volatile uintptr_t ptrval; + volatile int j; + + x = 0; + ptr = &x; + /* + * Try to hide what's going on from gcc; gcc 4.8 seems to + * detect the unaligned access and issue unaligned read + * instructions for it, so then it doesn't fault. Feh. + */ + ptrval = (uintptr_t)ptr; + ptrval++; + badptr = (int *)ptrval; + + j = *badptr; + + // gcc 4.8 improperly demands this + (void)j; +} + +static +void +divide_by_zero(void) +{ + volatile int x = 6; + volatile int z = 0; + volatile int a; + + a = x/z; + + // gcc 4.8 improperly demands this + (void)a; +} + +static +void +mod_by_zero(void) +{ + volatile int x = 6; + volatile int z = 0; + volatile int a; + + a = x%z; + + // gcc 4.8 improperly demands this + (void)a; +} + +static +void +recurse_inf(void) +{ + volatile char buf[16]; + + buf[0] = 0; + recurse_inf(); + buf[0] = 1; + + // gcc 4.8 improperly demands this + (void)buf; +} + + +static +struct { + int ch; + const char *name; + func f; + int sig; +} ops[] = { + { 'a', "read from NULL", read_from_null, SIGSEGV }, + { 'b', "read from invalid address", read_from_inval, SIGSEGV }, + { 'c', "read from kernel address", read_from_kernel, SIGBUS }, + { 'd', "write to NULL", write_to_null, SIGSEGV }, + { 'e', "write to invalid address", write_to_inval, SIGSEGV }, + { 'f', "write to code segment", write_to_code, SIGSEGV }, + { 'g', "write to kernel address", write_to_kernel, SIGBUS }, + { 'h', "jump to NULL", jump_to_null, SIGSEGV }, + { 'i', "jump to invalid address", jump_to_inval, SIGSEGV }, + { 'j', "jump to kernel address", jump_to_kernel, SIGBUS }, + { 'k', "alignment error", alignment_error, SIGBUS }, + { 'l', "illegal instruction", illegal_instruction, SIGILL }, + { 'm', "divide by zero", divide_by_zero, SIGTRAP }, + { 'n', "mod by zero", mod_by_zero, SIGTRAP }, + { 'o', "Recurse infinitely", recurse_inf, SIGSEGV }, + { 0, NULL, NULL, 0 } +}; + +static +void +runop(int op) +{ + int opindex; + pid_t pid; + int status; + int ok; + + if (op=='*') { + for (unsigned i=0; ops[i].name; i++) { + runop(ops[i].ch); + } + return; + } + else if (op == '-') { + forking = 0; + warnx("Forking disabled - next try will be the last"); + return; + } + else if (op == '+') { + forking = 1; + warnx("Forking enabled."); + return; + } + + /* intentionally don't check if op is in bounds :) */ + opindex = op-'a'; + + printf("Running: [%c] %s\n", ops[opindex].ch, ops[opindex].name); + + if (forking) { + pid = fork(); + if (pid < 0) { + /* error */ + err(1, "fork"); + } + else if (pid > 0) { + /* parent */ + if (waitpid(pid, &status, 0) < 0) { + err(1, "waitpid"); + } + ok = 0; + if (WIFSIGNALED(status)) { + printf("Signal %d\n", WTERMSIG(status)); + if (WTERMSIG(status) == ops[opindex].sig) { + ok = 1; + } + } + else { + printf("Exit %d\n", WEXITSTATUS(status)); + if (WEXITSTATUS(status) == MAGIC) { + ok = 1; + } + } + if (ok) { + printf("Ok.\n"); + } + else { + printf("FAILED: expected signal %d\n", + ops[opindex].sig); + } + printf("\n"); + return; + } + } + /* child, or not forking */ + + ops[opindex].f(); + + if (op == 'f') { + warnx(".... I guess you don't support read-only segments"); + /* use this magic signaling value so parent doesn't say FAIL */ + _exit(MAGIC); + } + errx(1, "I wasn't killed!"); +} + +static +void +ask(void) +{ + unsigned i; + int op; + + while (1) { + + for (i=0; ops[i].name; i++) { + printf("[%c] %s\n", ops[i].ch, ops[i].name); + } + printf("[-] Disable forking\n"); + printf("[+] Enable forking (default)\n"); + printf("[*] Run everything\n"); + printf("[!] Quit\n"); + + printf("Choose: "); + op = getchar(); + + if (op == '!') { + break; + } + + runop(op); + } +} + +int +main(int argc, char **argv) +{ + if (argc == 0 || argc == 1) { + /* no arguments */ + ask(); + } + else { + /* run the selected ops */ + for (int i=1; i +#include + +/* + * SIZE is the amount of memory used. + * DEFAULT is the default stride. + * Note that SIZE and DEFAULT should be relatively prime. + */ +#define SIZE (1024*1024/sizeof(struct entry)) +#define DEFAULT 477 + +struct entry { + struct entry *e; +}; + +struct entry array[SIZE]; + +int +main(int argc, char **argv) +{ + volatile struct entry *e; + unsigned i, stride; + + stride = DEFAULT; + if (argc == 2) { + stride = atoi(argv[1]); + } + if (stride <= 0 || argc > 2) { + printf("Usage: ctest [stridesize]\n"); + printf(" stridesize should not be a multiple of 2.\n"); + return 1; + } + + printf("Starting ctest: stride %d\n", stride); + + /* + * Generate a huge linked list, with each entry pointing to + * the slot STRIDE entries above it. As long as STRIDE and SIZE + * are relatively prime, this will put all the entries on one + * list. Otherwise you will get multiple disjoint lists. (All + * these lists will be circular.) + */ + for (i=0; ie; + } + + printf("\nDone!\n"); + return 0; +} diff --git a/userland/testbin/dirconc/Makefile b/userland/testbin/dirconc/Makefile new file mode 100644 index 0000000..0937cd8 --- /dev/null +++ b/userland/testbin/dirconc/Makefile @@ -0,0 +1,11 @@ +# Makefile for dirconc + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=dirconc +SRCS=dirconc.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/dirconc/dirconc.c b/userland/testbin/dirconc/dirconc.c new file mode 100644 index 0000000..c388006 --- /dev/null +++ b/userland/testbin/dirconc/dirconc.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Concurrent directory operations test. + * + * Your system should survive this (without leaving a corrupted file + * system behind) once the file system assignment is complete. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NTRIES 100 /* loop count */ +#define NPROCS 5 /* actually totals 4x this +1 processes */ + +#define TESTDIR "dirconc" +#define NNAMES 4 +#define NAMESIZE 32 + +//////////////////////////////////////////////////////////// + +static const char *const names[NNAMES] = { + "aaaa", + "bbbb", + "cccc", + "dddd", +}; + +static +void +choose_name(char *buf, size_t len) +{ + const char *a, *b, *c; + + a = names[random()%NNAMES]; + if (random()%2==0) { + snprintf(buf, len, "%s", a); + return; + } + b = names[random()%NNAMES]; + if (random()%2==0) { + snprintf(buf, len, "%s/%s", a, b); + return; + } + c = names[random()%NNAMES]; + snprintf(buf, len, "%s/%s/%s", a, b, c); +} + +//////////////////////////////////////////////////////////// + +/* + * The purpose of this is to be atomic. In our world, straight + * printf tends not to be. + */ +static +void +#ifdef __GNUC__ + __attribute__((__format__(__printf__, 1, 2))) +#endif +say(const char *fmt, ...) +{ + char buf[512]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + write(STDOUT_FILENO, buf, strlen(buf)); +} + +//////////////////////////////////////////////////////////// + +static +void +dorename(const char *name1, const char *name2) +{ + if (rename(name1, name2) < 0) { + switch (errno) { + case ENOENT: + case ENOTEMPTY: + case EINVAL: + break; + default: + say("pid %d: rename %s -> %s: %s\n", + getpid(), name1, name2, strerror(errno)); + break; + } + } +} + +static +void +domkdir(const char *name) +{ + if (mkdir(name, 0775)<0) { + switch (errno) { + case ENOENT: + case EEXIST: + break; + default: + say("pid %d: mkdir %s: %s\n", + getpid(), name, strerror(errno)); + break; + } + } +} + +static +void +dormdir(const char *name) +{ + if (rmdir(name)<0) { + switch (errno) { + case ENOENT: + case ENOTEMPTY: + break; + default: + say("pid %d: rmdir %s: %s\n", + getpid(), name, strerror(errno)); + break; + } + } +} + +static +void +cleanup_rmdir(const char *name) +{ + if (rmdir(name)<0) { + switch (errno) { + case ENOENT: + break; + default: + say("cleanup (pid %d): rmdir %s: %s\n", + getpid(), name, strerror(errno)); + break; + } + } +} + +//////////////////////////////////////////////////////////// + +static +void +rename_proc(void) +{ + char name1[NAMESIZE], name2[NAMESIZE]; + int ct; + + for (ct=0; ct %s\n", (int)getpid(), name1, name2); + dorename(name1, name2); + } +} + +static +void +mkdir_proc(void) +{ + char name[NAMESIZE]; + int ct; + + for (ct=0; ct=0) { + wp = waitpid(pids[i], &status, 0); + if (wp<0) { + say("waitpid %d: %s\n", (int) pids[i], + strerror(errno)); + } + else if (WIFSIGNALED(status)) { + say("pid %d: signal %d\n", (int) pids[i], + WTERMSIG(status)); + } + else if (WIFEXITED(status) && WEXITSTATUS(status)!=0) { + say("pid %d: exit %d\n", (int) pids[i], + WEXITSTATUS(status)); + } + } + } +} + +//////////////////////////////////////////////////////////// + +static +void +setup(const char *fs) +{ + if (chdir(fs)<0) { + say("chdir: %s: %s\n", fs, strerror(errno)); + exit(1); + } + if (mkdir(TESTDIR, 0775)<0) { + say("mkdir: %s: %s\n", TESTDIR, strerror(errno)); + exit(1); + } + if (chdir(TESTDIR)<0) { + say("chdir: %s: %s\n", TESTDIR, strerror(errno)); + exit(1); + } +} + +static +void +recursive_cleanup(const char *sofar, int depth) +{ + char buf[NAMESIZE*32]; + int i; + + for (i=0; i +#include +#include +#include +#include +#include +#include + +#define TESTDIR "seektestdir" + +static struct { + const char *name; + int make_it; + off_t pos; +} testfiles[] = { + { ".", 0, -1 }, + { "..", 0, -1 }, + { "ridcully", 1, -1 }, + { "weatherwax", 1, -1 }, + { "ogg", 1, -1 }, + { "vorbis", 1, -1 }, + { "verence", 1, -1 }, + { "magrat", 1, -1 }, + { "agnes", 1, -1 }, + { "rincewind", 1, -1 }, + { "angua", 1, -1 }, + { "cherry", 1, -1 }, + { "dorfl", 1, -1 }, + { "nobby", 1, -1 }, + { "carrot", 1, -1 }, + { "vimes", 1, -1 }, + { "detritus", 1, -1 }, + { "twoflower", 1, -1 }, + { "teatime", 1, -1 }, + { "qu", 1, -1 }, + { NULL, 0, 0 } +}; + +/************************************************************/ +/* Test code */ +/************************************************************/ + +static int dirfd; + +static +int +findentry(const char *name) +{ + int i; + + for (i=0; testfiles[i].name; i++) { + if (!strcmp(testfiles[i].name, name)) { + return i; + } + } + return -1; +} + +static +void +openit(void) +{ + dirfd = open(".", O_RDONLY); + if (dirfd < 0) { + err(1, ".: open"); + } +} + +static +void +closeit(void) +{ + if (close(dirfd)<0) { + err(1, ".: close"); + } + dirfd = -1; +} + +static +void +readit(void) +{ + char buf[4096]; + off_t pos; + int len; + int n, i, ix; + + for (i=0; testfiles[i].name; i++) { + testfiles[i].pos = -1; + } + + pos = lseek(dirfd, 0, SEEK_CUR); + if (pos < 0) { + err(1, ".: lseek(0, SEEK_CUR)"); + } + n = 0; + + while ((len = getdirentry(dirfd, buf, sizeof(buf)-1)) > 0) { + + if ((unsigned)len >= sizeof(buf)-1) { + errx(1, ".: entry %d: getdirentry returned " + "invalid length %d", n, len); + } + buf[len] = 0; + ix = findentry(buf); + if (ix < 0) { + errx(1, ".: entry %d: getdirentry returned " + "unexpected name %s", n, buf); + } + + if (testfiles[ix].pos >= 0) { + errx(1, ".: entry %d: getdirentry returned " + "%s a second time", n, buf); + } + + testfiles[ix].pos = pos; + + pos = lseek(dirfd, 0, SEEK_CUR); + if (pos < 0) { + err(1, ".: lseek(0, SEEK_CUR)"); + } + n++; + } + if (len<0) { + err(1, ".: entry %d: getdirentry", n); + } + + for (i=0; testfiles[i].name; i++) { + if (testfiles[i].pos < 0) { + errx(1, ".: getdirentry failed to return %s", + testfiles[i].name); + } + } + if (i!=n) { + /* + * If all of the other checks have passed, this should not + * be able to fail. But... just in case I forgot something + * or there's a bug... + */ + + errx(1, ".: getdirentry returned %d names, not %d (huh...?)", + n, i); + } +} + +static +void +firstread(void) +{ + off_t pos; + + pos = lseek(dirfd, 0, SEEK_CUR); + if (pos < 0) { + err(1, ".: lseek(0, SEEK_CUR)"); + } + if (pos != 0) { + errx(1, ".: File position after open not 0"); + } + + printf("Scanning directory...\n"); + + readit(); +} + +static +void +doreadat0(void) +{ + off_t pos; + + printf("Rewinding directory and reading it again...\n"); + + pos = lseek(dirfd, 0, SEEK_SET); + if (pos < 0) { + err(1, ".: lseek(0, SEEK_SET)"); + } + if (pos != 0) { + errx(1, ".: lseek(0, SEEK_SET) returned %ld", (long) pos); + } + + readit(); +} + +static +void +readone(const char *shouldbe) +{ + char buf[4096]; + int len; + + len = getdirentry(dirfd, buf, sizeof(buf)-1); + if (len < 0) { + err(1, ".: getdirentry"); + } + if ((unsigned)len >= sizeof(buf)-1) { + errx(1, ".: getdirentry returned invalid length %d", len); + } + buf[len] = 0; + + if (strcmp(buf, shouldbe)) { + errx(1, ".: getdirentry returned %s (expected %s)", + buf, shouldbe); + } +} + +static +void +doreadone(int which) +{ + off_t pos; + pos = lseek(dirfd, testfiles[which].pos, SEEK_SET); + if (pos<0) { + err(1, ".: lseek(%ld, SEEK_SET)", (long) testfiles[which].pos); + } + if (pos != testfiles[which].pos) { + errx(1, ".: lseek(%ld, SEEK_SET) returned %ld", + (long) testfiles[which].pos, (long) pos); + } + + readone(testfiles[which].name); +} + +static +void +readallonebyone(void) +{ + int i; + + printf("Trying to read each entry again...\n"); + for (i=0; testfiles[i].name; i++) { + doreadone(i); + } +} + +static +void +readallrandomly(void) +{ + int n, i, x; + + printf("Trying to read a bunch of entries randomly...\n"); + + for (i=0; testfiles[i].name; i++); + n = i; + + srandom(39584); + for (i=0; i<512; i++) { + x = (int)(random()%n); + doreadone(x); + } +} + +static +void +readateof(void) +{ + char buf[4096]; + int len; + + len = getdirentry(dirfd, buf, sizeof(buf)-1); + if (len < 0) { + err(1, ".: at EOF: getdirentry"); + } + if (len==0) { + return; + } + if ((unsigned)len >= sizeof(buf)-1) { + errx(1, ".: at EOF: getdirentry returned " + "invalid length %d", len); + } + buf[len] = 0; + errx(1, ".: at EOF: got unexpected name %s", buf); +} + +static +void +doreadateof(void) +{ + off_t pos; + int i; + + printf("Trying to read after going to EOF...\n"); + + pos = lseek(dirfd, 0, SEEK_END); + if (pos<0) { + err(1, ".: lseek(0, SEEK_END)"); + } + + for (i=0; testfiles[i].name; i++) { + if (pos <= testfiles[i].pos) { + errx(1, ".: EOF position %ld below position %ld of %s", + pos, testfiles[i].pos, testfiles[i].name); + } + } + + readateof(); +} + +static +void +inval_read(void) +{ + char buf[4096]; + int len; + + len = getdirentry(dirfd, buf, sizeof(buf)-1); + + /* Any result is ok, as long as the system doesn't crash */ + (void)len; +} + +static +void +dobadreads(void) +{ + off_t pos, pos2, eof; + int valid, i, k=0; + + printf("Trying some possibly invalid reads...\n"); + + eof = lseek(dirfd, 0, SEEK_END); + if (eof < 0) { + err(1, ".: lseek(0, SEEK_END)"); + } + + for (pos=0; pos < eof; pos++) { + valid = 0; + for (i=0; testfiles[i].name; i++) { + if (pos==testfiles[i].pos) { + valid = 1; + } + } + if (valid) { + /* don't try offsets that are known to be valid */ + continue; + } + + pos2 = lseek(dirfd, pos, SEEK_SET); + if (pos2 < 0) { + /* this is ok */ + } + else { + inval_read(); + k++; + } + } + + if (k>0) { + printf("Survived %d invalid reads...\n", k); + } + else { + printf("Couldn't find any invalid offsets to try...\n"); + } + + printf("Trying to read beyond EOF...\n"); + pos2 = lseek(dirfd, eof + 1000, SEEK_SET); + if (pos2 < 0) { + /* this is ok */ + } + else { + inval_read(); + } +} + +static +void +dotest(void) +{ + printf("Opening directory...\n"); + openit(); + + printf("Running tests...\n"); + + /* read the whole directory */ + firstread(); + + /* make sure eof behaves right */ + readateof(); + + /* read all the filenames again by seeking */ + readallonebyone(); + + /* try reading at eof */ + doreadateof(); + + /* read a bunch of the filenames over and over again */ + readallrandomly(); + + /* rewind and read the whole thing again, to make sure that works */ + doreadat0(); + + /* do invalid reads */ + dobadreads(); + + /* rewind again to make sure the invalid attempts didn't break it */ + doreadat0(); + + printf("Closing directory...\n"); + closeit(); +} + +/************************************************************/ +/* Setup code */ +/************************************************************/ + +static +void +mkfile(const char *name) +{ + int fd, i, r; + static const char message[] = "The turtle moves!\n"; + char buf[32*sizeof(message)+1]; + + buf[0]=0; + for (i=0; i<32; i++) { + strcat(buf, message); + } + + /* Use O_EXCL, because we know the file shouldn't already be there */ + fd = open(name, O_WRONLY|O_CREAT|O_EXCL, 0664); + if (fd<0) { + err(1, "%s: create", name); + } + + r = write(fd, buf, strlen(buf)); + if (r<0) { + err(1, "%s: write", name); + } + if ((unsigned)r != strlen(buf)) { + errx(1, "%s: short write (%d bytes)", name, r); + } + + if (close(fd)<0) { + err(1, "%s: close", name); + } +} + +static +void +setup(void) +{ + int i; + + printf("Making directory %s...\n", TESTDIR); + + /* Create a directory */ + if (mkdir(TESTDIR, 0775)<0) { + err(1, "%s: mkdir", TESTDIR); + } + + /* Switch to it */ + if (chdir(TESTDIR)<0) { + err(1, "%s: chdir", TESTDIR); + } + + printf("Making some files...\n"); + + /* Populate it */ + for (i=0; testfiles[i].name; i++) { + if (testfiles[i].make_it) { + mkfile(testfiles[i].name); + } + testfiles[i].pos = -1; + } +} + +static +void +cleanup(void) +{ + int i; + + printf("Cleaning up...\n"); + + /* Remove the files */ + for (i=0; testfiles[i].name; i++) { + if (testfiles[i].make_it) { + if (remove(testfiles[i].name)<0) { + err(1, "%s: remove", testfiles[i].name); + } + } + } + + /* Leave the dir */ + if (chdir("..")<0) { + err(1, "..: chdir"); + } + + /* Remove the dir */ + if (rmdir(TESTDIR)<0) { + err(1, "%s: rmdir", TESTDIR); + } +} + + +int +main(void) +{ + setup(); + + /* Do the whole thing twice */ + dotest(); + dotest(); + + cleanup(); + return 0; +} diff --git a/userland/testbin/dirtest/Makefile b/userland/testbin/dirtest/Makefile new file mode 100644 index 0000000..0b63a49 --- /dev/null +++ b/userland/testbin/dirtest/Makefile @@ -0,0 +1,11 @@ +# Makefile for dirtest + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=dirtest +SRCS=dirtest.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/dirtest/dirtest.c b/userland/testbin/dirtest/dirtest.c new file mode 100644 index 0000000..692506d --- /dev/null +++ b/userland/testbin/dirtest/dirtest.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * dirtest.c + * + * Tests your hierarchical directory implementation by creating + * and deleting directories. + * + * Works in the current directory. + * + * Intended for the file system assignment. Should run (on SFS) + * when that assignment is complete. + */ + +#include +#include +#include +#include +#include +#include + +#define MAXLEVELS 5 + +int +main(void) +{ + int i; + const char *onename = "testdir"; + char dirname[512]; + + strcpy(dirname, onename); + + for (i=0; i +#include +#include +#include "f_hdr.h" + +static char buffer[SectorSize + 1]; + +static +void +check_buffer(void) +{ + int i; + char ch = buffer[0]; + + for (i = 1; i < SectorSize + 1; i++) { + if (buffer[i] != ch) { + errx(1, "Read error: %s", buffer); + } + } + + putchar(ch); +} + +void +subproc_read(void) +{ + int fd; + int i, res; + + printf("File Reader starting ...\n\n"); + + fd = open(FNAME, O_RDONLY); + if (fd < 0) { + err(1, "%s: open", FNAME); + } + + for (i=0; i +#include +#include +#include +#include +#include +#include "f_hdr.h" + +#define SECTOR_SIZE 512 + + +#define BUFFER_SIZE (2 * SECTOR_SIZE + 1) +#define BIGFILE_SIZE (270 * BUFFER_SIZE) +#define BIGFILE_NAME "large-f" + +#define LETTER(x) ('a' + (x % 31)) + +char fbuffer[BUFFER_SIZE]; +char ibuffer[32]; + + +#define DIR_DEPTH 8 +#define DIR_NAME "/t" +#define DIRFILE_NAME "a" + + +#define FNAME "f-testfile" +#define TMULT 50 +#define FSIZE ((SECTOR_SIZE + 1) * TMULT) + +#define READCHAR 'r' +#define WRITECHAR 'w' + +char cbuffer[SECTOR_SIZE + 1]; + + +/* =================================================== + + */ + +static +pid_t +forkoff(void (*func)(void)) +{ + pid_t pid = fork(); + switch (pid) { + case -1: + warn("fork"); + return -1; + case 0: + func(); + _exit(0); + default: break; + } + return pid; +} + +static +void +dowait(int pid) +{ + int status; + + if (waitpid(pid, &status, 0)<0) { + warn("waitpid for %d", pid); + } + else if (WIFSIGNALED(status)) { + warnx("pid %d: signal %d", pid, WTERMSIG(status)); + } + else if (WEXITSTATUS(status) != 0) { + warnx("pid %d: exit %d", pid, WEXITSTATUS(status)); + } +} + +/* =================================================== + + */ + +static +void +big_file(int size) +{ + int i, j, fileid; + + printf("[BIGFILE] test starting :\n"); + printf("\tCreating a file of size: %d\n", size); + + fileid = open(BIGFILE_NAME, O_WRONLY|O_CREAT|O_TRUNC, 0664); + if (fileid < 0) { + err(1, "[BIGFILE]: %s: open for write", BIGFILE_NAME); + } + + for(i = 0; i < BUFFER_SIZE; i++) { + fbuffer[i] = LETTER(i); + } + + printf("\tWriting to file.\n"); + for (i = 0; i < size; i += BUFFER_SIZE) { + write(fileid, fbuffer, BUFFER_SIZE); + + if (!(i % (10 * BUFFER_SIZE))) { + printf("\rBW : %d", i); + } + } + + printf("\n\tReading from file.\n"); + close(fileid); + + fileid = open(BIGFILE_NAME, O_RDONLY); + if (fileid < 0) { + err(1, "[BIGFILE]: %s: open for read", BIGFILE_NAME); + } + + for (i = 0; i < size; i += BUFFER_SIZE) { + j = read(fileid, fbuffer, BUFFER_SIZE); + if (j<0) { + err(1, "[BIGFILE]: read"); + } + if (j != BUFFER_SIZE) { + errx(1, "[BIGFILE]: read: only %d bytes", j); + } + } + + if (!(i % (10 * BUFFER_SIZE))) { + printf("\rBR : %d", i); + } + + /* Check to see that the data is consistent : */ + for (j = 0; j < BUFFER_SIZE; j++) { + if (fbuffer[j] != LETTER(j)) { + errx(1, "[BIGFILE] : Failed read check : " + "inconsistent data read: %d", i+j); + } + } + + + close(fileid); + if (remove(BIGFILE_NAME)) { + err(1, "[BIGFILE]: %s: remove", BIGFILE_NAME); + } + + printf("\n[BIGFILE] : Success!\n"); +} + +/* =================================================== + + */ + +static +void +concur(void) +{ + int i, fd; + int r1, r2, w1; + + printf("Spawning 2 readers, 1 writer.\n"); + + + fd = open(FNAME, O_WRONLY|O_CREAT|O_TRUNC, 0664); + if (fd < 0) { + err(1, "[CONCUR]: %s: open", FNAME); + } + + printf("Initializing test file: "); + + for (i = 0; i < SECTOR_SIZE + 1; i++) { + cbuffer[i] = READCHAR; + } + + for (i = 0; i < TMULT; i++) { + write(fd, cbuffer, SECTOR_SIZE + 1); + } + + + close(fd); + + printf("Done initializing. Starting processes...\n"); + + r1 = forkoff(subproc_read); + w1 = forkoff(subproc_write); + r2 = forkoff(subproc_read); + + printf("Waiting for processes.\n"); + + dowait(r1); + dowait(r2); + dowait(w1); + + if (remove(FNAME)) { + err(1, "[CONCUR]: %s: remove", FNAME); + } + + printf("[CONCUR] Done!\n"); +} + +/* =================================================== + + */ + +static +void +dir_test(int depth) +{ + int i, fd; + char tmp[] = DIR_NAME; + char fmp[] = DIRFILE_NAME; + char dirname[64]; + + strcpy(dirname, "."); + + for (i = 0; i < depth; i++) { + strcat(dirname, tmp); + + printf("\tCreating dir : %s\n", dirname); + + if (mkdir(dirname, 0775) < 0) { + err(1, "[DIRTEST]: %s: mkdir", dirname); + } + + strcat(dirname, fmp); + printf("\tCreating file: %s\n", dirname); + + fd = open(dirname, O_WRONLY|O_CREAT|O_TRUNC, 0664); + if (fd<0) { + err(1, "[DIRTEST]: %s: open", dirname); + } + + dirname[strlen(dirname) - strlen(fmp)] = '\0'; + } + + printf("[DIRTEST] : Passed directory creation test.\n"); + + for (i = 0; i < depth; i++) { + strcat(dirname, fmp); + + printf("\tDeleting file: %s\n", dirname); + + if (remove(dirname)) { + err(1, "[DIRTEST]: %s: remove", dirname); + } + + dirname[strlen(dirname) - strlen(fmp)] = '\0'; + printf("\tRemoving dir : %s\n", dirname); + + if (rmdir(dirname)) { + err(1, "[DIRTEST]: %s: rmdir", dirname); + } + + dirname[strlen(dirname) - strlen(tmp)] = '\0'; + } + + printf("[DIRTEST] : Passed directory removal test.\n"); + printf("[DIRTEST] : Success!\n"); +} + +/* =================================================== + + */ + +#define RUNBIGFILE 0x1 +#define RUNDIRTEST 0x2 +#define RUNCONCUR 0x4 +#define RUNTHEMALL (RUNBIGFILE | RUNDIRTEST | RUNCONCUR) + +int +main(int argc, char * argv[]) +{ + int tv = 0; + + if (argc > 1) { + if (*argv[1]=='1') { + tv = RUNBIGFILE; + } + else if (*argv[1]=='2') { + tv = RUNDIRTEST; + } + else if (*argv[1]=='3') { + tv = RUNCONCUR; + } + } + else { + tv = RUNTHEMALL; + } + + if (tv & RUNBIGFILE) { + printf("[BIGFILE] : Run #1\n"); + big_file(BIGFILE_SIZE); + printf("[BIGFILE] : Run #2\n"); + big_file(BIGFILE_SIZE); + } + + if (tv & RUNDIRTEST) { + printf("[DIRTEST] : Run #1\n"); + dir_test(DIR_DEPTH); + printf("[DIRTEST] : Run #2\n"); + dir_test(DIR_DEPTH); + } + + if (tv & RUNCONCUR) { + printf("[CONCUR]\n"); + concur(); + } + return 0; +} + + diff --git a/userland/testbin/f_test/f_write.c b/userland/testbin/f_test/f_write.c new file mode 100644 index 0000000..8a466d8 --- /dev/null +++ b/userland/testbin/f_test/f_write.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * f_write.c + * + * This used to be a separate binary, because it came from Nachos + * and nachos didn't support fork(). However, in OS/161 there's + * no reason to make it a separate binary; doing so just makes + * the test flaky. + * + * + * It will start writing into a file, concurrently with + * one or more instances of f_read. + * + */ + +#define SectorSize 512 + +#define TMULT 50 +#define FSIZE ((SectorSize + 1) * TMULT) + +#define FNAME "f-testfile" +#define READCHAR 'r' +#define WRITECHAR 'w' + +#include +#include +#include +#include "f_hdr.h" + +static char buffer[SectorSize + 1]; + +void +subproc_write(void) +{ + int fd; + int i; + + for (i=0; i < SectorSize + 1; i++) { + buffer[i] = WRITECHAR; + } + + printf("File Writer starting ...\n"); + + fd = open(FNAME, O_WRONLY); + if (fd < 0) { + err(1, "%s: open", FNAME); + } + + for (i=0; i +#include +#include +#include +#include + +#define _PATH_SELF "/testbin/factorial" + +/* + * factorial - compute factorials by recursive exec + * + * External usage: factorial N + * (compute N!) + * + * Internal usage: factoral N M + * (compute N! * M) + */ + +//////////////////////////////////////////////////////////// +// arithmetic + +/* + * We compute using binary-coded decimal integers where + * each byte contains the digit characters '0' through '9'. + * This is not exactly optimum for computation but it's + * perfect for sending numbers through execv. + */ + +#define NUMSIZE 8191 +struct number { + char buf[NUMSIZE+1]; /* includes space for a null-terminator */ + size_t first; /* first valid digit */ +}; + +static struct number scratch; + +static +void +number_init(struct number *n, const char *txt) +{ + size_t len, i; + + len = strlen(txt); + if (len > NUMSIZE) { + warnx("%s", txt); + errx(1, "Number too large"); + } + n->first = NUMSIZE - len; + strcpy(n->buf + n->first, txt); +#if 0 + for (i=0; ifirst; i++) { + n->buf[i] = '0'; + } +#endif + for (i=n->first; ibuf[i] < '0' || n->buf[i] > '9') { + warnx("%s", txt); + errx(1, "Number contained non-digit characters"); + } + } + assert(n->buf[NUMSIZE] == 0); + while (n->first < NUMSIZE && n->buf[n->first] == '0') { + n->first++; + } +} + +static +char * +number_get(struct number *n) +{ + size_t pos; + + pos = n->first; + while (pos < NUMSIZE && n->buf[pos] == '0') { + pos++; + } + if (pos == NUMSIZE) { + pos--; + n->buf[pos] = '0'; + } + return &n->buf[pos]; +} + +static +void +finishcarry(struct number *r, const struct number *b, size_t pos, + unsigned carry) +{ + if (carry > 0 && b->first == 0) { + /* if b->first is 0, pos may now be 2^32-1 */ + errx(1, "Overflow"); + } + while (carry > 0) { + if (pos == 0) { + errx(1, "Overflow"); + } + r->buf[pos--] = carry % 10 + '0'; + carry = carry / 10; + } + r->first = pos + 1; +} + +static +void +pluseq(struct number *r, const struct number *b) +{ + size_t pos; + unsigned an, bn, rn, carry; + + carry = 0; + for (pos = NUMSIZE; pos-- > b->first; ) { + an = pos < r->first ? 0 : r->buf[pos] - '0'; + bn = b->buf[pos] - '0'; + rn = an + bn + carry; + r->buf[pos] = rn % 10 + '0'; + carry = rn / 10; + } + finishcarry(r, b, pos, carry); +} + +static +void +dec(struct number *r) +{ + size_t pos; + + for (pos = NUMSIZE; pos-- > r->first; ) { + if (r->buf[pos] == '0') { + r->buf[pos] = '9'; + } + else { + r->buf[pos]--; + return; + } + } + /* This should really not happen. */ + errx(1, "Underflow"); +} + +static +void +multc(struct number *r, const struct number *a, unsigned bn, size_t offset) +{ + size_t pos; + unsigned an, rn, carry; + + for (pos = NUMSIZE; pos-- > NUMSIZE - offset; ) { + r->buf[pos] = '0'; + } + carry = 0; + for (pos = NUMSIZE; pos-- > a->first; ) { + an = a->buf[pos] - '0'; + rn = an * bn + carry; + if (pos < offset) { + errx(1, "Overflow"); + } + r->buf[pos - offset] = rn % 10 + '0'; + carry = rn / 10; + } + if (carry > 0 && pos < offset) { + errx(1, "Overflow"); + } + finishcarry(r, a, pos - offset, carry); +} + +static +void +mult(struct number *r, const struct number *a, const struct number *b) +{ + unsigned offset; + size_t apos; + + /* B should normally be the larger number */ + if (a->first < b->first) { + mult(r, b, a); + return; + } + + number_init(&scratch, "0"); + offset = 0; + for (apos = NUMSIZE; apos-- > a->first; ) { + multc(&scratch, b, a->buf[apos] - '0', offset); + pluseq(r, &scratch); + offset++; + } +} + +//////////////////////////////////////////////////////////// +// argv logic + +static +void +self(const char *arg1, const char *arg2) +{ + const char *args[4]; + + args[0] = _PATH_SELF; + args[1] = arg1; + args[2] = arg2; + args[3] = NULL; + execv(_PATH_SELF, (char **)args); + err(1, "execv"); +} + +static struct number n1, n2, multbuf; + +int +main(int argc, char *argv[]) +{ + if (argc == 0) { + /* Assume we've just been run from the menu. */ + self("404", "1"); + } + else if (argc == 2) { + self(argv[1], "1"); + } + else if (argc == 3) { + if (!strcmp(argv[1], "1") || !strcmp(argv[1], "0")) { + printf("%s\n", argv[2]); + } + else { + number_init(&n1, argv[1]); + number_init(&n2, argv[2]); + number_init(&multbuf, "0"); + mult(&multbuf, &n1, &n2); + dec(&n1); + self(number_get(&n1), number_get(&multbuf)); + } + } + else { + warnx("Usage: factorial N"); + } + return 0; +} diff --git a/userland/testbin/farm/Makefile b/userland/testbin/farm/Makefile new file mode 100644 index 0000000..a8ac3eb --- /dev/null +++ b/userland/testbin/farm/Makefile @@ -0,0 +1,11 @@ +# Makefile for farm + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=farm +SRCS=farm.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/farm/farm.c b/userland/testbin/farm/farm.c new file mode 100644 index 0000000..e28d820 --- /dev/null +++ b/userland/testbin/farm/farm.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * farm.c + * + * Run a bunch of cpu pigs and one cat. + * The file it cats is "catfile". This should be created in advance. + * + * This test should itself run correctly when the basic system calls + * are complete. It may be helpful for scheduler performance analysis. + */ + +#include +#include + +static char *hargv[2] = { (char *)"hog", NULL }; +static char *cargv[3] = { (char *)"cat", (char *)"catfile", NULL }; + +#define MAXPROCS 6 +static int pids[MAXPROCS], npids; + +static +void +spawnv(const char *prog, char **argv) +{ + int pid = fork(); + switch (pid) { + case -1: + err(1, "fork"); + case 0: + /* child */ + execv(prog, argv); + err(1, "%s", prog); + default: + /* parent */ + pids[npids++] = pid; + break; + } +} + +static +void +waitall(void) +{ + int i, status; + for (i=0; i + +#define REALLY_BIG_ADDRESS 0x40000000 + +int +main(void) +{ + volatile int i; + + printf("\nEntering the faulter program - I should die immediately\n"); + i = *(int *)REALLY_BIG_ADDRESS; + + // gcc 4.8 improperly demands this + (void)i; + + printf("I didn't get killed! Program has a bug\n"); + return 0; +} diff --git a/userland/testbin/filetest/Makefile b/userland/testbin/filetest/Makefile new file mode 100644 index 0000000..e1f7974 --- /dev/null +++ b/userland/testbin/filetest/Makefile @@ -0,0 +1,11 @@ +# Makefile for filetest + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=filetest +SRCS=filetest.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/filetest/filetest.c b/userland/testbin/filetest/filetest.c new file mode 100644 index 0000000..dc062ec --- /dev/null +++ b/userland/testbin/filetest/filetest.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * filetest.c + * + * Tests the filesystem by opening, writing to and reading from a + * user specified file. + * + * This should run (on SFS) even before the file system assignment is started. + * It should also continue to work once said assignment is complete. + * It will not run fully on emufs, because emufs does not support remove(). + */ + +#include +#include +#include +#include + +int +main(int argc, char *argv[]) +{ + static char writebuf[41] = "Twiddle dee dee, Twiddle dum dum.......\n"; + static char readbuf[41]; + + const char *file; + int fd, rv; + + if (argc == 0) { + warnx("No arguments - running on \"testfile\""); + file = "testfile"; + } + else if (argc == 2) { + file = argv[1]; + } + else { + errx(1, "Usage: filetest "); + } + + fd = open(file, O_WRONLY|O_CREAT|O_TRUNC, 0664); + if (fd<0) { + err(1, "%s: open for write", file); + } + + + rv = write(fd, writebuf, 40); + if (rv<0) { + err(1, "%s: write", file); + } + + rv = close(fd); + if (rv<0) { + err(1, "%s: close (1st time)", file); + } + + fd = open(file, O_RDONLY); + if (fd<0) { + err(1, "%s: open for read", file); + } + + rv = read(fd, readbuf, 40); + if (rv<0) { + err(1, "%s: read", file); + } + rv = close(fd); + if (rv<0) { + err(1, "%s: close (2nd time)", file); + } + /* ensure null termination */ + readbuf[40] = 0; + + if (strcmp(readbuf, writebuf)) { + errx(1, "Buffer data mismatch!"); + } + + rv = remove(file); + if (rv<0) { + err(1, "%s: remove", file); + } + printf("Passed filetest.\n"); + return 0; +} diff --git a/userland/testbin/forkbomb/Makefile b/userland/testbin/forkbomb/Makefile new file mode 100644 index 0000000..e4d240a --- /dev/null +++ b/userland/testbin/forkbomb/Makefile @@ -0,0 +1,11 @@ +# Makefile for forkbomb + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=forkbomb +SRCS=forkbomb.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/forkbomb/forkbomb.c b/userland/testbin/forkbomb/forkbomb.c new file mode 100644 index 0000000..6db265b --- /dev/null +++ b/userland/testbin/forkbomb/forkbomb.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * forkbomb - apply malthus to an operating system ;-) + * + * DO NOT RUN THIS ON A REAL SYSTEM - IT WILL GRIND TO A HALT AND + * PEOPLE WILL COME AFTER YOU WIELDING BASEBALL BATS OR THE AD + * BOARD(*). WE WARNED YOU. + * + * We don't expect your system to withstand this without grinding to + * a halt, but once your basic system calls are complete it shouldn't + * crash. Likewise for after your virtual memory system is complete. + * + * (...at least in an ideal world. However, it can be difficult to + * handle all the loose ends involved. Heroic measures are not + * expected. If in doubt, talk to the course staff.) + * + * + * (*) The Administrative Board of Harvard College handles formal + * disciplinary action. + */ + +#include +#include + +static volatile int pid; + +int +main(void) +{ + int i; + + while (1) { + fork(); + + pid = getpid(); + + /* Make sure each fork has its own address space. */ + for (i=0; i<300; i++) { + volatile int seenpid; + seenpid = pid; + if (seenpid != getpid()) { + errx(1, "pid mismatch (%d, should be %d) " + "- your vm is broken!", + seenpid, getpid()); + } + } + } +} diff --git a/userland/testbin/forktest/Makefile b/userland/testbin/forktest/Makefile new file mode 100644 index 0000000..8642031 --- /dev/null +++ b/userland/testbin/forktest/Makefile @@ -0,0 +1,11 @@ +# Makefile for forktest + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=forktest +SRCS=forktest.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/forktest/forktest.c b/userland/testbin/forktest/forktest.c new file mode 100644 index 0000000..46e5da2 --- /dev/null +++ b/userland/testbin/forktest/forktest.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * forktest - test fork(). + * + * This should work correctly when fork is implemented. + * + * It should also continue to work after subsequent assignments, most + * notably after implementing the virtual memory system. + */ + +#include +#include +#include +#include +#include + +/* + * This is used by all processes, to try to help make sure all + * processes have a distinct address space. + */ +static volatile int mypid; + +/* + * Helper function for fork that prints a warning on error. + */ +static +int +dofork(void) +{ + int pid; + pid = fork(); + if (pid < 0) { + warn("fork"); + } + return pid; +} + +/* + * Check to make sure each process has its own address space. Write + * the pid into the data segment and read it back repeatedly, making + * sure it's correct every time. + */ +static +void +check(void) +{ + int i; + + mypid = getpid(); + + /* Make sure each fork has its own address space. */ + for (i=0; i<800; i++) { + volatile int seenpid; + seenpid = mypid; + if (seenpid != getpid()) { + errx(1, "pid mismatch (%d, should be %d) " + "- your vm is broken!", + seenpid, getpid()); + } + } +} + +/* + * Wait for a child process. + * + * This assumes dowait is called the same number of times as dofork + * and passed its results in reverse order. Any forks that fail send + * us -1 and are ignored. The first 0 we see indicates the fork that + * generated the current process; that means it's time to exit. Only + * the parent of all the processes returns from the chain of dowaits. + */ +static +void +dowait(int nowait, int pid) +{ + int x; + + if (pid<0) { + /* fork in question failed; just return */ + return; + } + if (pid==0) { + /* in the fork in question we were the child; exit */ + exit(0); + } + + if (!nowait) { + if (waitpid(pid, &x, 0)<0) { + warn("waitpid"); + } + else if (WIFSIGNALED(x)) { + warnx("pid %d: signal %d", pid, WTERMSIG(x)); + } + else if (WEXITSTATUS(x) != 0) { + warnx("pid %d: exit %d", pid, WEXITSTATUS(x)); + } + } +} + +/* + * Actually run the test. + */ +static +void +test(int nowait) +{ + int pid0, pid1, pid2, pid3; + int depth = 0; + + /* + * Caution: This generates processes geometrically. + * + * It is unrolled to encourage gcc to registerize the pids, + * to prevent wait/exit problems if fork corrupts memory. + * + * Note: if the depth prints trigger and show that the depth + * is too small, the most likely explanation is that the fork + * child is returning from the write() inside putchar() + * instead of from fork() and thus skipping the depth++. This + * is a fairly common problem caused by races in the kernel + * fork code. + */ + + pid0 = dofork(); + depth++; + putchar('A'); + if (depth != 1) { + warnx("depth %d, should be 1", depth); + } + check(); + + pid1 = dofork(); + depth++; + putchar('B'); + if (depth != 2) { + warnx("depth %d, should be 2", depth); + } + check(); + + pid2 = dofork(); + depth++; + putchar('C'); + if (depth != 3) { + warnx("depth %d, should be 3", depth); + } + check(); + + pid3 = dofork(); + depth++; + putchar('D'); + if (depth != 4) { + warnx("depth %d, should be 4", depth); + } + check(); + + /* + * These must be called in reverse order to avoid waiting + * improperly. + */ + dowait(nowait, pid3); + dowait(nowait, pid2); + dowait(nowait, pid1); + dowait(nowait, pid0); + + putchar('\n'); +} + +int +main(int argc, char *argv[]) +{ + static const char expected[] = + "|----------------------------|\n"; + int nowait=0; + + if (argc==2 && !strcmp(argv[1], "-w")) { + nowait=1; + } + else if (argc!=1 && argc!=0) { + warnx("usage: forktest [-w]"); + return 1; + } + warnx("Starting. Expect this many:"); + write(STDERR_FILENO, expected, strlen(expected)); + + test(nowait); + + warnx("Complete."); + return 0; +} diff --git a/userland/testbin/frack/Makefile b/userland/testbin/frack/Makefile new file mode 100644 index 0000000..333d5c2 --- /dev/null +++ b/userland/testbin/frack/Makefile @@ -0,0 +1,11 @@ +# Makefile for frack + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=frack +SRCS=main.c workloads.c ops.c do.c check.c pool.c data.c name.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/frack/check.c b/userland/testbin/frack/check.c new file mode 100644 index 0000000..fea6783 --- /dev/null +++ b/userland/testbin/frack/check.c @@ -0,0 +1,2911 @@ +/* + * Copyright (c) 2013, 2015 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "name.h" +#include "data.h" +#include "pool.h" +#include "check.h" + +/* + * Check pass. + * + * We first replay the workload into a model that keeps track of what + * should be on the volume at each step; then we inspect the real + * volume and compare it to the model. + */ + +//////////////////////////////////////////////////////////// +// model representation + +#define UNKNOWN_ID ((unsigned)-1) + +/* + * 1. log of changes to a filesystem + * (this is not quite fully general but supports only things we do) + */ + +enum fschanges { + FC_NEWFS, /* create the volume */ + FC_TRUNCATE, /* truncate a file */ + FC_WRITE, /* write to a file */ + FC_CREAT, /* create a file */ + FC_MKDIR, /* create a directory */ + FC_RMDIR, /* remove a directory */ + FC_UNLINK, /* remove a file */ + FC_LINK, /* hardlink a file */ + FC_RENAMEFILE, /* rename a file */ + FC_RENAMEDIR, /* rename a directory */ +}; +struct fschange { + /* all changes are kept in order on a doubly linked list */ + struct fschange *prev; + struct fschange *next; + + /* version number for this change */ + unsigned version; + + /* whether this change reflects a partially committed operation */ + int partial; + + /* the change type, parameters, and metadata */ + enum fschanges type; + union { + struct { + /* object id of the root directory */ + unsigned rootdirnum; + } fc_newfs; + struct { + /* cached: previous change affecting this file */ + struct fschange *prev_thisfile; + /* truncate params: file oid and new length */ + unsigned file; + off_t len; + } fc_truncate; + struct { + /* cached: previous change affecting this file */ + struct fschange *prev_thisfile; + /* write params: file oid, position, length */ + unsigned file; + off_t pos; + off_t len; + /* size of file before the write */ + off_t oldfilesize; + /* key for generating the write contents */ + unsigned code; + unsigned seq; + } fc_write; + struct { + /* cached: previous change affecting containing dir */ + struct fschange *prev_thisdir; + /* creat params: containing dir oid, name, new oid */ + unsigned dir; + unsigned name; + unsigned newfile; + } fc_creat; + struct { + /* cached: previous change affecting containing dir */ + struct fschange *prev_thisdir; + /* mkdir params: containing dir oid, name, new oid */ + unsigned dir; + unsigned name; + unsigned newdir; + } fc_mkdir; + struct { + /* cached: previous change affecting either dir */ + struct fschange *prev_thisdir; + struct fschange *prev_victimdir; + /* rmdir params */ + unsigned dir; + unsigned name; + unsigned victimdir; + } fc_rmdir; + struct { + /* cached: previous change affecting either object */ + struct fschange *prev_thisdir; + struct fschange *prev_victimfile; + /* unlink params */ + unsigned dir; + unsigned name; + unsigned victimfile; + } fc_unlink; + struct { + /* cached: previous change affecting each object */ + struct fschange *prev_fromdir; + struct fschange *prev_todir; + struct fschange *prev_thisfile; + /* link params */ + unsigned fromdir; + unsigned fromname; + unsigned todir; + unsigned toname; + unsigned file; + } fc_link; + struct { + /* cached: previous change affecting each object */ + struct fschange *prev_fromdir; + struct fschange *prev_todir; + struct fschange *prev_movedfile; + /* rename params */ + unsigned fromdir; + unsigned fromname; + unsigned todir; + unsigned toname; + unsigned movedfile; + } fc_renamefile; + struct { + /* cached: previous change affecting each object */ + struct fschange *prev_fromdir; + struct fschange *prev_todir; + struct fschange *prev_moveddir; + /* rename params */ + unsigned fromdir; + unsigned fromname; + unsigned todir; + unsigned toname; + unsigned moveddir; + } fc_renamedir; + }; +}; + +/* + * 2. representation of a current (visible) filesystem state + * + * The state starts at the root directory; each directory is a singly + * linked list of directory entries, each of which holds another + * directory or a file. We don't keep track of file contents, only the + * length. + * + * The identity field is within the union structure because file and + * directory object ids are different namespaces. + */ + +struct fsdirent { + unsigned name; + struct fsobject *obj; + struct fsdirent *next; +}; + +struct fsobject { + unsigned isdir; + unsigned refcount; + union { + struct { + unsigned identity; + off_t len; + } obj_file; + struct { + unsigned identity; + struct fsdirent *entries; + struct fsobject *parent; + } obj_dir; + }; +}; + +//////////////////////////////////////////////////////////// +// allocator pools + +/* + * Allocate from static space instead of using malloc, to help avoid + * unnecessary lossage on kernels where malloc doesn't work. + */ + +#define MAXCHANGES 16384 +#define MAXOBJECTS 16384 +#define MAXDIRENTS 16384 + +DECLPOOL(fschange, MAXCHANGES); +DECLPOOL(fsobject, MAXOBJECTS); +DECLPOOL(fsdirent, MAXDIRENTS); + +static +struct fschange * +getchange(void) +{ + return POOLALLOC(fschange); +} + +static +struct fsobject * +getobject(void) +{ + return POOLALLOC(fsobject); +} + +static +struct fsdirent * +getdirent(void) +{ + return POOLALLOC(fsdirent); +} + +#if 0 +static +void +putchange(struct fschange *fc) +{ + POOLFREE(fschange, fc); +} +#endif + +static +void +putobject(struct fsobject *obj) +{ + POOLFREE(fsobject, obj); +} + +static +void +putdirent(struct fsdirent *dirent) +{ + POOLFREE(fsdirent, dirent); +} + +//////////////////////////////////////////////////////////// +// record constructors for change records + +static +struct fschange * +fc_create(enum fschanges type) +{ + struct fschange *fc; + + fc = getchange(); + fc->prev = fc->next = NULL; + fc->version = 0; + fc->partial = 0; + fc->type = type; + return fc; +} + +static +struct fschange * +fc_create_newfs(unsigned rootdirnum) +{ + struct fschange *fc; + + fc = fc_create(FC_NEWFS); + fc->fc_newfs.rootdirnum = rootdirnum; + return fc; +} + +static +struct fschange * +fc_create_truncate(struct fschange *prev_thisfile, unsigned file, off_t len) +{ + struct fschange *fc; + + fc = fc_create(FC_TRUNCATE); + fc->fc_truncate.prev_thisfile = prev_thisfile; + fc->fc_truncate.file = file; + fc->fc_truncate.len = len; + return fc; +} + +static +struct fschange * +fc_create_write(struct fschange *prev_thisfile, unsigned file, + off_t pos, off_t len, off_t oldfilesize, + unsigned code, unsigned seq) +{ + struct fschange *fc; + + fc = fc_create(FC_WRITE); + fc->fc_write.prev_thisfile = prev_thisfile; + fc->fc_write.file = file; + fc->fc_write.pos = pos; + fc->fc_write.len = len; + fc->fc_write.oldfilesize = oldfilesize; + fc->fc_write.code = code; + fc->fc_write.seq = seq; + return fc; +} + +static +struct fschange * +fc_create_creat(struct fschange *prev_thisdir, + unsigned dir, unsigned name, unsigned newfile) +{ + struct fschange *mdc; + + mdc = fc_create(FC_CREAT); + mdc->fc_creat.prev_thisdir = prev_thisdir; + mdc->fc_creat.dir = dir; + mdc->fc_creat.name = name; + mdc->fc_creat.newfile = newfile; + return mdc; +} + +static +struct fschange * +fc_create_mkdir(struct fschange *prev_thisdir, + unsigned dir, unsigned name, unsigned newdir) +{ + struct fschange *mdc; + + mdc = fc_create(FC_MKDIR); + mdc->fc_mkdir.prev_thisdir = prev_thisdir; + mdc->fc_mkdir.dir = dir; + mdc->fc_mkdir.name = name; + mdc->fc_mkdir.newdir = newdir; + return mdc; +} + +static +struct fschange * +fc_create_rmdir(struct fschange *prev_thisdir, struct fschange *prev_victimdir, + unsigned dir, unsigned name, unsigned victimdir) +{ + struct fschange *mdc; + + mdc = fc_create(FC_RMDIR); + mdc->fc_rmdir.prev_thisdir = prev_thisdir; + mdc->fc_rmdir.prev_victimdir = prev_victimdir; + mdc->fc_rmdir.dir = dir; + mdc->fc_rmdir.name = name; + mdc->fc_rmdir.victimdir = victimdir; + return mdc; +} + +static +struct fschange * +fc_create_unlink(struct fschange *prev_thisdir, + struct fschange *prev_victimfile, + unsigned dir, unsigned name, unsigned victimfile) +{ + struct fschange *mdc; + + mdc = fc_create(FC_UNLINK); + mdc->fc_unlink.prev_thisdir = prev_thisdir; + mdc->fc_unlink.prev_victimfile = prev_victimfile; + mdc->fc_unlink.dir = dir; + mdc->fc_unlink.name = name; + mdc->fc_unlink.victimfile = victimfile; + return mdc; +} + +static +struct fschange * +fc_create_link(struct fschange *prev_fromdir, struct fschange *prev_todir, + struct fschange *prev_thisfile, + unsigned fromdir, unsigned fromname, + unsigned todir, unsigned toname, + unsigned file) +{ + struct fschange *mdc; + + mdc = fc_create(FC_LINK); + mdc->fc_link.prev_fromdir = prev_fromdir; + mdc->fc_link.prev_todir = prev_todir; + mdc->fc_link.prev_thisfile = prev_thisfile; + mdc->fc_link.fromdir = fromdir; + mdc->fc_link.fromname = fromname; + mdc->fc_link.todir = todir; + mdc->fc_link.toname = toname; + mdc->fc_link.file = file; + return mdc; +} + +static +struct fschange * +fc_create_renamefile(struct fschange *prev_fromdir, + struct fschange *prev_todir, + struct fschange *prev_movedfile, + unsigned fromdir, unsigned fromname, + unsigned todir, unsigned toname, + unsigned movedfile) +{ + struct fschange *mdc; + + mdc = fc_create(FC_RENAMEFILE); + mdc->fc_renamefile.prev_fromdir = prev_fromdir; + mdc->fc_renamefile.prev_todir = prev_todir; + mdc->fc_renamefile.prev_movedfile = prev_movedfile; + mdc->fc_renamefile.fromdir = fromdir; + mdc->fc_renamefile.fromname = fromname; + mdc->fc_renamefile.todir = todir; + mdc->fc_renamefile.toname = toname; + mdc->fc_renamefile.movedfile = movedfile; + return mdc; +} + +static +struct fschange * +fc_create_renamedir(struct fschange *prev_fromdir, + struct fschange *prev_todir, + struct fschange *prev_moveddir, + unsigned fromdir, unsigned fromname, + unsigned todir, unsigned toname, + unsigned moveddir) +{ + struct fschange *fc; + + fc = fc_create(FC_RENAMEDIR); + fc->fc_renamedir.prev_fromdir = prev_fromdir; + fc->fc_renamedir.prev_todir = prev_todir; + fc->fc_renamedir.prev_moveddir = prev_moveddir; + fc->fc_renamedir.fromdir = fromdir; + fc->fc_renamedir.fromname = fromname; + fc->fc_renamedir.todir = todir; + fc->fc_renamedir.toname = toname; + fc->fc_renamedir.moveddir = moveddir; + return fc; +} + +//////////////////////////////////////////////////////////// +// constructors/destructors for current state objects + +static +struct fsdirent * +fsdirent_create(unsigned name, struct fsobject *obj) +{ + struct fsdirent *ret; + + ret = getdirent(); + ret->name = name; + ret->obj = obj; + ret->next = NULL; + return ret; +} + +static +void +fsdirent_destroy(struct fsdirent *de) +{ + assert(de->obj == NULL); + assert(de->next == NULL); + putdirent(de); +} + +static +struct fsobject * +fsobject_create_file(unsigned id) +{ + struct fsobject *ret; + + ret = getobject(); + ret->isdir = 0; + ret->refcount = 1; + ret->obj_file.identity = id; + ret->obj_file.len = 0; + return ret; +} + +static +struct fsobject * +fsobject_create_dir(unsigned id, struct fsobject *parent) +{ + struct fsobject *ret; + + ret = getobject(); + ret->isdir = 1; + ret->refcount = 1; + ret->obj_dir.identity = id; + ret->obj_dir.entries = NULL; + ret->obj_dir.parent = parent; + return ret; +} + +static +void +fsobject_incref(struct fsobject *obj) +{ + assert(obj->refcount > 0); + obj->refcount++; + assert(obj->refcount > 0); +} + +static +void +fsobject_decref(struct fsobject *obj) +{ + assert(obj->refcount > 0); + obj->refcount--; + if (obj->refcount > 0) { + return; + } + + if (obj->isdir) { + assert(obj->obj_dir.entries == NULL); + } + putobject(obj); +} + +static +void +fsobject_destroytree(struct fsobject *obj) +{ + struct fsdirent *de; + + if (obj->isdir) { + while (obj->obj_dir.entries != NULL) { + de = obj->obj_dir.entries; + obj->obj_dir.entries = de->next; + de->next = NULL; + fsobject_destroytree(de->obj); + de->obj = NULL; + fsdirent_destroy(de); + } + } + fsobject_decref(obj); +} + +//////////////////////////////////////////////////////////// +// operations on current state objects + +/* + * Bail out if something's broken. + */ +static +void +die(const char *fmt, ...) +{ + char buf[256]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + errx(1, "Inconsistency: %s", buf); +} + +#if 0 /* not used */ +/* + * Count a list of directory entries. + */ +static +unsigned +fsdirent_count(struct fsdirent *de) +{ + if (de == NULL) { + return 0; + } + return 1 + fsdirent_count(de->next); +} +#endif + +/* + * Add an entry to a directory. + */ +static +void +fsdir_add_entry(struct fsobject *dir, struct fsdirent *nde) +{ + struct fsdirent *ode; + + assert(dir->isdir); + for (ode = dir->obj_dir.entries; ode != NULL; ode = ode->next) { + if (ode->name == nde->name) { + die("In directory %u, %s already existed", + dir->obj_dir.identity, name_get(nde->name)); + } + } + nde->next = dir->obj_dir.entries; + dir->obj_dir.entries = nde; +} + +/* + * Find an entry in a directory by name. If CROAK is set, bail out if + * it's not there. + */ +static +struct fsdirent * +fsdir_find_entry(struct fsobject *dir, unsigned name, int croak) +{ + struct fsdirent *de; + + assert(dir->isdir); + for (de = dir->obj_dir.entries; de != NULL; de = de->next) { + if (de->name == name) { + return de; + } + } + if (croak) { + die("In directory %u, did not find %s", + dir->obj_dir.identity, name_get(name)); + } + return NULL; +} + +/* + * Remove an entry from a directory. + */ +static +struct fsdirent * +fsdir_remove_entry(struct fsobject *dir, unsigned name) +{ + struct fsdirent *de, **prevptr; + + assert(dir->isdir); + prevptr = &dir->obj_dir.entries; + for (de = *prevptr; de != NULL; prevptr = &de->next, de = *prevptr) { + if (de->name == name) { + *prevptr = de->next; + de->next = NULL; + return de; + } + } + die("In directory %u, did not find %s", + dir->obj_dir.identity, name_get(name)); + return NULL; +} + +//////////////////////////////////////////////////////////// +// apply a change record to a current state + +static +struct fsobject * +findsub(struct fsobject *obj, unsigned isdir, unsigned id) +{ + struct fsobject *ret; + struct fsdirent *de; + unsigned objid; + + /* Are we on the object we're looking for? */ + objid = obj->isdir ? obj->obj_dir.identity : obj->obj_file.identity; + if (obj->isdir == isdir && objid == id) { + return obj; + } + + /* If the object we're on isn't a dir, can't search any further */ + if (!obj->isdir) { + return NULL; + } + + for (de = obj->obj_dir.entries; de != NULL; de = de->next) { + ret = findsub(de->obj, isdir, id); + if (ret != NULL) { + return ret; + } + } + return NULL; +} + +#if 0 +static +struct fsobject * +findfile(struct fsobject *rootdir, unsigned id) +{ + struct fsobject *ret; + + ret = findsub(rootdir, 0/*!isdir*/, id); + if (ret == NULL) { + die("File %u not found in current state", id); + } + return ret; +} +#endif + +static +struct fsobject * +findfile_maybe(struct fsobject *rootdir, unsigned id) +{ + return findsub(rootdir, 0/*!isdir*/, id); +} + +static +struct fsobject * +finddir(struct fsobject *rootdir, unsigned id) +{ + struct fsobject *ret; + + ret = findsub(rootdir, 1/*isdir*/, id); + if (ret == NULL) { + die("Directory %u not found in current state", id); + } + return ret; +} + +/* + * Apply change CHANGE to the volume state encoded in/under ROOTDIR. + */ +static +void +apply_change(struct fsobject *rootdir, struct fschange *change) +{ + struct fsobject *obj1, *obj2; + struct fsdirent *de; + off_t endpos; + + assert(rootdir->isdir); + + switch (change->type) { + case FC_NEWFS: + /* + * Creating the volume; crosscheck the root directory. + */ + assert(rootdir->isdir); + assert(rootdir->refcount == 1); + assert(rootdir->obj_dir.identity == + change->fc_newfs.rootdirnum); + assert(rootdir->obj_dir.entries == NULL); + assert(rootdir->obj_dir.parent == rootdir); + break; + case FC_TRUNCATE: + /* + * Truncate a file. (Only files, not directories.) + * + * Because truncates can and do get posted after a + * file is unlinked, we have to tolerate not finding + * the file. We don't model unlinked files, because + * they aren't visible and our goal is to check the + * visible/observable state. + */ + obj1 = findfile_maybe(rootdir, change->fc_truncate.file); + if (obj1 != NULL) { + obj1->obj_file.len = change->fc_truncate.len; + } + break; + case FC_WRITE: + /* + * Write to a file. (Only files, not directories.) + * All this actually does is update the file size if + * needed. + * + * We also have to tolerate writes to unlinked files. + */ + obj1 = findfile_maybe(rootdir, change->fc_write.file); + if (obj1 != NULL) { + endpos = change->fc_write.pos + change->fc_write.len; + if (obj1->obj_file.len < endpos) { + obj1->obj_file.len = endpos; + } + } + break; + case FC_CREAT: + /* + * Create a file. This creates a new object and a + * directory entry to hold it, then inserts the + * directory entry in the containing directory. + */ + obj1 = finddir(rootdir, change->fc_creat.dir); + obj2 = fsobject_create_file(change->fc_creat.newfile); + de = fsdirent_create(change->fc_creat.name, obj2); + fsdir_add_entry(obj1, de); + break; + case FC_MKDIR: + /* + * Create a directory. The same as creating a file, + * except the new object is a directory. + */ + obj1 = finddir(rootdir, change->fc_mkdir.dir); + obj2 = fsobject_create_dir(change->fc_mkdir.newdir, obj1); + de = fsdirent_create(change->fc_mkdir.name, obj2); + fsdir_add_entry(obj1, de); + break; + case FC_RMDIR: + /* + * Remove a directory. First take out the directory + * entry (by name); then examine the object found; + * then delete everything. + * + * XXX: why do these checks use assert vs. testing and + * calling die()? + */ + obj1 = finddir(rootdir, change->fc_rmdir.dir); + de = fsdir_remove_entry(obj1, change->fc_rmdir.name); + obj2 = de->obj; + de->obj = NULL; + assert(obj2->isdir); + assert(obj2->obj_dir.entries == NULL); + assert(obj2->obj_dir.identity == change->fc_rmdir.victimdir); + assert(obj2->obj_dir.parent == obj1); + fsdirent_destroy(de); + fsobject_decref(obj2); + break; + case FC_UNLINK: + /* + * Remove a file. Much the same as removing a directory. + */ + obj1 = finddir(rootdir, change->fc_unlink.dir); + de = fsdir_remove_entry(obj1, change->fc_unlink.name); + obj2 = de->obj; + de->obj = NULL; + assert(!obj2->isdir); + assert(obj2->obj_file.identity == + change->fc_unlink.victimfile); + fsdirent_destroy(de); + fsobject_decref(obj2); + break; + case FC_LINK: + /* + * Hard-link a file. + */ + obj1 = finddir(rootdir, change->fc_link.fromdir); + de = fsdir_find_entry(obj1, change->fc_link.fromname, 1); + obj2 = de->obj; + assert(!obj2->isdir); + assert(obj2->obj_file.identity == change->fc_link.file); + obj1 = finddir(rootdir, change->fc_link.todir); + fsobject_incref(obj2); + de = fsdirent_create(change->fc_link.toname, obj2); + fsdir_add_entry(obj1, de); + break; + case FC_RENAMEFILE: + /* + * Rename a file. XXX: this appears to do the wrong + * thing if you rename one file over another. + */ + obj1 = finddir(rootdir, change->fc_renamefile.fromdir); + de = fsdir_remove_entry(obj1, change->fc_renamefile.fromname); + obj2 = de->obj; + assert(!obj2->isdir); + assert(obj2->obj_file.identity == + change->fc_renamefile.movedfile); + obj1 = finddir(rootdir, change->fc_renamefile.todir); + de->name = change->fc_renamefile.toname; + fsdir_add_entry(obj1, de); + break; + case FC_RENAMEDIR: + /* + * Rename a directory. Same as renaming a file, except + * that we update the parent of the directory being + * moved. XXX: also seems to do the wrong thing if you + * rename one directory over another. And, XXX: should + * this be updating the refcount as the parent + * changes? Shouldn't the refcount be the same as the + * on-disk linkcount, and shouldn't the on-disk + * linkcount be part of the state we examine and + * verify? + */ + obj1 = finddir(rootdir, change->fc_renamedir.fromdir); + de = fsdir_remove_entry(obj1, change->fc_renamedir.fromname); + obj2 = de->obj; + assert(obj2->isdir); + assert(obj2->obj_dir.identity == + change->fc_renamedir.moveddir); + assert(obj2->obj_dir.parent == obj1); + obj1 = finddir(rootdir, change->fc_renamedir.todir); + de->name = change->fc_renamedir.toname; + obj2->obj_dir.parent = obj1; + fsdir_add_entry(obj1, de); + break; + } +} + +//////////////////////////////////////////////////////////// +// global fs state + +/* + * The change records. FIRSTCHANGE is the first change record; CHANGES + * is the list root, which given the current linked list implementation + * is the *last* (most recent) change record. + */ +static struct fschange *firstchange; +static struct fschange *changes; + +/* + * The current volume state that we're working with. As we add change + * records while replaying the workload, we roll this forward so we + * can inspect it; for some things this is necessary to be able to + * replay the workload fully. + */ +static struct fsobject *state; + +/* + * The next oids of each type to assign. File and directory ids are + * counted independently, which might or might not have been a good + * idea. + */ +static unsigned nextfilenum, nextdirnum; + +/* + * Add a new change record. This allocates the version number; + * however, the change record should otherwise be fully filled in + * already. + * + * usage: fc_attach(newrecord); + */ +static +void +fc_attach(struct fschange *new) +{ + struct fschange *prev; + + prev = changes; + + assert(prev->next == NULL); + assert(new->prev == NULL); + assert(new->next == NULL); + prev->next = new; + new->prev = prev; + new->version = prev->version + 1; + + changes = new; + apply_change(state, new); +} + +/* + * Rewind the volume state kept in the global STATE to the beginning. + */ +static +void +rewindstate(void) +{ + /* If we already have a state, throw it away. */ + if (state != NULL) { + fsobject_destroytree(state); + } + + assert(firstchange->type == FC_NEWFS); + + state = fsobject_create_dir(firstchange->fc_newfs.rootdirnum, NULL); + /* root directory's parent is itself */ + state->obj_dir.parent = state; +} + +/* + * Roll the volume state kept in STATE forward to a specific change + * entry. + */ +static +void +advancestateto(struct fschange *targetchange) +{ + struct fschange *change; + + for (change = firstchange; change != NULL; change = change->next) { + apply_change(state, change); + if (change == targetchange) { + return; + } + } + assert(0); +} + +//////////////////////////////////////////////////////////// +// lookup in the fs state +// (used during model construction) + +/* + * Find the most recent previous record that mentions a particular file. + * + * If there isn't one, something's wrong; because we start with a + * fresh volume every file that ever exists must have been created at + * some point. + * + * This is used while replaying the workload and accumulating change + * records, so it can always just start from the most recent end + * instead of from a specific place. + */ +static +struct fschange * +changes_findprevfile(unsigned filenum) +{ + struct fschange *here; + + for (here = changes; here != NULL; here = here->prev) { + switch (here->type) { + case FC_NEWFS: + break; + case FC_TRUNCATE: + if (here->fc_truncate.file == filenum) { + return here; + } + break; + case FC_WRITE: + if (here->fc_write.file == filenum) { + return here; + } + break; + case FC_CREAT: + if (here->fc_creat.newfile == filenum) { + return here; + } + break; + case FC_MKDIR: + case FC_RMDIR: + break; + case FC_UNLINK: + if (here->fc_unlink.victimfile == filenum) { + return here; + } + break; + case FC_LINK: + if (here->fc_link.file == filenum) { + return here; + } + break; + case FC_RENAMEFILE: + if (here->fc_renamefile.movedfile == filenum) { + return here; + } + break; + case FC_RENAMEDIR: + break; + } + } + die("No previous record for file %u", filenum); + return NULL; +} + +/* + * Find the most recent previous record that mentions a particular dir. + * + * Likewise, if there isn't one, something's wrong. + */ +static +struct fschange * +changes_findprevdir(unsigned dirnum) +{ + struct fschange *here; + + for (here = changes; here != NULL; here = here->prev) { + switch (here->type) { + case FC_NEWFS: + if (here->fc_newfs.rootdirnum == dirnum) { + return here; + } + break; + case FC_TRUNCATE: + case FC_WRITE: + break; + case FC_CREAT: + if (here->fc_creat.dir == dirnum) { + return here; + } + break; + case FC_MKDIR: + if (here->fc_mkdir.dir == dirnum || + here->fc_mkdir.newdir == dirnum) { + return here; + } + break; + case FC_RMDIR: + if (here->fc_rmdir.dir == dirnum || + here->fc_rmdir.victimdir == dirnum) { + return here; + } + break; + case FC_UNLINK: + if (here->fc_unlink.dir == dirnum) { + return here; + } + break; + case FC_LINK: + if (here->fc_link.fromdir == dirnum || + here->fc_link.todir == dirnum) { + return here; + } + break; + case FC_RENAMEFILE: + if (here->fc_renamefile.fromdir == dirnum || + here->fc_renamefile.todir == dirnum) { + return here; + } + break; + case FC_RENAMEDIR: + if (here->fc_renamedir.fromdir == dirnum || + here->fc_renamedir.todir == dirnum || + here->fc_renamedir.moveddir == dirnum) { + return here; + } + break; + } + } + die("No previous record for directory %u", dirnum); + return NULL; +} + +#if 0 +/* + * Back up to the previous record mentioning the same file. + * + * XXX: No longer used and should be removed. + */ +static +struct fschange * +fs_prevforfile(struct fschange *fc, unsigned filenum) +{ + switch (fc->type) { + case FC_TRUNCATE: + if (fc->fc_truncate.file == filenum) { + return fc->fc_truncate.prev_thisfile; + } + break; + case FC_WRITE: + if (fc->fc_write.file == filenum) { + return fc->fc_write.prev_thisfile; + } + break; + case FC_UNLINK: + if (fc->fc_unlink.victimfile == filenum) { + return fc->fc_unlink.prev_victimfile; + } + break; + case FC_LINK: + if (fc->fc_link.file == filenum) { + return fc->fc_link.prev_thisfile; + } + break; + case FC_RENAMEFILE: + if (fc->fc_renamefile.movedfile == filenum) { + return fc->fc_renamefile.prev_movedfile; + } + break; + default: + break; + } + return fc->prev; +} +#endif + +#if 0 +/* + * Back up to the previous record mentioning the same directory. + * + * XXX: No longer used and should be removed. + */ +static +struct fschange * +fs_prevfordir(struct fschange *fc, unsigned dirnum) +{ + switch (fc->type) { + case FC_CREAT: + if (fc->fc_creat.dir == dirnum) { + return fc->fc_creat.prev_thisdir; + } + break; + case FC_MKDIR: + if (fc->fc_mkdir.dir == dirnum) { + return fc->fc_mkdir.prev_thisdir; + } + break; + case FC_RMDIR: + if (fc->fc_rmdir.dir == dirnum) { + return fc->fc_rmdir.prev_thisdir; + } + if (fc->fc_rmdir.victimdir == dirnum) { + return fc->fc_rmdir.prev_victimdir; + } + break; + case FC_UNLINK: + if (fc->fc_unlink.dir == dirnum) { + return fc->fc_unlink.prev_thisdir; + } + break; + case FC_LINK: + if (fc->fc_link.fromdir == dirnum) { + return fc->fc_link.prev_fromdir; + } + if (fc->fc_link.todir == dirnum) { + return fc->fc_link.prev_todir; + } + break; + case FC_RENAMEFILE: + if (fc->fc_renamefile.fromdir == dirnum) { + return fc->fc_renamefile.prev_fromdir; + } + if (fc->fc_renamefile.todir == dirnum) { + return fc->fc_renamefile.prev_todir; + } + break; + case FC_RENAMEDIR: + if (fc->fc_renamedir.fromdir == dirnum) { + return fc->fc_renamedir.prev_fromdir; + } + if (fc->fc_renamedir.todir == dirnum) { + return fc->fc_renamedir.prev_todir; + } + if (fc->fc_renamedir.moveddir == dirnum) { + return fc->fc_renamedir.prev_moveddir; + } + break; + default: + break; + } + return fc->prev; +} + +/* + * Find an object by name and containing directory by searching the + * change history. + * + * No longer used (instead we maintain the current state and search + * that, which is a lot simpler) and should probably be removed. + */ +struct findresult { + int isfile; + unsigned objnum; +}; + +static +int +fs_find(unsigned dirnum, unsigned name, struct findresult *res) +{ + struct fschange *here; + + for (here = fs; here != NULL; here = fs_prevfordir(here, dirnum)) { + switch (here->type) { + case FC_NEWFS: + case FC_TRUNCATE: + case FC_WRITE: + break; + case FC_CREAT: + if (here->fc_creat.dir == dirnum && + here->fc_creat.name == name) { + res->isfile = 1; + res->objnum = here->fc_creat.newfile; + return 0; + } + break; + case FC_MKDIR: + if (here->fc_mkdir.dir == dirnum && + here->fc_mkdir.name == name) { + res->isfile = 0; + res->objnum = here->fc_mkdir.newdir; + return 0; + } + if (here->fc_mkdir.newdir == dirnum) { + return -1; + } + break; + case FC_RMDIR: + if (here->fc_rmdir.dir == dirnum && + here->fc_rmdir.name == name) { + return -1; + } + if (here->fc_rmdir.victimdir == dirnum) { + return -1; + } + break; + case FC_UNLINK: + if (here->fc_unlink.dir == dirnum && + here->fc_unlink.name == name) { + return -1; + } + break; + case FC_LINK: + if ((here->fc_link.todir == dirnum && + here->fc_link.toname == name) || + (here->fc_link.fromdir == dirnum && + here->fc_link.fromname == name)) { + res->isfile = 1; + res->objnum = here->fc_link.file; + return 0; + } + break; + case FC_RENAMEFILE: + if (here->fc_renamefile.fromdir == dirnum && + here->fc_renamefile.fromname == name) { + return -1; + } + if (here->fc_renamefile.todir == dirnum && + here->fc_renamefile.toname == name) { + res->isfile = 1; + res->objnum = here->fc_renamefile.movedfile; + return 0; + } + break; + case FC_RENAMEDIR: + if (here->fc_renamedir.fromdir == dirnum && + here->fc_renamedir.fromname == name) { + return -1; + } + if (here->fc_renamedir.todir == dirnum && + here->fc_renamedir.toname == name) { + res->isfile = 0; + res->objnum = here->fc_renamedir.moveddir; + return 0; + } + break; + } + } + return -1; +} + +/* + * Find a file by name and containing directory, using fs_find to + * search the history. + * + * No longer used; should be removed. + */ +static +unsigned +fs_findfile(unsigned dirnum, unsigned name) +{ + struct findresult res; + + if (fs_find(dirnum, name, &res) < 0) { + die("In directory %u, did not find %s", + dirnum, name_get(name)); + } + if (res.isfile == 0) { + die("In directory %u, %s was a directory", + dirnum, name_get(name)); + } + return res.objnum; +} + +/* + * Find a directory by name and containing directory, using fs_find to + * search the history. + * + * No longer used; should be removed. + */ +static +unsigned +fs_finddir(unsigned dirnum, unsigned name) +{ + struct findresult res; + + if (fs_find(dirnum, name, &res) < 0) { + die("In directory %u, did not find %s", + dirnum, name_get(name)); + } + if (res.isfile == 1) { + die("In directory %u, %s was not a directory", + dirnum, name_get(name)); + } + return res.objnum; +} + +/* + * Check if a name (in a specific containing directory) is a file, + * using fs_find. + * + * No longer used; should be removed. + */ +static +int +fs_isfile(unsigned dirnum, unsigned name) +{ + struct findresult res; + + if (fs_find(dirnum, name, &res) < 0) { + return 0; + } + return res.isfile; +} + +/* + * Check if a name (in a specific containing directory) is a + * directory, using fs_find. + * + * No longer used; should be removed. + */ +static +int +fs_isdir(unsigned dirnum, unsigned name) +{ + struct findresult res; + + if (fs_find(dirnum, name, &res) < 0) { + return 0; + } + return !res.isfile; +} + +/* + * Find the parent of a directory by its object id, by searching the + * history. + * + * No longer used; should be removed. + */ +static +unsigned +fs_findparent(unsigned dirnum) +{ + struct fschange *here; + + for (here = fs; here != NULL; here = fs_prevfordir(here, dirnum)) { + switch (here->type) { + case FC_NEWFS: + if (here->fc_newfs.rootdirnum == dirnum) { + return dirnum; + } + break; + case FC_TRUNCATE: + case FC_WRITE: + case FC_CREAT: + break; + case FC_MKDIR: + if (here->fc_mkdir.newdir == dirnum) { + return here->fc_mkdir.dir; + } + break; + case FC_RMDIR: + if (here->fc_rmdir.victimdir == dirnum) { + die("Directory %u was removed", dirnum); + } + break; + case FC_UNLINK: + case FC_LINK: + case FC_RENAMEFILE: + break; + case FC_RENAMEDIR: + if (here->fc_renamedir.moveddir == dirnum) { + return here->fc_renamedir.todir; + } + break; + } + } + die("Directory %u not found", dirnum); + return 0; +} +#endif /* 0 */ + +/* + * Find a file by name and containing directory, by searching the + * volume state. + */ +static +unsigned +model_findfile(unsigned dirnum, unsigned name) +{ + struct fsobject *obj; + struct fsdirent *de; + + obj = finddir(state, dirnum); + de = fsdir_find_entry(obj, name, 1); + if (de->obj->isdir) { + die("In directory %u, %s was a directory", + dirnum, name_get(name)); + } + return de->obj->obj_file.identity; +} + +/* + * Find a directory by name and containing directory, by searching the + * volume state. + */ +static +unsigned +model_finddir(unsigned dirnum, unsigned name) +{ + struct fsobject *obj; + struct fsdirent *de; + + obj = finddir(state, dirnum); + de = fsdir_find_entry(obj, name, 1); + if (!de->obj->isdir) { + die("In directory %u, %s was not a directory", + dirnum, name_get(name)); + } + return de->obj->obj_dir.identity; +} + +/* + * Find a directory's parent by object id, by searching the volume + * state. + */ +static +unsigned +model_findparent(unsigned dirnum) +{ + struct fsobject *obj; + + obj = finddir(state, dirnum); + assert(obj->isdir); + assert(obj->obj_dir.parent->isdir); + return obj->obj_dir.parent->obj_dir.identity; +} + +/* + * Check if a name (in a specific containing directory) is a file, by + * searching the volume state. + */ +static +unsigned +model_isfile(unsigned dirnum, unsigned name) +{ + struct fsobject *obj; + struct fsdirent *de; + + obj = finddir(state, dirnum); + de = fsdir_find_entry(obj, name, 0); + return de != NULL && !de->obj->isdir; +} + +/* + * Check if a name (in a specific containing directory) is a + * directory, by searching the volume state. + */ +static +unsigned +model_isdir(unsigned dirnum, unsigned name) +{ + struct fsobject *obj; + struct fsdirent *de; + + obj = finddir(state, dirnum); + de = fsdir_find_entry(obj, name, 0); + return de != NULL && de->obj->isdir; +} + +/* + * Get the current size of a file in the current volume state. + */ +static +off_t +model_getfilesize(unsigned filenum) +{ + struct fsobject *obj; + + obj = findfile_maybe(state, filenum); + if (obj == NULL) { + /* file is unlinked */ + return 0; + } + assert(!obj->isdir); + return obj->obj_file.len; +} + +//////////////////////////////////////////////////////////// +// model construction (replaying the workload) + +/* The workload's current directory. */ +static unsigned cwd; + +/* + * Set up for replying the workload: allocate the root directory, + * generate the newfs record, set up the volume state, initialize + * the current directory. + */ +void +check_setup(void) +{ + unsigned rootdir; + + assert(firstchange == NULL); + assert(changes == NULL); + assert(state == NULL); + assert(nextfilenum == 0); + assert(nextdirnum == 0); + + rootdir = nextdirnum++; + firstchange = changes = fc_create_newfs(rootdir); + + rewindstate(); + + /* apply the first change (the newfs record) */ + apply_change(state, changes); + + cwd = rootdir; +} + +/* + * Workload replay: create a file + */ +int +check_createfile(unsigned name) +{ + struct fschange *prevdir; + unsigned filenum; + + prevdir = changes_findprevdir(cwd); + + filenum = nextfilenum++; + fc_attach(fc_create_creat(prevdir, cwd, name, filenum)); + return filenum; +} + +/* + * Workload replay: open a file + */ +int +check_openfile(unsigned name) +{ + return model_findfile(cwd, name); +} + +/* + * Workload replay: close a file + */ +void +check_closefile(int handle, unsigned name) +{ + /* don't need to do anything */ + (void)handle; + (void)name; +} + +/* + * Workload replay: write to a file + * + * CODE and SEQ encode the contents to be written. + */ +void +check_write(int handle, unsigned name, unsigned code, unsigned seq, + off_t pos, off_t len) +{ + unsigned filenum; + struct fschange *prevfile; + off_t prevlen; + + filenum = handle; + assert(filenum < nextfilenum); + (void)name; + + prevlen = model_getfilesize(filenum); + + prevfile = changes_findprevfile(filenum); + fc_attach(fc_create_write(prevfile, filenum, pos, len, prevlen, + code, seq)); +} + +/* + * Workload replay: truncate a file + */ +void +check_truncate(int handle, unsigned name, off_t len) +{ + unsigned filenum; + struct fschange *prevfile; + + filenum = handle; + assert(filenum < nextfilenum); + (void)name; + + prevfile = changes_findprevfile(filenum); + fc_attach(fc_create_truncate(prevfile, filenum, len)); +} + +/* + * Workload replay: create a directory + */ +void +check_mkdir(unsigned name) +{ + struct fschange *prevdir; + unsigned dirnum; + + prevdir = changes_findprevdir(cwd); + dirnum = nextdirnum++; + fc_attach(fc_create_mkdir(prevdir, cwd, name, dirnum)); +} + +/* + * Workload replay: remove a directory + */ +void +check_rmdir(unsigned name) +{ + struct fschange *prevdir, *prevvictim; + unsigned victim; + + prevdir = changes_findprevdir(cwd); + victim = model_finddir(cwd, name); + prevvictim = changes_findprevdir(victim); + + fc_attach(fc_create_rmdir(prevdir, prevvictim, cwd, name, victim)); +} + +/* + * Workload replay: remove a file + */ +void +check_unlink(unsigned name) +{ + struct fschange *prevdir, *prevvictim; + unsigned victim; + + prevdir = changes_findprevdir(cwd); + victim = model_findfile(cwd, name); + prevvictim = changes_findprevfile(victim); + + fc_attach(fc_create_unlink(prevdir, prevvictim, cwd, name, victim)); +} + +/* + * Workload replay: hard link a file + */ +void +check_link(unsigned fromname, unsigned toname) +{ + struct fschange *prevdir, *prevfile; + unsigned filenum; + + prevdir = changes_findprevdir(cwd); + filenum = model_findfile(cwd, fromname); + prevfile = changes_findprevfile(filenum); + + fc_attach(fc_create_link(prevdir, prevdir, prevfile, + cwd, fromname, cwd, toname, filenum)); +} + +/* + * Workload replay: rename something + */ +static +void +common_rename(unsigned fromdirnum, unsigned fromname, + unsigned todirnum, unsigned toname) +{ + struct fschange *prevfromdir, *prevtodir, *prevfrom, *prevto; + unsigned fromnum, tonum; + struct fschange *fc; + int isfile; + + prevfromdir = changes_findprevdir(fromdirnum); + prevtodir = changes_findprevdir(todirnum); + + if (model_isfile(todirnum, toname)) { + isfile = 1; + assert(model_isfile(fromdirnum, fromname)); + tonum = model_findfile(todirnum, toname); + prevto = changes_findprevfile(tonum); + fc = fc_create_unlink(prevtodir, prevto, + todirnum, toname, tonum); + } + else if (model_isdir(todirnum, toname)) { + isfile = 0; + assert(model_isdir(fromdirnum, fromname)); + tonum = model_finddir(todirnum, toname); + prevto = changes_findprevdir(tonum); + fc = fc_create_rmdir(prevtodir, prevto, + todirnum, toname, tonum); + } + else { + isfile = model_isfile(fromdirnum, fromname); + fc = NULL; + } + + if (fc) { + fc->partial = 1; + fc_attach(fc); + } + + if (isfile) { + fromnum = model_findfile(fromdirnum, fromname); + prevfrom = changes_findprevfile(fromnum); + fc = fc_create_renamefile(prevfromdir, prevtodir, prevfrom, + fromdirnum, fromname, + todirnum, toname, fromnum); + } + else { + fromnum = model_finddir(fromdirnum, fromname); + prevfrom = changes_findprevdir(fromnum); + fc = fc_create_renamedir(prevfromdir, prevtodir, prevfrom, + fromdirnum, fromname, + todirnum, toname, fromnum); + } + fc_attach(fc); +} + +/* + * Workload replay: rename within the current directory + */ +void +check_rename(unsigned from, unsigned to) +{ + common_rename(cwd, from, cwd, to); +} + +/* + * Workload replay: cross-directory rename + */ +void +check_renamexd(unsigned fromdir, unsigned from, unsigned todir, unsigned to) +{ + unsigned fromdirnum, todirnum; + + /* fromdir/todir are names in cwd */ + fromdirnum = model_finddir(cwd, fromdir); + todirnum = model_finddir(cwd, todir); + + common_rename(fromdirnum, from, todirnum, to); +} + +/* + * Workload replay: change directory + */ +void +check_chdir(unsigned name) +{ + cwd = model_finddir(cwd, name); +} + +/* + * Workload replay: change directory to .. + */ +void +check_chdirup(void) +{ + cwd = model_findparent(cwd); +} + +/* + * Workload replay: sync + */ +void +check_sync(void) +{ + /* nothing */ +} + +//////////////////////////////////////////////////////////// +// inspection of the fs + +/* the root of the state we found (as opposed to the state we modeled) */ +static struct fsobject *found; + +/* count of how much we found */ +static unsigned found_subdirs, found_files; + +/* + * Wrapper. As of this writing OS/161 provides fstat but not stat... + * grr + */ +static +int +xstat(const char *path, struct stat *buf) +{ + int fd, ret, serrno; + + fd = open(path, O_RDONLY); + if (fd < 0) { + return -1; + } + ret = fstat(fd, buf); + serrno = errno; + close(fd); + errno = serrno; + return ret; +} + +/* + * Inspect a directory. PARENTOBJ is the *containing* directory; + * PARENTINO is its inode number, and DIRNAMESTR is the name of the + * directory to inspect. The arguments are set up this way (rather + * than e.g. passing the fsobject of the directory to inspect) to + * improve the error reporting, and to allow checking .., and so + * forth. + */ +static +struct fsobject * +inspectdir(struct fsobject *parentobj, ino_t parentino, const char *dirnamestr) +{ + char subnamestr[NAME_MAX+1]; + size_t subnamelen; + struct stat dirstat, dotstat, substat; + int dirfd; + struct fsobject *subobj, *ret; + struct fsdirent *contents, *de; + + /* + * Stat the target, and cd into it. + */ + + if (xstat(dirnamestr, &dirstat)) { + err(1, "%s: stat", dirnamestr); + } + + assert(S_ISDIR(dirstat.st_mode)); + if (chdir(dirnamestr)) { + err(1, "%s: chdir", dirnamestr); + } + + /* + * Check that . is correct + */ + + if (xstat(".", &dotstat)) { + err(1, "In %s: .: stat", dirnamestr); + } + if (dotstat.st_dev != dirstat.st_dev) { + errx(1, "in %s: .: wrong volume id; found %u, expected %u", + dirnamestr, dotstat.st_dev, dirstat.st_dev); + } + if (dotstat.st_ino != dirstat.st_ino) { + errx(1, "%s/.: wrong inode number; found %u, expected %u", + dirnamestr, dotstat.st_ino, dirstat.st_ino); + } + + /* + * Check that .. leads back + */ + + if (xstat("..", &dotstat)) { + err(1, "In %s: ..: stat", dirnamestr); + } + if (dotstat.st_dev != dirstat.st_dev) { + errx(1, "In %s: ..: wrong volume id; found %u, expected %u", + dirnamestr, dotstat.st_dev, dirstat.st_dev); + } + if (dotstat.st_ino != parentino) { + errx(1, "In %s: ..: wrong inode number; found %u, expected %u", + dirnamestr, dotstat.st_ino, parentino); + } + + /* + * Create a directory fsobject. + */ + + dirfd = open(".", O_RDONLY); + if (dirfd < 0) { + err(1, "In %s: .: open", dirnamestr); + } + + ret = fsobject_create_dir(UNKNOWN_ID, parentobj); + + /* + * Read the contents of the target directory and create + * directory entries for them. Recurse for ones that are + * themselves directories. + */ + contents = NULL; + while (1) { + subnamelen = getdirentry(dirfd, subnamestr, + sizeof(subnamestr)-1); + if (subnamelen == 0) { + break; + } + subnamestr[subnamelen] = 0; + + if (!strcmp(subnamestr, ".") || !strcmp(subnamestr, "..")) { + continue; + } + if (xstat(subnamestr, &substat)) { + err(1, "In %s: %s: stat", dirnamestr, subnamestr); + } + if (S_ISDIR(substat.st_mode)) { + subobj = inspectdir(ret, dirstat.st_ino, subnamestr); + found_subdirs++; + } + else { + subobj = fsobject_create_file(UNKNOWN_ID); + subobj->obj_file.len = substat.st_size; + found_files++; + } + de = fsdirent_create(name_find(subnamestr), subobj); + de->next = contents; + contents = de; + } + + /* + * Done scanning; cd out, save the contents, and return the + * new object. + */ + + close(dirfd); + if (chdir("..")) { + err(1, "In %s; ..: chdir", dirnamestr); + } + + ret->obj_dir.entries = contents; + + return ret; +} + +/* + * Inspect the whole volume by starting with "." -- we assume that we + * were run in the root directory. + */ +static +void +inspectfs(void) +{ + struct stat st; + + if (xstat(".", &st)) { + err(1, ".: stat"); + } + found = inspectdir(NULL, st.st_ino, "."); +} + +//////////////////////////////////////////////////////////// +// comparison of state trees + +/* + * Count the number of objects at and below a particular fsobject. + */ +static +unsigned +count_subtree(struct fsobject *obj) +{ + struct fsdirent *de; + unsigned ret = 1; + + if (obj->isdir) { + for (de = obj->obj_dir.entries; de != NULL; de = de->next) { + ret += count_subtree(de->obj); + } + } + return ret; +} + +/* + * Compare two fsobjects. Return the matching score. (lower scores are + * better matches) + */ +static +unsigned +compare_objects(struct fsobject *obja, struct fsobject *objb) +{ + struct fsdirent *enta, *entb; + unsigned ret, found; + + if (obja->isdir != objb->isdir) { + /* + * One object's a file, the other's a directory. + * + * Return one point for each name in the missing + * subtree. This includes one point for the top dir, + * which is mismatched rather than missing. + */ + if (obja->isdir) { + return count_subtree(obja); + } + assert(objb->isdir); + return count_subtree(objb); + } + + if (!obja->isdir) { + /* + * Both objects are files + */ + assert(!objb->isdir); + if (obja->obj_file.len != objb->obj_file.len) { + /* one point for the size being different */ + return 1; + } + return 0; + } + + /* + * Both objects are directories. Recurse on all pairs of + * entries that have the same name. Return one point for each + * name that's present (recursively) in one object but not the + * other. + * + * XXX: sort the entries first or something instead of naively + * searching 2*N^2 times. + */ + assert(obja->isdir); + assert(objb->isdir); + + ret = 0; + for (enta = obja->obj_dir.entries; enta != NULL; enta = enta->next) { + found = 0; + for (entb = objb->obj_dir.entries; entb != NULL; + entb = entb->next) { + if (enta->name == entb->name) { + ret += compare_objects(enta->obj, entb->obj); + found = 1; + break; + } + } + if (!found) { + if (enta->obj->isdir) { + /* whole subtree is missing */ + ret += count_subtree(enta->obj); + } + /* one file is missing */ + ret += 1; + } + } + + + for (entb = objb->obj_dir.entries; entb != NULL; entb = entb->next) { + found = 0; + for (enta = obja->obj_dir.entries; enta != NULL; + enta = enta->next) { + if (enta->name == entb->name) { + found = 1; + break; + } + } + if (!found) { + if (entb->obj->isdir) { + /* whole subtree is missing */ + ret += count_subtree(entb->obj); + } + /* one file is missing */ + ret += 1; + } + } + + return ret; +} + +/* + * Print an indentation. + */ +static +void +doindent(unsigned depth) +{ + unsigned i; + + for (i=0; iisdir); + assert(objb->isdir); + + for (enta = obja->obj_dir.entries; enta != NULL; enta = enta->next) { + found = 0; + for (entb = objb->obj_dir.entries; entb != NULL; + entb = entb->next) { + if (enta->name == entb->name) { + doindent(indent); + printf("%s", name_get(enta->name)); + if (enta->obj->isdir && + !entb->obj->isdir) { + printf(": expected dir, found file;"); + printf(" %u names missing.\n", + count_subtree(enta->obj) - 1); + } + else if (!enta->obj->isdir && + entb->obj->isdir) { + printf(": expected file, found dir;"); + printf(" %u extra names.\n", + count_subtree(entb->obj) - 1); + } + else if (!enta->obj->isdir && + !entb->obj->isdir) { + off_t alen, blen; + + alen = enta->obj->obj_file.len; + blen = entb->obj->obj_file.len; + if (alen == blen) { + printf("\t\t%lld bytes (ok)\n", + alen); + } + else { + printf(": found %lld bytes, " + "expected %lld " + "bytes.\n", + blen, alen); + } + } + else { + printf("/\n"); + printdiffs(indent + 1, + enta->obj, entb->obj); + } + found = 1; + break; + } + } + if (!found) { + doindent(indent); + printf("%s: missing ", name_get(enta->name)); + if (enta->obj->isdir) { + printf("subtree with %u names.\n", + count_subtree(enta->obj) - 1); + } + else { + printf("file\n"); + } + } + } + + + for (entb = objb->obj_dir.entries; entb != NULL; entb = entb->next) { + found = 0; + for (enta = obja->obj_dir.entries; enta != NULL; + enta = enta->next) { + if (enta->name == entb->name) { + found = 1; + break; + } + } + if (!found) { + doindent(indent); + printf("%s: extra ", name_get(entb->name)); + if (entb->obj->isdir) { + printf("subtree with %u names.\n", + count_subtree(entb->obj) - 1); + } + else { + printf("file\n"); + } + } + } +} + +//////////////////////////////////////////////////////////// +// comparison of file contents + +/* + * Return the version of the oldest change with the same directory + * structure as CHANGE. This skips past truncate and write operations + * that only change file sizes. + */ +static +unsigned +findokversion(struct fschange *change) +{ + while (change != NULL) { + switch (change->type) { + case FC_TRUNCATE: + case FC_WRITE: + break; + default: + return change->version; + } + change = change->prev; + } + assert(0); + return 0; +} + +/* + * Back up to previous change entries until we find one affecting the + * contents of the specified file. (That means: truncate, write, or + * create.) + * + * Returns the current (passed-in) change if that matches. + */ +static +struct fschange * +backup_for_file(struct fschange *change, unsigned filenum) +{ + while (change != NULL) { + switch (change->type) { + case FC_TRUNCATE: + if (change->fc_truncate.file == filenum) { + return change; + } + break; + case FC_WRITE: + if (change->fc_write.file == filenum) { + return change; + } + break; + case FC_CREAT: + if (change->fc_creat.newfile == filenum) { + return change; + } + break; + default: + break; + } + change = change->prev; + } + return NULL; +} + +/* + * Expect zeros in a file from START to END. The file is given by FD + * and named NAMESTR. Report if we find stuff other than zeros. + */ +static +void +checkfilezeros(int fd, const char *namestr, off_t start, off_t end) +{ + char buf[1024]; + size_t len, i; + ssize_t ret; + unsigned poison = 0, trash = 0; + off_t origstart = start; + + printf(" %lld - %lld (expecting zeros)\n", start, end); + + if (lseek(fd, start, SEEK_SET) == -1) { + err(1, "%s: lseek to %lld", namestr, start); + } + while (start < end) { + /* XXX this assumes end - start fits in size_t */ + len = end - start; + if (len > sizeof(buf)) { + len = sizeof(buf); + } + ret = read(fd, buf, len); + if (ret == -1) { + err(1, "%s: read %u at %lld", namestr, len, start); + } + if (ret == 0) { + errx(1, "%s: read %u at %lld: Unexpected EOF", + namestr, len, start); + } + for (i=0; i<(size_t)ret; i++) { + if ((unsigned char)buf[i] == POISON_VAL) { + poison++; + } + else if (buf[i] != 0) { + trash++; + } + } + start += ret; + } + if (poison > 0 || trash > 0) { + printf("ERROR: File %s: expected zeros from %lld to %lld; " + "found", + namestr, origstart, end); + if (poison > 0) { + printf(" %u poison bytes", poison); + if (trash > 0) { + printf(" and"); + } + } + if (trash > 0) { + printf(" %u trash bytes", trash); + } + printf("\n"); + } +} + +/* + * Read data in from a file, into data.c's read buffer where it will + * be checked for correctness. The data.c region involved is + * REGIONSTART..REGIONEND; all of that space is needed so the expected + * data can be generated correctly. However, we're only looking at the + * range CHECKSTART..CHECKEND, which may be only part of the data.c + * region. + */ +static +void +readfiledata(int fd, const char *namestr, + off_t regionstart, off_t checkstart, + off_t checkend, off_t regionend) +{ + char *readbuf; + size_t bufpos, len; + ssize_t ret; + + /* CHECKSTART..CHECKEND must be within REGIONSTART..REGIONEND */ + assert(regionstart <= checkstart); + assert(checkstart <= checkend); + assert(checkend <= regionend); + + readbuf = data_mapreadbuf(regionend - regionstart); + bufpos = checkstart - regionstart; + len = checkend - checkstart; + if (lseek(fd, checkstart, SEEK_SET) == -1) { + err(1, "%s: lseek to %lld", namestr, checkstart); + } + + while (len > 0) { + ret = read(fd, readbuf + bufpos, len); + if (ret == -1) { + err(1, "%s: read %u at %lld", + namestr, len, regionstart + bufpos); + } + if (ret == 0) { + errx(1, "%s: read %u at %lld: Unexpected EOF", + namestr, len, regionstart + bufpos); + } + bufpos += ret; + assert(len >= (size_t)ret); + len -= ret; + } +} + +/* + * Check the data found in the file FD named NAMESTR, in the range + * CHECKSTART..CHECKEND, which is within or equal to the data.c + * region REGIONSTART..REGIONEND. ZEROSTART is the place where the + * data can legitimately be zeroed rather than the expected data + * (the portion of a write that extended a file) and the data is + * generated from CODE and SEQ. + */ +static +void +checkfiledata(int fd, const char *namestr, unsigned code, unsigned seq, + off_t zerostart, + off_t regionstart, off_t checkstart, + off_t checkend, off_t regionend) +{ + if (checkstart < regionstart) { + checkstart = regionstart; + } + if (checkend > regionend) { + checkend = regionend; + } + + printf(" %lld - %lld\n", checkstart, checkend); + + readfiledata(fd, namestr, + regionstart, checkstart, checkend, regionend); + + data_check(namestr, regionstart, + code, seq, zerostart - regionstart, regionend - regionstart, + checkstart - regionstart, checkend - checkstart); +} + +/* + * Check a range of the file FD named NAMESTR, from START to END, + * against the model state expected as of CHANGE. + */ +static +void +checkfilerange(int fd, const char *namestr, struct fschange *change, + off_t start, off_t end) +{ + assert(start < end); + if (change->type == FC_TRUNCATE) { + off_t tlen; + struct fschange *prev; + + /* + * The most recent change was a truncate. Anything + * beyond the truncate length should read as zeroes; + * recurse on the part before (if any) using the + * previous change affecting this file. + * + * We might be checking that a chunk of the file + * beyond the truncate length is zero (even though as + * of this change it's past EOF) if a later change + * made that region into a hole in a sparse file. + */ + + tlen = change->fc_truncate.len; + prev = change->fc_truncate.prev_thisfile; + + if (tlen < start) { + checkfilezeros(fd, namestr, start, end); + } + else if (tlen < end) { + checkfilerange(fd, namestr, prev, start, tlen); + checkfilezeros(fd, namestr, tlen, end); + } + else { + checkfilerange(fd, namestr, prev, start, end); + } + } + else if (change->type == FC_WRITE) { + off_t wstart, wend; + struct fschange *prev; + unsigned code, seq; + off_t oldfilesize, zerostart; + + /* + * The most recent change was a write. + */ + + wstart = change->fc_write.pos; + wend = change->fc_write.pos + change->fc_write.len; + prev = change->fc_write.prev_thisfile; + code = change->fc_write.code; + seq = change->fc_write.seq; + oldfilesize = change->fc_write.oldfilesize; + + /* + * ZEROSTART (where we begin to allow the file to + * contain zeros) should be the point at the write + * where we began to extend the file, if any. + */ + if (oldfilesize < wstart) { + zerostart = wstart; + } + else if (oldfilesize < wend) { + zerostart = oldfilesize; + } + else { + zerostart = wend; + } + + /* + * Six cases for the range overlap: + * (1) (2) (3) (4) (5) (6) + * ** *** ****** * *** ** + * *** *** *** *** *** *** + * + * We call checkfilerange recursively using the + * previous change for this file for the + * non-overlapping parts, because this write didn't + * touch those so they must reflect the previous file + * state; and checkfiledata for the overlapping parts + * that this write did touch. + */ + + if (end <= wstart || start >= wend) { + /* cases 1 and 6 */ + checkfilerange(fd, namestr, prev, start, end); + } + else { + /* cases 2-5 */ + if (start < wstart) { + /* case 2 or 3 */ + checkfilerange(fd, namestr, prev, + start, wstart); + } + checkfiledata(fd, namestr, code, seq, zerostart, + wstart, start, end, wend); + if (end > wend) { + /* cases 3 or 5 */ + checkfilerange(fd, namestr, prev, wend, end); + } + } + } + else if (change->type == FC_RENAMEFILE) { + struct fschange *prev; + + /* + * The most recent change was a rename. As rename + * doesn't affect contents, recurse on the previous + * change affecting the file. + */ + + prev = change->fc_renamefile.prev_movedfile; + checkfilerange(fd, namestr, prev, start, end); + } + else { + assert(change->type == FC_CREAT); + + /* + * The most recent change was the file being created. + * Like with truncate, check that the range is zero + * even though it's past EOF, as a later write might + * have converted past-EOF space into a hole in a + * sparse file. + */ + checkfilezeros(fd, namestr, start, end); + } +} + +/* + * Check if a change CHANGE to a file is present in the observed file + * FD, whose name is NAMESTR and size is FILESIZE. + * + * For writes it checks the data, so should be accurate; for truncate + * all it can check is the size, so it can readily be fooled by + * sequences of truncates or multiple truncates to the same length. + */ +static +int +change_is_present(int fd, const char *namestr, off_t filesize, + struct fschange *change) +{ + off_t pos, len, oldfilesize, zerostart; + unsigned code, seq; + + switch (change->type) { + case FC_TRUNCATE: + return filesize == change->fc_truncate.len; + case FC_WRITE: + pos = change->fc_write.pos; + len = change->fc_write.len; + code = change->fc_write.code; + seq = change->fc_write.seq; + oldfilesize = change->fc_write.oldfilesize; + if (oldfilesize < pos) { + zerostart = 0; + } + else if (oldfilesize < pos + len) { + zerostart = oldfilesize - pos; + } + else { + zerostart = len; + } + readfiledata(fd, namestr, pos, pos, pos+len, pos+len); + return data_matches(namestr, pos, + code, seq, zerostart, len, 0, len); + case FC_CREAT: + return 1; + default: + break; + } + assert(0); + return 0; +} + +/* + * Check the contents of the file called NAMESTR, which is the model + * file FILE, as of change CHANGE. + */ +static +void +checkonefilecontents(const char *namestr, struct fsobject *file, + struct fschange *change) +{ + unsigned okversion; + int fd; + + /* + * Open the file. + */ + + assert(!file->isdir); + + fd = open(namestr, O_RDONLY); + if (fd < 0) { + err(1, "%s: open", namestr); + } + + /* + * Find the oldest version that has the same directory + * structure as CHANGE, and thus reflects the earliest + * contents we can legitimately find in the file. + * + * XXX: the matching we do to pick the change to examine takes + * file sizes into account, but findokversion specifically + * doesn't stop going backwards if just the file size changes. + * This seems wrong: if we match on file size, ok versions to + * see are only those that have the same file size. + */ + okversion = findokversion(change); + + /* + * Find the first change (going backwards) that affects this + * file. There should always be at least the create. This + * change might be before or after OKVERSION. + */ + change = backup_for_file(change, file->obj_file.identity); + if (change == NULL) { + die("File %s was never even created?", namestr); + } + + if (file->obj_file.len == 0) { + /* + * The model expects the length to be 0. + * + * XXX: I think the code here was written thinking + * FILE is from the inspection results; but it's not, + * it's the model from the workload replay. So these + * checks appear to be wrong. + */ + if (change->type == FC_CREAT) { + /* file was created empty and never written to */ + return; + } + if (change->type == FC_TRUNCATE) { + /* if the length is wrong we shouldn't get this far */ + assert(change->fc_truncate.len == 0); + + /* so, nothing to check */ + close(fd); + return; + } + assert(change->type == FC_WRITE); + printf("ERROR: File %s is zero length but was expected to " + "contain at least %lld bytes at offset %lld!\n", + namestr, change->fc_write.pos, change->fc_write.len); + close(fd); + return; + } + + /* XXX: this check is wrong too. */ + if (change->type == FC_CREAT) { + printf("ERROR: File %s was never written to but has " + "length %lld\n", + namestr, file->obj_file.len); + close(fd); + return; + } + + /* + * If CHANGE isn't reflected in the file, back up. If this + * causes us to back up past OKVERSION, complain that the + * change should be present. + * + * XXX: the call to change_is_present should be using the + * observed file size, not the modeled file size. + * + * XXX: More seriously, however, this logic is not really + * right. If the workload contains multiple writes that don't + * affect the file length, interspersed with truncates that + * are all to the same length, we'll stop looking back at the + * first truncate (because the length matches) regardless of + * which writes are present. None of the workloads currently + * does anything like this, but it's still wrong. + * + * I think the right thing to do (especially since the version + * matching checks file lengths) is to check only writes for + * presence and ignore truncates; and probably, rather than + * back up based on what writes appear to be present and then + * call checkfilerange, which will then complain loudly if + * parts of an older write didn't make it out, divide the file + * into ranges based on blocks and writes and figure out which + * version the data found in each such range corresponds to, + * then object only to the ones that are crazy and warn about + * ones that reflect data buffers not making it out. But this + * is a fairly big rewrite. + */ + while (!change_is_present(fd, namestr, file->obj_file.len, change)) { + if (change->version < okversion) { + printf("File %s: change for version %u is missing\n", + namestr, change->version); + } + change = backup_for_file(change->prev,file->obj_file.identity); + if (change == NULL) { + printf("File %s: no matching version found\n", + namestr); + close(fd); + return; + } + } + + /* + * Now we've found a version that we think the file contents + * should correspond to; check that it's what we actually + * have. + * + * XXX: should this use the model length or the observed + * length? + */ + + checkfilerange(fd, namestr, change, 0, file->obj_file.len); + close(fd); +} + +/* + * Check the contents of all files under DIR with respect to the + * change CHANGE. Recurses on subdirectories. + */ +static +void +checkallfilecontents(struct fsobject *dir, struct fschange *change) +{ + struct fsdirent *de; + const char *namestr; + + assert(dir->isdir); + for (de = dir->obj_dir.entries; de != NULL; de = de->next) { + namestr = name_get(de->name); + if (de->obj->isdir) { + printf(" >>> Entering %s\n", namestr); + if (chdir(namestr)) { + err(1, "%s: chdir", namestr); + } + checkallfilecontents(de->obj, change); + printf(" <<< Leaving %s\n", namestr); + if (chdir("..")) { + err(1, "..: chdir"); + } + } + else { + printf("%s...\n", namestr); + checkonefilecontents(namestr, de->obj, change); + } + } +} + +//////////////////////////////////////////////////////////// +// model validation + +/* + * Compare the on-disk state we see to the model we've built. + */ +void +checkfs(void) +{ + struct fschange *change, *best; + unsigned score, bestscore; + + /* + * We just built the model; talk about it. + */ + printf("Established %u versions across %u directories and %u files\n", + changes->version + 1, nextdirnum, nextfilenum); + + /* + * Inspect the volume state we've got. Initializes the global + * FOUND holding the found volume state. + */ + inspectfs(); + printf("Found %u subdirs and %u files on the volume\n", + found_subdirs, found_files); + + /* + * Rewind the model state to the beginning. + */ + rewindstate(); + + /* + * Loop through all the changes; apply each one to the model + * state, and score the model state against the found state. + * Keep track of the best matching version. + * + * XXX: there might be several versions with the same score, + * in which case we'll blindly take the most recent one. If + * there are several versions that match exactly (which can + * easily happen for workloads that don't explicitly avoid it) + * we'll also blindly take the most recent one, and then the + * matching of file contents can blow up. We should collect + * all the versions with the same score, and score each one + * on file contents too. Or something like that. + */ + + change = firstchange; + assert(change->type == FC_NEWFS); + best = NULL; + bestscore = 0; + + while (change != NULL) { + apply_change(state, change); + score = compare_objects(state, found); + if (best == NULL || score <= bestscore) { + best = change; + bestscore = score; + } + //printf("version %u score %u\n", change->version, score); + change = change->next; + } + assert(best != NULL); + + /* + * Set the model state to the best matching state we found. + */ + + rewindstate(); + advancestateto(best); + + if (bestscore > 0) { + /* + * We didn't get an exact match, so print how the + * differences. XXX: this results in not checking file + * data... + */ + printf("FAILURE: Directory tree does not match on any " + "version.\n"); + printf("Best version is %u; describing differences:\n", + best->version); + printdiffs(1, state, found); + return; + } + + /* + * Ok, we did get an exact match. Print it. + */ + + printf("Directory tree matched in version %u.\n", best->version); + if (best->partial) { + printf("WARNING: this is a version from a partially committed " + "operation.\n"); + } + + /* + * XXX we should check hard links here; that is, that all the + * files that are supposed to be hard links of each other are, + * and that no other files are randomly hardlinked. + * + * However, if things are wrong it should result in bad + * contents. It would be very unlikely for even a very broken + * filesystem to, on its own, copy files that are supposed to + * be hardlinked. + */ + + /* now check the file contents */ + + printf("Checking file contents...\n"); + checkallfilecontents(state, best); + printf("Done.\n"); +} diff --git a/userland/testbin/frack/check.h b/userland/testbin/frack/check.h new file mode 100644 index 0000000..c429180 --- /dev/null +++ b/userland/testbin/frack/check.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +int check_createfile(unsigned name); +int check_openfile(unsigned name); +void check_closefile(int handle, unsigned name); +void check_write(int handle, unsigned name, unsigned code, unsigned seq, + off_t pos, off_t len); +void check_truncate(int handle, unsigned name, off_t len); +void check_mkdir(unsigned name); +void check_rmdir(unsigned name); +void check_unlink(unsigned name); +void check_link(unsigned from, unsigned to); +void check_rename(unsigned from, unsigned to); +void check_renamexd(unsigned fromdir, unsigned from, + unsigned todir, unsigned to); +void check_chdir(unsigned name); +void check_chdirup(void); +void check_sync(void); + + +void check_setup(void); +void checkfs(void); diff --git a/userland/testbin/frack/data.c b/userland/testbin/frack/data.c new file mode 100644 index 0000000..dbaa26f --- /dev/null +++ b/userland/testbin/frack/data.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "data.h" + +/* + * XXX for now hardwire things we know about SFS + */ +#define BLOCKSIZE /*SFS_BLOCKSIZE*/ 512 + +static char databuf[DATA_MAXSIZE]; +static char readbuf[DATA_MAXSIZE]; + +static +void +prepdata(unsigned code, unsigned seq, char *buf, off_t len) +{ + char smallbuf[32]; + char letter; + size_t slen; + + snprintf(smallbuf, sizeof(smallbuf), "%u@%u\n", seq, code); + slen = strlen(smallbuf); + + while (len >= slen) { + memcpy(buf, smallbuf, slen); + buf += slen; + len -= slen; + } + if (len > 1) { + letter = 'A' + (code + seq) % 26; + memset(buf, letter, len - 1); + buf += len - 1; + } + if (len > 0) { + *buf = '\n'; + } +} + +static +int +matches_at(size_t start, size_t len) +{ + if (!memcmp(databuf + start, readbuf + start, len)) { + return 1; + } + return 0; +} + +static +int +byte_at(size_t start, size_t len, unsigned char val) +{ + size_t i; + + for (i=0; i 0); + assert(checklen <= len); + assert(checkstart >= 0 && checkstart < len); + assert(checkstart + checklen <= len); + assert(zerostart >= 0); + assert(zerostart <= len); + + prepdata(code, seq, databuf, len); + + ret = 1; + while (checklen > 0) { + /* check one block at a time */ + where = checkstart; + howmuch = BLOCKSIZE; + /* no more than is left to do */ + if (howmuch > checklen) { + howmuch = checklen; + } + /* if we stick over a block boundary, stop there */ + absend = regionoffset + where + howmuch; + slop = absend % BLOCKSIZE; + if (slop != 0 && slop < howmuch) { + howmuch -= slop; + } + /* if we go past the zerostart point, stop there */ + if (where < zerostart && where + howmuch > zerostart) { + howmuch = zerostart - where; + } + assert(howmuch > 0); + + if (matches_at(where, howmuch)) { + /* nothing */ + } + else if (zero_at(where, howmuch)) { + if (where >= zerostart) { + printf("WARNING: file %s range %lld-%lld is " + "zeroed\n", + namestr, regionoffset + where, + regionoffset + where + howmuch); + } + else { + ret = 0; + } + } + else if (poison_at(where, howmuch)) { + if (where >= zerostart) { + printf("ERROR: file %s range %lld-%lld is " + "poisoned\n", + namestr, regionoffset + where, + regionoffset + where + howmuch); + } + else { + ret = 0; + } + } + else { + ret = 0; + } + + checkstart += howmuch; + checklen -= howmuch; + } + return ret; +} + +void +data_check(const char *namestr, off_t regionoffset, + unsigned code, unsigned seq, off_t zerostart, off_t len, + off_t checkstart, off_t checklen) +{ + assert(zerostart >= 0); + assert(zerostart <= len); + + if (!data_matches(namestr, regionoffset, + code, seq, zerostart, len, checkstart, checklen)) { + printf("ERROR: file %s range %lld-%lld contains garbage\n", + namestr, regionoffset + checkstart, + regionoffset + checkstart + checklen); + } +} + +void * +data_map(unsigned code, unsigned seq, off_t len) +{ + assert(len <= DATA_MAXSIZE); + prepdata(code, seq, databuf, len); + return databuf; +} + +void * +data_mapreadbuf(off_t len) +{ + assert(len <= DATA_MAXSIZE); + return readbuf; +} diff --git a/userland/testbin/frack/data.h b/userland/testbin/frack/data.h new file mode 100644 index 0000000..6d5c15e --- /dev/null +++ b/userland/testbin/frack/data.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +void *data_map(unsigned code, unsigned seq, off_t len); +void *data_mapreadbuf(off_t len); +int data_matches(const char *namestr, off_t regionoffset, + unsigned code, unsigned seq, off_t zerostart, off_t len, + off_t checkstart, off_t checklen); +void data_check(const char *namestr, off_t regionoffset, + unsigned code, unsigned seq, off_t zerostart, off_t len, + off_t checkstart, off_t checklen); + +#define DATA_MAXSIZE 65536 +#define POISON_VAL 0xa9 diff --git a/userland/testbin/frack/do.c b/userland/testbin/frack/do.c new file mode 100644 index 0000000..059cf2c --- /dev/null +++ b/userland/testbin/frack/do.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "data.h" +#include "name.h" +#include "do.h" + +int +do_opendir(unsigned name) +{ + const char *namestr; + int fd; + + namestr = name_get(name); + fd = open(namestr, O_RDONLY); + if (fd < 0) { + err(1, "%s: opendir", namestr); + } + return fd; +} + +void +do_closedir(int fd, unsigned name) +{ + if (close(fd)) { + warn("%s: closedir", name_get(name)); + } +} + +int +do_createfile(unsigned name) +{ + const char *namestr; + int fd; + + namestr = name_get(name); + fd = open(namestr, O_WRONLY|O_CREAT|O_EXCL, 0664); + if (fd < 0) { + err(1, "%s: create", namestr); + } + printf("create %s\n", namestr); + return fd; +} + +int +do_openfile(unsigned name, int dotrunc) +{ + const char *namestr; + int fd; + + namestr = name_get(name); + fd = open(namestr, O_WRONLY | (dotrunc ? O_TRUNC : 0), 0664); + if (fd < 0) { + err(1, "%s: open", namestr); + } + return fd; +} + +void +do_closefile(int fd, unsigned name) +{ + if (close(fd)) { + warn("%s: close", name_get(name)); + } +} + +void +do_write(int fd, unsigned name, unsigned code, unsigned seq, + off_t pos, off_t len) +{ + off_t done = 0; + ssize_t ret; + char *buf; + const char *namestr; + + namestr = name_get(name); + buf = data_map(code, seq, len); + if (lseek(fd, pos, SEEK_SET) == -1) { + err(1, "%s: lseek to %lld", name_get(name), pos); + } + + while (done < len) { + ret = write(fd, buf + done, len - done); + if (ret == -1) { + err(1, "%s: write %lld at %lld", name_get(name), + len, pos); + } + done += ret; + } + + printf("write %s: %lld at %lld\n", namestr, len, pos); +} + +void +do_truncate(int fd, unsigned name, off_t len) +{ + const char *namestr; + + namestr = name_get(name); + if (ftruncate(fd, len) == -1) { + err(1, "%s: truncate to %lld", namestr, len); + } + printf("truncate %s: to %lld\n", namestr, len); +} + +void +do_mkdir(unsigned name) +{ + const char *namestr; + + namestr = name_get(name); + if (mkdir(namestr, 0775) == -1) { + err(1, "%s: mkdir", namestr); + } + printf("mkdir %s\n", namestr); +} + +void +do_rmdir(unsigned name) +{ + const char *namestr; + + namestr = name_get(name); + if (rmdir(namestr) == -1) { + err(1, "%s: rmdir", namestr); + } + printf("rmdir %s\n", namestr); +} + +void +do_unlink(unsigned name) +{ + const char *namestr; + + namestr = name_get(name); + if (remove(namestr) == -1) { + err(1, "%s: remove", namestr); + } + printf("remove %s\n", namestr); +} + +void +do_link(unsigned from, unsigned to) +{ + const char *fromstr, *tostr; + + fromstr = name_get(from); + tostr = name_get(to); + if (link(fromstr, tostr) == -1) { + err(1, "link %s to %s", fromstr, tostr); + } + printf("link %s %s\n", fromstr, tostr); +} + +void +do_rename(unsigned from, unsigned to) +{ + const char *fromstr, *tostr; + + fromstr = name_get(from); + tostr = name_get(to); + if (rename(fromstr, tostr) == -1) { + err(1, "rename %s to %s", fromstr, tostr); + } + printf("rename %s %s\n", fromstr, tostr); +} + +void +do_renamexd(unsigned fromdir, unsigned from, unsigned todir, unsigned to) +{ + char frombuf[64]; + char tobuf[64]; + + strcpy(frombuf, name_get(fromdir)); + strcat(frombuf, "/"); + strcat(frombuf, name_get(from)); + + strcpy(tobuf, name_get(todir)); + strcat(tobuf, "/"); + strcat(tobuf, name_get(to)); + + if (rename(frombuf, tobuf) == -1) { + err(1, "rename %s to %s", frombuf, tobuf); + } + printf("rename %s %s\n", frombuf, tobuf); +} + +void +do_chdir(unsigned name) +{ + const char *namestr; + + namestr = name_get(name); + if (chdir(namestr) == -1) { + err(1, "chdir: %s", namestr); + } + printf("chdir %s\n", namestr); +} + +void +do_chdirup(void) +{ + if (chdir("..") == -1) { + err(1, "chdir: .."); + } + printf("chdir ..\n"); +} + +void +do_sync(void) +{ + if (sync()) { + warn("sync"); + } + printf("sync\n"); + printf("----------------------------------------\n"); +} diff --git a/userland/testbin/frack/do.h b/userland/testbin/frack/do.h new file mode 100644 index 0000000..7726815 --- /dev/null +++ b/userland/testbin/frack/do.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +int do_opendir(unsigned name); +void do_closedir(int handle, unsigned name); +int do_createfile(unsigned name); +int do_openfile(unsigned name, int dotrunc); +void do_closefile(int handle, unsigned name); +void do_write(int handle, unsigned name, unsigned code, unsigned seq, + off_t pos, off_t len); +void do_truncate(int handle, unsigned name, off_t len); +void do_mkdir(unsigned name); +void do_rmdir(unsigned name); +void do_unlink(unsigned name); +void do_link(unsigned from, unsigned to); +void do_rename(unsigned from, unsigned to); +void do_renamexd(unsigned fromdir, unsigned from, unsigned todir, unsigned to); +void do_chdir(unsigned name); +void do_chdirup(void); +void do_sync(void); diff --git a/userland/testbin/frack/main.c b/userland/testbin/frack/main.c new file mode 100644 index 0000000..1a0c7e8 --- /dev/null +++ b/userland/testbin/frack/main.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +#include "workloads.h" +#include "main.h" + +struct workload { + const char *name; + const char *argname; + union { + void (*witharg)(const char *); + void (*noarg)(void); + } run; +}; + +#define WL(n) { .name = #n, .argname = NULL, .run.noarg = wl_##n } +#define WLA(n,a) { .name = #n, .argname = #a, .run.witharg = wl_##n } + +static const struct workload workloads[] = { + WLA(createwrite, size), + WLA(rewrite, size), + WLA(randupdate, size), + WLA(truncwrite, size), + WLA(makehole, size), + WLA(fillhole, size), + WLA(truncfill, size), + WLA(append, size), + WLA(trunczero, size), + WLA(trunconeblock, size), + WLA(truncsmallersize, size), + WLA(trunclargersize, size), + WLA(appendandtrunczero, size), + WLA(appendandtruncpartly, size), + WL(mkfile), + WL(mkdir), + WL(mkmanyfile), + WL(mkmanydir), + WL(mktree), + WLA(mkrandtree, seed), + WL(rmfile), + WL(rmdir), + WL(rmfiledelayed), + WL(rmfiledelayedappend), + WL(rmdirdelayed), + WL(rmmanyfile), + WL(rmmanyfiledelayed), + WL(rmmanyfiledelayedandappend), + WL(rmmanydir), + WL(rmmanydirdelayed), + WL(rmtree), + WLA(rmrandtree, seed), + WL(linkfile), + WL(linkmanyfile), + WL(unlinkfile), + WL(unlinkmanyfile), + WL(linkunlinkfile), + WL(renamefile), + WL(renamedir), + WL(renamesubtree), + WL(renamexdfile), + WL(renamexddir), + WL(renamexdsubtree), + WL(renamemanyfile), + WL(renamemanydir), + WL(renamemanysubtree), + WL(copyandrename), + WL(untar), + WL(compile), + WL(cvsupdate), + WLA(writefileseq, seed), + WLA(writetruncseq, seed), + WLA(mkrmseq, seed), + WLA(linkunlinkseq, seed), + WLA(renameseq, seed), + WLA(diropseq, seed), + WLA(genseq, seed), +}; +static const unsigned numworkloads = sizeof(workloads) / sizeof(workloads[0]); + +#undef WL +#undef WLA + +static +const struct workload * +findworkload(const char *name) +{ + unsigned i; + + for (i=0; iargname) { + if (argc != 4) { + errx(1, "%s requires argument %s\n", + workloadname, workload->argname); + } + workload->run.witharg(argv[3]); + } + else { + if (argc != 3) { + errx(1, "Stray argument for workload %s",workloadname); + } + workload->run.noarg(); + } + complete(); + return 0; +} diff --git a/userland/testbin/frack/main.h b/userland/testbin/frack/main.h new file mode 100644 index 0000000..7ccfb08 --- /dev/null +++ b/userland/testbin/frack/main.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +void setcheckmode(int checkmode); +void complete(void); diff --git a/userland/testbin/frack/name.c b/userland/testbin/frack/name.c new file mode 100644 index 0000000..88eff09 --- /dev/null +++ b/userland/testbin/frack/name.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include "name.h" + +#define MAXNAMES 32 + +static const char *const names[MAXNAMES] = { + "allspice", + "anise", + "basil", + "cardamom", + "cayenne", + "cilantro", + "cinnamon", + "cloves", + "coriander", + "cumin", + "dill", + "fennel", + "fenugreek", + "galangal", + "ginger", + "horseradish", + "lemongrass", + "licorice", + "mace", + "marjoram", + "mustard", + "nutmeg", + "oregano", + "parsley", + "paprika", + "pepper", + "saffron", + "sage", + "rosemary", + "thyme", + "turmeric", + "wasabi", +}; + +const char * +name_get(unsigned name) +{ + assert(name < MAXNAMES); + return names[name]; +} + +unsigned +name_find(const char *namestr) +{ + unsigned i; + + for (i=0; i +#include +#include +#include + +#include "pool.h" +#include "data.h" +#include "do.h" +#include "check.h" +#include "ops.h" +#include "main.h" + +struct file { + unsigned name; + unsigned testcode; + unsigned seq; + int handle; +}; + +struct dir { + unsigned name; + int handle; +}; + +static int checkmode; + +void +setcheckmode(int mode) +{ + checkmode = mode; + if (checkmode) { + check_setup(); + } +} + +//////////////////////////////////////////////////////////// +// open directories + +#define MAXDIRS 32 +DECLPOOL(dir, MAXDIRS); + +struct dir * +op_opendir(unsigned name) +{ + struct dir *ret; + + ret = POOLALLOC(dir); + ret->name = name; + if (checkmode) { + ret->handle = -1; + } + else { + ret->handle = do_opendir(name); + } + return ret; +} + +void +op_closedir(struct dir *d) +{ + if (checkmode) { + /* nothing */ + (void)d; + } + else { + do_closedir(d->handle, d->name); + } + POOLFREE(dir, d); +} + +//////////////////////////////////////////////////////////// +// files + +#define MAXFILES 32 +DECLPOOL(file, MAXFILES); + +struct file * +op_open(unsigned testcode, unsigned name, unsigned openflags) +{ + struct file *ret; + int dotrunc; + + if (openflags == O_TRUNC) { + openflags = 0; + dotrunc = 1; + } + else { + dotrunc = 0; + } + + assert(openflags == 0 || openflags == (O_CREAT|O_EXCL)); + + ret = POOLALLOC(file); + ret->name = name; + ret->testcode = testcode; + ret->seq = 0; + if (checkmode) { + if (openflags) { + ret->handle = check_createfile(name); + } + else { + ret->handle = check_openfile(name); + } + } + else { + if (openflags) { + assert(dotrunc == 0); + ret->handle = do_createfile(name); + } + else { + /* + * XXX: as of 2013 OS/161 doesn't provide a + * truncate call - neither truncate() nor + * ftruncate()! You can only O_TRUNC. Oops... + */ + ret->handle = do_openfile(name, dotrunc); + dotrunc = 0; + } + } + if (dotrunc) { + op_truncate(ret, 0); + } + return ret; +} + +void +op_close(struct file *f) +{ + if (checkmode) { + check_closefile(f->handle, f->name); + } + else { + do_closefile(f->handle, f->name); + } + POOLFREE(file, f); +} + +void +op_write(struct file *f, off_t pos, off_t len) +{ + off_t amount; + + while (len > 0) { + amount = len; + if (amount > DATA_MAXSIZE) { + amount = DATA_MAXSIZE; + } + + if (checkmode) { + check_write(f->handle, f->name, f->testcode, f->seq, + pos, amount); + } + else { + do_write(f->handle, f->name, f->testcode, f->seq, + pos, amount); + } + f->seq++; + pos += amount; + len -= amount; + } +} + +void +op_truncate(struct file *f, off_t len) +{ + if (checkmode) { + check_truncate(f->handle, f->name, len); + } + else { + do_truncate(f->handle, f->name, len); + } +} + +//////////////////////////////////////////////////////////// +// dirops + +void +op_mkdir(unsigned name) +{ + if (checkmode) { + check_mkdir(name); + } + else { + do_mkdir(name); + } +} + +void +op_rmdir(unsigned name) +{ + if (checkmode) { + check_rmdir(name); + } + else { + do_rmdir(name); + } +} + +void +op_unlink(unsigned name) +{ + if (checkmode) { + check_unlink(name); + } + else { + do_unlink(name); + } +} + +void +op_link(unsigned from, unsigned to) +{ + if (checkmode) { + check_link(from, to); + } + else { + do_link(from, to); + } +} + +void +op_rename(unsigned from, unsigned to) +{ + if (checkmode) { + check_rename(from, to); + } + else { + do_rename(from, to); + } +} + +void +op_renamexd(unsigned fromdir, unsigned from, unsigned todir, unsigned to) +{ + if (checkmode) { + check_renamexd(fromdir, from, todir, to); + } + else { + do_renamexd(fromdir, from, todir, to); + } +} + +void +op_chdir(unsigned name) +{ + if (checkmode) { + check_chdir(name); + } + else { + do_chdir(name); + } +} + +void +op_chdirup(void) +{ + if (checkmode) { + check_chdirup(); + } + else { + do_chdirup(); + } +} + +//////////////////////////////////////////////////////////// +// other + +void +op_sync(void) +{ + if (checkmode) { + check_sync(); + } + else { + do_sync(); + } +} + +void +complete(void) +{ + if (checkmode) { + checkfs(); + } +} diff --git a/userland/testbin/frack/ops.h b/userland/testbin/frack/ops.h new file mode 100644 index 0000000..0bab559 --- /dev/null +++ b/userland/testbin/frack/ops.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +struct file; +struct dir; + +struct dir *op_opendir(unsigned); +void op_closedir(struct dir *); +struct file *op_open(unsigned, unsigned, unsigned); +void op_close(struct file *); +void op_write(struct file *, off_t, off_t); +void op_truncate(struct file *, off_t); +void op_sync(void); +void op_mkdir(unsigned); +void op_rmdir(unsigned); +void op_unlink(unsigned); +void op_link(unsigned, unsigned); +void op_rename(unsigned, unsigned); +void op_renamexd(unsigned, unsigned, unsigned, unsigned); +void op_chdir(unsigned); +void op_chdirup(void); diff --git a/userland/testbin/frack/pool.c b/userland/testbin/frack/pool.c new file mode 100644 index 0000000..ceda9c3 --- /dev/null +++ b/userland/testbin/frack/pool.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include "pool.h" + +unsigned +poolalloc(struct poolctl *pool) +{ + uint32_t mask; + unsigned j, i; + + assert(pool->max % 32 == 0); + for (j=0; jmax/32; j++) { + for (mask=1, i=0; i<32; mask<<=1, i++) { + if ((pool->inuse[j] & mask) == 0) { + pool->inuse[j] |= mask; + return j*32 + i; + } + } + } + errx(1, "Too many %s -- increase %s in %s", + pool->itemtype, pool->maxname, pool->file); + return 0; +} + +void +poolfree(struct poolctl *pool, unsigned num) +{ + uint32_t mask; + unsigned pos; + + assert(num < pool->max); + + pos = num / 32; + mask = 1 << (num % 32); + + assert(pool->inuse[pos] & mask); + pool->inuse[pos] &= ~(uint32_t)mask; +} diff --git a/userland/testbin/frack/pool.h b/userland/testbin/frack/pool.h new file mode 100644 index 0000000..f24347f --- /dev/null +++ b/userland/testbin/frack/pool.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +struct poolctl { + uint32_t *inuse; + unsigned max; + const char *itemtype; + const char *maxname; + const char *file; +}; + +#define DIVROUNDUP(a, b) (((a) + (b) - 1) / (b)) +#define ROUNDUP(a, b) (DIVROUNDUP(a, b) * (b)) + +#define DECLPOOL(T, MAX) \ + static struct T pool_space_##T[ROUNDUP(MAX, 32)]; \ + static uint32_t pool_inuse_##T[DIVROUNDUP(MAX, 32)]; \ + static struct poolctl pool_##T = { \ + .inuse = pool_inuse_##T, \ + .max = ROUNDUP(MAX, 32), \ + .itemtype = "struct " #T, \ + .maxname = #MAX, \ + .file = __FILE__ \ + } + +#define POOLALLOC(T) (&pool_space_##T[poolalloc(&pool_##T)]) +#define POOLFREE(T, x) (poolfree(&pool_##T, (x) - pool_space_##T)) + +unsigned poolalloc(struct poolctl *pool); +void poolfree(struct poolctl *pool, unsigned ix); diff --git a/userland/testbin/frack/workloads.c b/userland/testbin/frack/workloads.c new file mode 100644 index 0000000..e7b33d3 --- /dev/null +++ b/userland/testbin/frack/workloads.c @@ -0,0 +1,1794 @@ +/* + * Copyright (c) 2013 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#if 0 /* XXX: should add this to libc */ +#include +#else +typedef unsigned bool; +#define false 0 +#define true 1 +#endif + +#include "ops.h" +#include "workloads.h" + +//////////////////////////////////////////////////////////// +// support code + +static +unsigned long +getnum(const char *str) +{ +#if 0 /* sigh */ + unsigned long val; + char *x; + + errno = 0; + val = strtoul(str, &x, 0); + if (errno) { + err(1, "Invalid number %s", str); + } + if (strlen(x) > 0) { + errx(1, "Invalid junk at end of number %s", str); + } + return val; +#else + return atoi(str); +#endif +} + +//////////////////////////////////////////////////////////// +// standard sizes + +enum sizes { + SIZE_ONE, + SIZE_SMALL, + SIZE_MEDIUM, + SIZE_LARGE, + SIZE_LARGEPLUS, +}; + +/* + * This only returns the sizes that can be selected from the command + * line. + */ +static +enum sizes +strtosize(const char *word) +{ + if (!strcmp(word, "small")) { + return SIZE_SMALL; + } + if (!strcmp(word, "medium")) { + return SIZE_MEDIUM; + } + if (!strcmp(word, "large")) { + return SIZE_LARGE; + } + errx(1, "Invalid size %s (try small, medium, or large)", word); + /* XXX errx should be declared noreturn */ + return SIZE_SMALL; +} + +static +enum sizes +randsize(void) +{ + switch (random() % 7) { + case 0: + return SIZE_ONE; + case 1: + case 2: + case 3: + return SIZE_SMALL; + case 4: + case 5: + return SIZE_MEDIUM; + case 6: +#if 0 /* too annoying */ + return SIZE_LARGE; +#else + return SIZE_MEDIUM; +#endif + } + return SIZE_ONE; +} + +static +enum sizes +nextsmallersize(enum sizes sz) +{ + switch (sz) { + case SIZE_ONE: + break; + case SIZE_SMALL: + return SIZE_ONE; + case SIZE_MEDIUM: + return SIZE_SMALL; + case SIZE_LARGE: + return SIZE_MEDIUM; + case SIZE_LARGEPLUS: + return SIZE_LARGE; + } + assert(0); + return SIZE_ONE; +} + +static +enum sizes +nextlargersize(enum sizes sz) +{ + switch (sz) { + case SIZE_ONE: + return SIZE_SMALL; + case SIZE_SMALL: + return SIZE_MEDIUM; + case SIZE_MEDIUM: + return SIZE_LARGE; + case SIZE_LARGE: + return SIZE_LARGEPLUS; + case SIZE_LARGEPLUS: + break; + } + assert(0); + return SIZE_LARGEPLUS; +} + +static +unsigned +sizeblocks(enum sizes sz) +{ + /* + * XXX for now hardwire things we know about SFS + */ +#define BLOCKSIZE /*SFS_BLOCKSIZE*/ 512 + static const unsigned ndb = /*SFS_NDIRECT*/ 15; + static const unsigned dbperidb = /*SFS_DBPERIDB*/ 128; + + switch (sz) { + case SIZE_ONE: + /* one block; 512 bytes */ + return 1; + case SIZE_SMALL: + /* fits in direct blocks only; 7.5K */ + return ndb; + case SIZE_MEDIUM: + /* uses an indirect block; ~40K */ + return ndb + dbperidb / 2; + case SIZE_LARGE: + /* uses a double-indirect block; 4.2M */ + return ndb + dbperidb + dbperidb * dbperidb / 2; + case SIZE_LARGEPLUS: + /* requires a triple-indirect block; 8.5M */ + return ndb + dbperidb + dbperidb * dbperidb + dbperidb / 2; + } + assert(0); + return 12; +} + +static +unsigned +sizebytes(enum sizes sz) +{ + return BLOCKSIZE * sizeblocks(sz); +} + +//////////////////////////////////////////////////////////// +// common suboperations + +static +void +file_randomwrite(struct file *f, enum sizes sz, + unsigned startskip, unsigned endskip) +{ + unsigned nblocks, nwrites, i; + unsigned blocknum; + off_t pos; + + nblocks = sizeblocks(sz); + assert(nblocks > startskip + endskip); + + nwrites = nblocks/6; + if (nwrites < 2) { + nwrites = 2; + } + + nblocks -= startskip + endskip; + for (i=0; i +static +void +wl_mktree_sub(unsigned testcode, unsigned depth) +{ + unsigned i, numthings = 4; + + for (i=0; i 0) { + return; + } + break; + case 2: + case 3: + writenewfile(testcode, numhere/*filenum*/, SIZE_ONE); + (*ct)++; + numhere++; + break; + } + } +} + +static +void +rmrandtree_sub(unsigned depth, unsigned *ct, unsigned numthings) +{ + unsigned numhere; + + numhere = 0; + while (*ct < numthings) { + switch (random() % 4) { + case 0: + (*ct)++; + op_chdir(numhere/*filenum*/); + rmrandtree_sub(depth + 1, ct, numthings); + op_chdirup(); + op_rmdir(numhere/*filenum*/); + numhere++; + break; + case 1: + if (depth > 0) { + return; + } + break; + case 2: + case 3: + op_unlink(numhere/*filenum*/); + (*ct)++; + numhere++; + break; + } + } +} + +void +wl_mkrandtree(const char *seed) +{ + unsigned testcode = 103; + unsigned numthings, count; + unsigned long seednum = getnum(seed); + + srandom(seednum); + numthings = random() % 44 + 12; + count = 0; + + mkrandtree_sub(testcode, 0, &count, numthings); +} + +//////////////////////////////////////////////////////////// +// deleting + +/* + * Delete a file. (We have to create the file first and sync it.) + */ +void +wl_rmfile(void) +{ + unsigned testcode = 150; + + writenewfile(testcode, 0/*filenum*/, SIZE_ONE); + writeemptyfile(1/*filenum*/); + op_sync(); + op_unlink(0/*filenum*/); +} + +/* + * Delete a directory. (We have to mkdir first and sync it.) + */ +void +wl_rmdir(void) +{ + op_mkdir(0/*filenum*/); + writeemptyfile(1/*filenum*/); + op_sync(); + op_rmdir(0/*filenum*/); +} + +/* + * Delete a file, with delayed reclaim. + * + * (Should there be a form of this that syncs after unlinking but + * before closing?) + */ +void +wl_rmfiledelayed(void) +{ + unsigned testcode = 151; + struct file *f; + + writenewfile(testcode, 0/*filenum*/, SIZE_ONE); + writeemptyfile(1/*filenum*/); + op_sync(); + f = op_open(testcode, 0/*filenum*/, 0); + op_unlink(0/*filenum*/); + op_close(f); +} + +/* + * Delete a file, with delayed reclaim, and append to the file before + * reclaiming. + */ +void +wl_rmfiledelayedappend(void) +{ + unsigned testcode = 152; + struct file *f; + enum sizes sz = SIZE_SMALL; + + writenewfile(testcode, 0/*filenum*/, sz); + writeemptyfile(1/*filenum*/); + op_sync(); + f = op_open(testcode, 0/*filenum*/, 0); + op_unlink(0/*filenum*/); + op_write(f, sizebytes(sz), 6 * BLOCKSIZE); + op_close(f); +} + +/* + * Delete a directory, with delayed reclaim. + */ +void +wl_rmdirdelayed(void) +{ + struct dir *d; + + op_mkdir(0/*filenum*/); + writeemptyfile(1/*filenum*/); + op_sync(); + d = op_opendir(0/*filenum*/); + op_rmdir(0/*filenum*/); + op_closedir(d); +} + +/* + * Delete many files. + */ +void +wl_rmmanyfile(void) +{ + unsigned testcode = 153; + unsigned numfiles = 27; + unsigned i; + + for (i=0; i +#include +#include +#include + +#ifdef HOST +#include "hostcompat.h" +#endif + +#define HASHP 104729 + +int +main(int argc, char *argv[]) +{ + int fd; + char readbuf[1]; + int j = 0; + +#ifdef HOST + hostcompat_init(argc, argv); +#endif + + if (argc != 2) { + errx(1, "Usage: hash filename"); + } + + fd = open(argv[1], O_RDONLY, 0664); + + if (fd<0) { + err(1, "%s", argv[1]); + } + + for (;;) { + if (read(fd, readbuf, 1) <= 0) break; + j = ((j*8) + (int) readbuf[0]) % HASHP; + } + + close(fd); + + printf("Hash : %d\n", j); + + return 0; +} diff --git a/userland/testbin/hog/Makefile b/userland/testbin/hog/Makefile new file mode 100644 index 0000000..9183691 --- /dev/null +++ b/userland/testbin/hog/Makefile @@ -0,0 +1,12 @@ +# Makefile for hog + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=hog +SRCS=hog.c +BINDIR=/testbin + + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/hog/hog.c b/userland/testbin/hog/hog.c new file mode 100644 index 0000000..9c6e2b5 --- /dev/null +++ b/userland/testbin/hog/hog.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * hog.c + * Spawned by several other user programs to test time-slicing. + * + * Loops consuming CPU cycles. + */ + +int +main(void) +{ + volatile int i; + volatile int k, l, m; + + k = 1283; + l = 53; + for (i=0; i<15000000; i++) { + l = m + k; + } + + // gcc 4.8 improperly demands this + (void)l; + + return 0; +} diff --git a/userland/testbin/huge/Makefile b/userland/testbin/huge/Makefile new file mode 100644 index 0000000..9288523 --- /dev/null +++ b/userland/testbin/huge/Makefile @@ -0,0 +1,11 @@ +# Makefile for huge + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=huge +SRCS=huge.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/huge/huge.c b/userland/testbin/huge/huge.c new file mode 100644 index 0000000..600118c --- /dev/null +++ b/userland/testbin/huge/huge.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * huge.c + * + * Tests the VM system by accessing a large array (sparse) that + * cannot fit into memory. + * + * When the VM system assignment is done, your system should be able + * to run this successfully. + */ + +#include +#include + +#define PageSize 4096 +#define NumPages 512 + +int sparse[NumPages][PageSize]; /* use only the first element in the row */ + +int +main(void) +{ + int i,j; + + printf("Entering the huge program - I will stress test your VM\n"); + + /* move number in so that sparse[i][0]=i */ + for (i=0; i=0; i--) { + if (sparse[i][0]!=i+5) { + printf("BAD NEWS!!! - your VM mechanism has a bug!\n"); + exit(1); + } + } + + printf("You passed!\n"); + + return 0; +} + diff --git a/userland/testbin/malloctest/Makefile b/userland/testbin/malloctest/Makefile new file mode 100644 index 0000000..c1f1d5b --- /dev/null +++ b/userland/testbin/malloctest/Makefile @@ -0,0 +1,11 @@ +# Makefile for malloctest + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=malloctest +SRCS=malloctest.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/malloctest/malloctest.c b/userland/testbin/malloctest/malloctest.c new file mode 100644 index 0000000..5f3d4bf --- /dev/null +++ b/userland/testbin/malloctest/malloctest.c @@ -0,0 +1,694 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * malloctest.c + * + * This program contains a variety of tests for malloc and free. + * XXX: most tests leak on error. + * + * These tests (subject to restrictions and limitations noted below) + * should work once the kernel provides sbrk(). + * + * Note that because the userlevel malloc is extremely dumb, + * malloctest 3 is extremely slow and on most VM systems will run more + * or less forever. + */ + +#include +#include +#include +#include +#include +#include +#include + + +#define _PATH_RANDOM "random:" + +#define SMALLSIZE 72 +#define MEDIUMSIZE 896 +#define BIGSIZE 16384 +#define HUGESIZE (1024 * 1024 * 1024) + +/* Maximum amount of space per block we allow for indexing structures */ +#define OVERHEAD 32 + +/* Point past which we assume something else is going on */ +#define ABSURD_OVERHEAD 256 + +static +int +geti(void) +{ + int val=0; + int ch, digits=0; + + while (1) { + ch = getchar(); + if (ch=='\n' || ch=='\r') { + putchar('\n'); + break; + } + else if ((ch=='\b' || ch==127) && digits>0) { + printf("\b \b"); + val = val/10; + digits--; + } + else if (ch>='0' && ch<='9') { + putchar(ch); + val = val*10 + (ch-'0'); + digits++; + } + else { + putchar('\a'); + } + } + + if (digits==0) { + return -1; + } + return val; +} + +//////////////////////////////////////////////////////////// + +/* + * Fill a block of memory with a test pattern. + */ +static +void +markblock(volatile void *ptr, size_t size, unsigned bias, int doprint) +{ + size_t n, i; + unsigned long *pl; + unsigned long val; + + pl = (unsigned long *)ptr; + n = size / sizeof(unsigned long); + + for (i=0; inext = list; + list = tmp; + + tot += sizeof(struct test3); + + markblock(list->junk, sizeof(list->junk), (uintptr_t)list, 0); + + ct++; + if (ct%128==0) { + printf("."); + } + } + + printf("Allocated %lu bytes\n", (unsigned long) tot); + + printf("Trying some more allocations which I expect to fail...\n"); + + x = malloc(SMALLSIZE); + if (x != NULL) { + printf("FAILED: malloc(%u) succeeded\n", SMALLSIZE); + return; + } + + x = malloc(MEDIUMSIZE); + if (x != NULL) { + printf("FAILED: malloc(%u) succeeded\n", MEDIUMSIZE); + return; + } + + x = malloc(BIGSIZE); + if (x != NULL) { + printf("FAILED: malloc(%u) succeeded\n", BIGSIZE); + return; + } + + printf("Ok, now I'm going to free everything...\n"); + + while (list != NULL) { + tmp = list->next; + + if (checkblock(list->junk, sizeof(list->junk), + (uintptr_t)list, 0)) { + failed = 1; + } + + free(list); + list = tmp; + } + + if (failed) { + printf("FAILED: data corruption\n"); + return; + } + + printf("Let me see if I can allocate some more now...\n"); + + x = malloc(MEDIUMSIZE); + if (x == NULL) { + printf("FAIL: Nope, I couldn't.\n"); + return; + } + free(x); + + printf("Passed malloc test 3\n"); +} + +//////////////////////////////////////////////////////////// + +/* + * Test 4 + * + * Tries to test in detail if malloc coalesces the free list properly. + * + * This test will likely fail if something other than a basic first-fit/ + * next-fit/best-fit algorithm is used. + */ + +static +void +test4(void) +{ + void *x, *y, *z; + unsigned long lx, ly, lz, overhead, zsize; + + printf("Entering malloc test 4.\n"); + printf("This test is intended for first/best-fit based mallocs.\n"); + printf("This test may not work correctly if run after other tests.\n"); + + printf("Testing free list coalescing:\n"); + + x = malloc(SMALLSIZE); + if (x==NULL) { + printf("FAILED: malloc(%u) failed\n", SMALLSIZE); + return; + } + + y = malloc(MEDIUMSIZE); + if (y==NULL) { + printf("FAILED: malloc(%u) failed\n", MEDIUMSIZE); + return; + } + + if (sizeof(unsigned long) < sizeof(void *)) { + printf("Buh? I can't fit a void * in an unsigned long\n"); + printf("ENVIRONMENT FAILED...\n"); + return; + } + + lx = (unsigned long)x; + ly = (unsigned long)y; + + printf("x is 0x%lx; y is 0x%lx\n", lx, ly); + + /* + * The memory should look something like this: + * + * OXXXOYYYYYYYYYYY + * + * where O are optional overhead (indexing) blocks. + */ + + /* This is obviously wrong. */ + if (lx == ly) { + printf("FAIL: x == y\n"); + return; + } + + /* + * Check for overlap. It is sufficient to check if the start + * of each block is within the other block. (If the end of a + * block is within the other block, either the start is too, + * or the other block's start is within the first block.) + */ + if (lx < ly && lx + SMALLSIZE > ly) { + printf("FAIL: y starts within x\n"); + return; + } + if (ly < lx && ly + MEDIUMSIZE > lx) { + printf("FAIL: x starts within y\n"); + return; + } + + /* + * If y is lower than x, some memory scheme we don't + * understand is in use, or else there's already stuff on the + * free list. + */ + if (ly < lx) { + printf("TEST UNSUITABLE: y is below x\n"); + return; + } + + /* + * Compute the space used by index structures. + */ + overhead = ly - (lx + SMALLSIZE); + printf("Apparent block overhead: %lu\n", overhead); + + if (overhead > ABSURD_OVERHEAD) { + printf("TEST UNSUITABLE: block overhead absurdly large.\n"); + return; + } + if (overhead > OVERHEAD) { + printf("FAIL: block overhead is too large.\n"); + return; + } + + printf("Freeing blocks...\n"); + free(x); + free(y); + + zsize = SMALLSIZE + MEDIUMSIZE + overhead; + + printf("Now allocating %lu bytes... should reuse the space.\n", zsize); + z = malloc(zsize); + if (z == NULL) { + printf("FAIL: Allocation failed...\n"); + return; + } + + lz = (unsigned long) z; + + printf("z is 0x%lx (x was 0x%lx, y 0x%lx)\n", lz, lx, ly); + + if (lz==lx) { + printf("Passed.\n"); + } + else { + printf("Failed.\n"); + } + + free(z); +} + +//////////////////////////////////////////////////////////// + +/* + * Test 5/6/7 + * + * Generally beats on malloc/free. + * + * Test 5 uses random seed 0. + * Test 6 seeds the random number generator from random:. + * Test 7 asks for a seed. + */ + +static +void +test567(int testno, unsigned long seed) +{ + static const int sizes[8] = { 13, 17, 69, 176, 433, 871, 1150, 6060 }; + + void *ptrs[32]; + int psizes[32]; + int i, n, size, failed=0; + + srandom(seed); + printf("Seeded random number generator with %lu.\n", seed); + + for (i=0; i<32; i++) { + ptrs[i] = NULL; + psizes[i] = 0; + } + + for (i=0; i<100000; i++) { + n = random()%32; + if (ptrs[n] == NULL) { + size = sizes[random()%8]; + ptrs[n] = malloc(size); + psizes[n] = size; + if (ptrs[n] == NULL) { + printf("\nmalloc %u failed\n", size); + failed = 1; + break; + } + markblock(ptrs[n], size, n, 0); + } + else { + size = psizes[n]; + if (checkblock(ptrs[n], size, n, 0)) { + failed = 1; + break; + } + free(ptrs[n]); + ptrs[n] = NULL; + psizes[n] = 0; + } + if (i%256==0) { + printf("."); + } + } + printf("\n"); + + for (i=0; i<32; i++) { + if (ptrs[i] != NULL) { + free(ptrs[i]); + } + } + + if (failed) { + printf("FAILED malloc test %d\n", testno); + } + else { + printf("Passed malloc test %d\n", testno); + } +} + +static +void +test5(void) +{ + printf("Beginning malloc test 5\n"); + test567(5, 0); +} + +static +void +test6(void) +{ + int fd, len; + unsigned long seed; + + printf("Beginning malloc test 6\n"); + + fd = open(_PATH_RANDOM, O_RDONLY); + if (fd < 0) { + err(1, "%s", _PATH_RANDOM); + } + len = read(fd, &seed, sizeof(seed)); + if (len < 0) { + err(1, "%s", _PATH_RANDOM); + } + else if (len < (int)sizeof(seed)) { + errx(1, "%s: Short read", _PATH_RANDOM); + } + close(fd); + + test567(6, seed); +} + +static +void +test7(void) +{ + unsigned long seed; + + printf("Beginning malloc test 7\n"); + + printf("Enter random seed: "); + seed = geti(); + + test567(7, seed); +} + +//////////////////////////////////////////////////////////// + +static struct { + int num; + const char *desc; + void (*func)(void); +} tests[] = { + { 1, "Simple allocation test", test1 }, + { 2, "Allocate all memory in a big chunk", test2 }, + { 3, "Allocate all memory in small chunks", test3 }, + { 4, "Free list coalescing test (first/next/best-fit only)", test4 }, + { 5, "Stress test", test5 }, + { 6, "Randomized stress test", test6 }, + { 7, "Stress test with particular seed", test7 }, + { -1, NULL, NULL } +}; + +static +int +dotest(int tn) +{ + int i; + for (i=0; tests[i].num>=0; i++) { + if (tests[i].num == tn) { + tests[i].func(); + return 0; + } + } + return -1; +} + +int +main(int argc, char *argv[]) +{ + int i, tn, menu=1; + + if (argc > 1) { + for (i=1; i=0; i++) { + printf(" %2d %s\n", tests[i].num, + tests[i].desc); + } + menu = 0; + } + printf("malloctest: "); + tn = geti(); + if (tn < 0) { + break; + } + + if (dotest(tn)) { + menu = 1; + } + } + + return 0; +} + diff --git a/userland/testbin/matmult/Makefile b/userland/testbin/matmult/Makefile new file mode 100644 index 0000000..f67d49f --- /dev/null +++ b/userland/testbin/matmult/Makefile @@ -0,0 +1,12 @@ +# Makefile for matmult + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=matmult +SRCS=matmult.c +BINDIR=/testbin + + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/matmult/matmult-orig.c b/userland/testbin/matmult/matmult-orig.c new file mode 100644 index 0000000..b707347 --- /dev/null +++ b/userland/testbin/matmult/matmult-orig.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* matmult-orig.c + * Test program to do matrix multiplication on large arrays. + * + * Intended to stress virtual memory system. + * + * This is the original CS161 matmult program. Unfortunately, + * because matrix multiplication is order N^2 in space and N^3 in + * time, when this is made large enough to be an interesting VM + * test, it becomes so large that it takes hours to run. + * + * So you probably want to just run matmult, which has been + * gimmicked up to be order N^3 in space and thus have a tolerable + * running time. This version is provided for reference only. + * + * Once the VM assignment is complete your system should be able to + * survive this, if you have the patience to run it. + */ + +#include +#include + +#define Dim 360 /* sum total of the arrays doesn't fit in + * physical memory + */ + +#define RIGHT 46397160 /* correct answer */ + +int A[Dim][Dim]; +int B[Dim][Dim]; +int C[Dim][Dim]; + +int +main(void) +{ + int i, j, k, r; + + for (i = 0; i < Dim; i++) /* first initialize the matrices */ + for (j = 0; j < Dim; j++) { + A[i][j] = i; + B[i][j] = j; + C[i][j] = 0; + } + + for (i = 0; i < Dim; i++) /* then multiply them together */ + for (j = 0; j < Dim; j++) + for (k = 0; k < Dim; k++) + C[i][j] += A[i][k] * B[k][j]; + + printf("matmult-orig finished.\n"); + r = C[Dim-1][Dim-1]; + printf("answer is: %d (should be %d)\n", r, RIGHT); + if (r != RIGHT) { + printf("FAILED\n"); + } + else { + printf("Passed.\n"); + } + return 0; +} diff --git a/userland/testbin/matmult/matmult.c b/userland/testbin/matmult/matmult.c new file mode 100644 index 0000000..6dd99a3 --- /dev/null +++ b/userland/testbin/matmult/matmult.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* matmult.c + * Test program to do matrix multiplication on large arrays. + * + * This version uses a storage-inefficient technique to get a + * shorter running time for the same memory usage. + * + * Intended to stress virtual memory system. + * + * Once the VM system assignment is complete your system should be + * able to survive this. + */ + +#include +#include + +#define Dim 72 /* sum total of the arrays doesn't fit in + * physical memory + */ + +#define RIGHT 8772192 /* correct answer */ + +int A[Dim][Dim]; +int B[Dim][Dim]; +int C[Dim][Dim]; +int T[Dim][Dim][Dim]; + +int +main(void) +{ + int i, j, k, r; + + for (i = 0; i < Dim; i++) /* first initialize the matrices */ + for (j = 0; j < Dim; j++) { + A[i][j] = i; + B[i][j] = j; + C[i][j] = 0; + } + + for (i = 0; i < Dim; i++) /* then multiply them together */ + for (j = 0; j < Dim; j++) + for (k = 0; k < Dim; k++) + T[i][j][k] = A[i][k] * B[k][j]; + + for (i = 0; i < Dim; i++) + for (j = 0; j < Dim; j++) + for (k = 0; k < Dim; k++) + C[i][j] += T[i][j][k]; + + r = 0; + for (i = 0; i < Dim; i++) + r += C[i][i]; + + printf("matmult finished.\n"); + printf("answer is: %d (should be %d)\n", r, RIGHT); + if (r != RIGHT) { + printf("FAILED\n"); + return 1; + } + printf("Passed.\n"); + return 0; +} diff --git a/userland/testbin/multiexec/Makefile b/userland/testbin/multiexec/Makefile new file mode 100644 index 0000000..0e8729c --- /dev/null +++ b/userland/testbin/multiexec/Makefile @@ -0,0 +1,12 @@ +# Makefile for multiexec + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=multiexec +SRCS=multiexec.c +BINDIR=/testbin + + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/multiexec/multiexec.c b/userland/testbin/multiexec/multiexec.c new file mode 100644 index 0000000..b6f157d --- /dev/null +++ b/userland/testbin/multiexec/multiexec.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * multiexec - stuff N procs into exec at once + * usage: multiexec [-j N] [prog [arg...]] + * + * This can be used both to see what happens when you have a lot of + * execs at once (its original purpose) by running ordinary programs + * like pwd (the default) and also just as a workload generator / + * convenient way to start lots of copies of things at once. + * + * Note that this uses execv directly (not execvp) so it doesn't + * search $PATH for the program you want to run, and therefore it + * needs full paths. One could make it use execvp; it doesn't because + * that would complicate its coordinated startup logic, and also get + * in the way of using it to debug execv. + * + * Some things to try: + * multiexec /bin/true + * multiexec /bin/cat foo (for some file foo) + * multiexec /testbin/add 3 8 + * Some more aggressive things to try: + * multiexec /testbin/factorial 15 + * multiexec /testbin/bigexec + * multiexec /testbin/sort (once you have a VM system) + * Some mean things: + * multiexec /testbin/forktest + * multiexec /testbin/bloat (once you have sbrk) + * multiexec /bin/sh (this makes a huge mess unless you have job control) + */ + +#include +#include +#include +#include +#include + +//////////////////////////////////////////////////////////// +// semaphores + +/* + * We open the semaphore separately in each process to avoid + * filehandle-level locking problems. If you can't be "reading" and + * "writing" the semaphore concurrently because of the open file + * object lock, then using the same file handle for P and V will + * deadlock. Also, if this same lock is used to protect the reference + * count on the open file logic, fork will block if another process is + * using the same file handle for P, and then we're deadlocked too. + * + * Ideally the open file / filetable code wouldn't have this problem, + * as it makes e.g. console output from background jobs behave + * strangely, but it's a common issue in practice and it's better for + * tests to be immune to it. + */ + +struct usem { + char name[32]; + int fd; +}; + +static +void +semcreate(const char *tag, struct usem *sem) +{ + int fd; + + snprintf(sem->name, sizeof(sem->name), "sem:multiexec.%s.%d", + tag, (int)getpid()); + + fd = open(sem->name, O_WRONLY|O_CREAT|O_TRUNC, 0664); + if (fd < 0) { + err(1, "%s: create", sem->name); + } + close(fd); +} + +static +void +semopen(struct usem *sem) +{ + sem->fd = open(sem->name, O_RDWR, 0664); + if (sem->fd < 0) { + err(1, "%s: open", sem->name); + } +} + +static +void +semclose(struct usem *sem) +{ + close(sem->fd); +} + +static +void +semdestroy(struct usem *sem) +{ + remove(sem->name); +} + +static +void +semP(struct usem *sem, size_t num) +{ + char c[num]; + + if (read(sem->fd, c, num) < 0) { + err(1, "%s: read", sem->name); + } + (void)c; +} + +static +void +semV(struct usem *sem, size_t num) +{ + char c[num]; + + /* semfs does not use these values, but be conservative */ + memset(c, 0, num); + + if (write(sem->fd, c, num) < 0) { + err(1, "%s: write", sem->name); + } +} + +//////////////////////////////////////////////////////////// +// test + +#define SUBARGC_MAX 64 +static char *subargv[SUBARGC_MAX]; +static int subargc = 0; + +static +void +spawn(int njobs) +{ + struct usem s1, s2; + pid_t pids[njobs]; + int failed, status; + int i; + + semcreate("1", &s1); + semcreate("2", &s2); + + printf("Forking %d child processes...\n", njobs); + + for (i=0; i 0) { + warnx("%d children failed", failed); + } + else { + printf("Succeeded\n"); + } + + semclose(&s1); + semclose(&s2); + semdestroy(&s1); + semdestroy(&s2); +} + +int +main(int argc, char *argv[]) +{ + static char default_prog[] = "/bin/pwd"; + + int njobs = 12; + int i; + + for (i=1; i= SUBARGC_MAX) { + errx(1, "Too many arguments"); + } + } + } + + if (subargc == 0) { + subargv[subargc++] = default_prog; + } + subargv[subargc] = NULL; + + spawn(njobs); + + return 0; +} diff --git a/userland/testbin/palin/Makefile b/userland/testbin/palin/Makefile new file mode 100644 index 0000000..1756438 --- /dev/null +++ b/userland/testbin/palin/Makefile @@ -0,0 +1,12 @@ +# Makefile for palin + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=palin +SRCS=palin.c +BINDIR=/testbin + + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/palin/palin.c b/userland/testbin/palin/palin.c new file mode 100644 index 0000000..6bc476c --- /dev/null +++ b/userland/testbin/palin/palin.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + + Test suite. + + This program takes the palindrome below and checks if it's + a palindrome or not. It will hopefully exhibit an interesting + page fault pattern. + + The palindrome was taken from + + http://www.cs.brown.edu/people/nfp/palindrome.html + + This is not large enough to really stress the VM system, but + might be useful for testing in the early stages of the VM + assignment. +*/ + +/* +A man, a plan, a caret, a ban, a myriad, a sum, a lac, a liar, a hoop, +a pint, a catalpa, a gas, an oil, a bird, a yell, a vat, a caw, a pax, +a wag, a tax, a nay, a ram, a cap, a yam, a gay, a tsar, a wall, a +car, a luger, a ward, a bin, a woman, a vassal, a wolf, a tuna, a nit, +a pall, a fret, a watt, a bay, a daub, a tan, a cab, a datum, a gall, +a hat, a fag, a zap, a say, a jaw, a lay, a wet, a gallop, a tug, a +trot, a trap, a tram, a torr, a caper, a top, a tonk, a toll, a ball, +a fair, a sax, a minim, a tenor, a bass, a passer, a capital, a rut, +an amen, a ted, a cabal, a tang, a sun, an ass, a maw, a sag, a jam, +a dam, a sub, a salt, an axon, a sail, an ad, a wadi, a radian, a +room, a rood, a rip, a tad, a pariah, a revel, a reel, a reed, a pool, +a plug, a pin, a peek, a parabola, a dog, a pat, a cud, a nu, a fan, +a pal, a rum, a nod, an eta, a lag, an eel, a batik, a mug, a mot, a +nap, a maxim, a mood, a leek, a grub, a gob, a gel, a drab, a citadel, +a total, a cedar, a tap, a gag, a rat, a manor, a bar, a gal, a cola, +a pap, a yaw, a tab, a raj, a gab, a nag, a pagan, a bag, a jar, a +bat, a way, a papa, a local, a gar, a baron, a mat, a rag, a gap, a +tar, a decal, a tot, a led, a tic, a bard, a leg, a bog, a burg, a +keel, a doom, a mix, a map, an atom, a gum, a kit, a baleen, a gala, +a ten, a don, a mural, a pan, a faun, a ducat, a pagoda, a lob, a rap, +a keep, a nip, a gulp, a loop, a deer, a leer, a lever, a hair, a pad, +a tapir, a door, a moor, an aid, a raid, a wad, an alias, an ox, an +atlas, a bus, a madam, a jag, a saw, a mass, an anus, a gnat, a lab, +a cadet, an em, a natural, a tip, a caress, a pass, a baronet, a +minimax, a sari, a fall, a ballot, a knot, a pot, a rep, a carrot, +a mart, a part, a tort, a gut, a poll, a gateway, a law, a jay, a sap, +a zag, a fat, a hall, a gamut, a dab, a can, a tabu, a day, a batt, +a waterfall, a patina, a nut, a flow, a lass, a van, a mow, a nib, +a draw, a regular, a call, a war, a stay, a gam, a yap, a cam, a ray, +an ax, a tag, a wax, a paw, a cat, a valley, a drib, a lion, a saga, +a plat, a catnip, a pooh, a rail, a calamus, a dairyman, a bater, +a canal - Panama! +*/ + +/* The palindrome below is a quadruple concatenation of the above */ + +#include +#include + +char palindrome[8000] = +"amanaplanacaretabanamyriadasumalacaliarahoopapintacatalpaagasanoil" +"abirdayellavatacawapaxawagataxanayaramacapayamagayatsarawalla" +"caralugerawardabinawomanavassalawolfatunaanitapallafretawattabaya" +"daubatanacabadatumagallahatafagazapasayajawalayawetagallopatuga" +"trotatrapatramatorracaperatopatonkatollaballafairasaxaminimatenora" +"bassapasseracapitalarutanamenatedacabalatangasunanassamawasaga" +"jamadamasubasaltanaxonasailanadawadiaradianaroomaroodaripatada" +"pariaharevelareelareedapoolaplugapinapeekaparabolaadogapatacudanua" +"fanapalarumanodanetaalaganeelabatikamugamotanapamaximamooda" +"leekagrubagobageladrabacitadelatotalacedaratapagagaratamanorabara" +"galacolaapapayawatabarajagabanagapaganabagajarabatawayapapaa" +"localagarabaronamataragagapataradecalatotaledaticabardalegaboga" +"burgakeeladoomamixamapanatomagumakitabaleenagalaatenadonamurala" +"panafaunaducatapagodaalobarapakeepanipagulpaloopadeeraleeralevera" +"hairapadatapiradooramooranaidaraidawadanaliasanoxanatlasabusamadam" +"ajagasawamassananusagnatalabacadetanemanaturalatipacaressapassa" +"baronetaminimaxasariafallaballotaknotapotarepacarrotamartapartatorta" +"gutapollagatewayalawajayasapazagafatahallagamutadabacanatabuaday" +"abattawaterfallapatinaanutaflowalassavanamowanibadrawaregularacalla" +"warastayagamayapacamarayanaxatagawaxapawacatavalleyadribaliona" +"sagaaplatacatnipapooharailacalamusadairymanabateracanalpanama" +"amanaplanacaretabanamyriadasumalacaliarahoopapintacatalpaagasanoil" +"abirdayellavatacawapaxawagataxanayaramacapayamagayatsarawalla" +"caralugerawardabinawomanavassalawolfatunaanitapallafretawattabaya" +"daubatanacabadatumagallahatafagazapasayajawalayawetagallopatuga" +"trotatrapatramatorracaperatopatonkatollaballafairasaxaminimatenora" +"bassapasseracapitalarutanamenatedacabalatangasunanassamawasaga" +"jamadamasubasaltanaxonasailanadawadiaradianaroomaroodaripatada" +"pariaharevelareelareedapoolaplugapinapeekaparabolaadogapatacudanua" +"fanapalarumanodanetaalaganeelabatikamugamotanapamaximamooda" +"leekagrubagobageladrabacitadelatotalacedaratapagagaratamanorabara" +"galacolaapapayawatabarajagabanagapaganabagajarabatawayapapaa" +"localagarabaronamataragagapataradecalatotaledaticabardalegaboga" +"burgakeeladoomamixamapanatomagumakitabaleenagalaatenadonamurala" +"panafaunaducatapagodaalobarapakeepanipagulpaloopadeeraleeralevera" +"hairapadatapiradooramooranaidaraidawadanaliasanoxanatlasabusamadam" +"ajagasawamassananusagnatalabacadetanemanaturalatipacaressapassa" +"baronetaminimaxasariafallaballotaknotapotarepacarrotamartapartatorta" +"gutapollagatewayalawajayasapazagafatahallagamutadabacanatabuaday" +"abattawaterfallapatinaanutaflowalassavanamowanibadrawaregularacalla" +"warastayagamayapacamarayanaxatagawaxapawacatavalleyadribaliona" +"sagaaplatacatnipapooharailacalamusadairymanabateracanalpanama" +"amanaplanacaretabanamyriadasumalacaliarahoopapintacatalpaagasanoil" +"abirdayellavatacawapaxawagataxanayaramacapayamagayatsarawalla" +"caralugerawardabinawomanavassalawolfatunaanitapallafretawattabaya" +"daubatanacabadatumagallahatafagazapasayajawalayawetagallopatuga" +"trotatrapatramatorracaperatopatonkatollaballafairasaxaminimatenora" +"bassapasseracapitalarutanamenatedacabalatangasunanassamawasaga" +"jamadamasubasaltanaxonasailanadawadiaradianaroomaroodaripatada" +"pariaharevelareelareedapoolaplugapinapeekaparabolaadogapatacudanua" +"fanapalarumanodanetaalaganeelabatikamugamotanapamaximamooda" +"leekagrubagobageladrabacitadelatotalacedaratapagagaratamanorabara" +"galacolaapapayawatabarajagabanagapaganabagajarabatawayapapaa" +"localagarabaronamataragagapataradecalatotaledaticabardalegaboga" +"burgakeeladoomamixamapanatomagumakitabaleenagalaatenadonamurala" +"panafaunaducatapagodaalobarapakeepanipagulpaloopadeeraleeralevera" +"hairapadatapiradooramooranaidaraidawadanaliasanoxanatlasabusamadam" +"ajagasawamassananusagnatalabacadetanemanaturalatipacaressapassa" +"baronetaminimaxasariafallaballotaknotapotarepacarrotamartapartatorta" +"gutapollagatewayalawajayasapazagafatahallagamutadabacanatabuaday" +"abattawaterfallapatinaanutaflowalassavanamowanibadrawaregularacalla" +"warastayagamayapacamarayanaxatagawaxapawacatavalleyadribaliona" +"sagaaplatacatnipapooharailacalamusadairymanabateracanalpanama" +"amanaplanacaretabanamyriadasumalacaliarahoopapintacatalpaagasanoil" +"abirdayellavatacawapaxawagataxanayaramacapayamagayatsarawalla" +"caralugerawardabinawomanavassalawolfatunaanitapallafretawattabaya" +"daubatanacabadatumagallahatafagazapasayajawalayawetagallopatuga" +"trotatrapatramatorracaperatopatonkatollaballafairasaxaminimatenora" +"bassapasseracapitalarutanamenatedacabalatangasunanassamawasaga" +"jamadamasubasaltanaxonasailanadawadiaradianaroomaroodaripatada" +"pariaharevelareelareedapoolaplugapinapeekaparabolaadogapatacudanua" +"fanapalarumanodanetaalaganeelabatikamugamotanapamaximamooda" +"leekagrubagobageladrabacitadelatotalacedaratapagagaratamanorabara" +"galacolaapapayawatabarajagabanagapaganabagajarabatawayapapaa" +"localagarabaronamataragagapataradecalatotaledaticabardalegaboga" +"burgakeeladoomamixamapanatomagumakitabaleenagalaatenadonamurala" +"panafaunaducatapagodaalobarapakeepanipagulpaloopadeeraleeralevera" +"hairapadatapiradooramooranaidaraidawadanaliasanoxanatlasabusamadam" +"ajagasawamassananusagnatalabacadetanemanaturalatipacaressapassa" +"baronetaminimaxasariafallaballotaknotapotarepacarrotamartapartatorta" +"gutapollagatewayalawajayasapazagafatahallagamutadabacanatabuaday" +"abattawaterfallapatinaanutaflowalassavanamowanibadrawaregularacalla" +"warastayagamayapacamarayanaxatagawaxapawacatavalleyadribaliona" +"sagaaplatacatnipapooharailacalamusadairymanabateracanalpanama"; + +int +main(void) +{ + char *start, *end; + + printf("Welcome to the palindrome tester!\n"); + printf("I will take a large palindrome and test it.\n"); + printf("Here it is:\n"); + printf("%s\n", palindrome); + + printf("Testing..."); + /* skip to end */ + end = palindrome+strlen(palindrome); + end--; + + for (start = palindrome; start <= end; start++, end--) { + putchar('.'); + if (*start != *end) { + printf("NOT a palindrome\n"); + return 0; + } + } + + printf("IS a palindrome\n"); + return 0; +} diff --git a/userland/testbin/parallelvm/Makefile b/userland/testbin/parallelvm/Makefile new file mode 100644 index 0000000..bc26d2f --- /dev/null +++ b/userland/testbin/parallelvm/Makefile @@ -0,0 +1,12 @@ +# Makefile for parallelvm + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=parallelvm +SRCS=parallelvm.c +BINDIR=/testbin + + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/parallelvm/parallelvm.c b/userland/testbin/parallelvm/parallelvm.c new file mode 100644 index 0000000..953764a --- /dev/null +++ b/userland/testbin/parallelvm/parallelvm.c @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * parallelvm.c: highly parallelized VM stress test. + * + * This test probably won't run with only 512k of physical memory + * (unless maybe if you have a *really* gonzo VM system) because each + * of its processes needs to allocate a kernel stack, and those add up + * quickly. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NJOBS 24 + +#define DIM 35 +#define NMATS 11 +#define JOBSIZE ((NMATS+1)*DIM*DIM*sizeof(int)) + +static const int right_answers[NJOBS] = { + -1337312809, + 356204544, + -537881911, + -65406976, + 1952063315, + -843894784, + 1597000869, + -993925120, + 838840559, + -1616928768, + -182386335, + -364554240, + 251084843, + -61403136, + 295326333, + 1488013312, + 1901440647, + 0, + -1901440647, + -1488013312, + -295326333, + 61403136, + -251084843, + 364554240, +}; + +//////////////////////////////////////////////////////////// + +struct matrix { + int m_data[DIM][DIM]; +}; + +//////////////////////////////////////////////////////////// + +/* + * Use this instead of just calling printf so we know each printout + * is atomic; this prevents the lines from getting intermingled. + */ +static +void +say(const char *fmt, ...) +{ + char buf[256]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + write(STDOUT_FILENO, buf, strlen(buf)); +} + +//////////////////////////////////////////////////////////// + +static +void +multiply(struct matrix *res, const struct matrix *m1, const struct matrix *m2) +{ + int i, j, k; + + for (i=0; im_data[i][k]*m2->m_data[k][j]; + } + res->m_data[i][j] = val; + } + } +} + +static +void +addeq(struct matrix *m1, const struct matrix *m2) +{ + int i, j; + for (i=0; im_data[i][j] += m2->m_data[i][j]; + } + } +} + +static +int +trace(const struct matrix *m1) +{ + int i, t=0; + for (i=0; im_data[i][i]; + } + return t; +} + +//////////////////////////////////////////////////////////// + +static struct matrix mats[NMATS]; + +static +void +populate_initial_matrixes(int mynum) +{ + int i,j; + struct matrix *m = &mats[0]; + for (i=0; im_data[i][j] = mynum+i-2*j; + } + } + + multiply(&mats[1], &mats[0], &mats[0]); +} + +static +void +compute(int n) +{ + struct matrix tmp; + int i, j; + + for (i=0,j=n-1; iname, sizeof(sem->name), "sem:parallelvm.%s.%d", + tag, (int)getpid()); + + fd = open(sem->name, O_WRONLY|O_CREAT|O_TRUNC, 0664); + if (fd < 0) { + err(1, "%s: create", sem->name); + } + close(fd); +} + +static +void +semopen(struct usem *sem) +{ + sem->fd = open(sem->name, O_RDWR, 0664); + if (sem->fd < 0) { + err(1, "%s: open", sem->name); + } +} + +static +void +semclose(struct usem *sem) +{ + close(sem->fd); +} + +static +void +semdestroy(struct usem *sem) +{ + remove(sem->name); +} + +static +void +semP(struct usem *sem, size_t num) +{ + char c[num]; + + if (read(sem->fd, c, num) < 0) { + err(1, "%s: read", sem->name); + } + (void)c; +} + +static +void +semV(struct usem *sem, size_t num) +{ + char c[num]; + + /* semfs does not use these values, but be conservative */ + memset(c, 0, num); + + if (write(sem->fd, c, num) < 0) { + err(1, "%s: write", sem->name); + } +} + +//////////////////////////////////////////////////////////// +// driver + +static +int +status_is_failure(int status) +{ + /* Proper interpretation of Unix exit status */ + if (WIFSIGNALED(status)) { + return 1; + } + if (!WIFEXITED(status)) { + /* ? */ + return 1; + } + status = WEXITSTATUS(status); + return status != 0; +} + +static +void +makeprocs(bool dowait) +{ + int i, status, failcount; + struct usem s1, s2; + pid_t pids[NJOBS]; + + if (dowait) { + semcreate("1", &s1); + semcreate("2", &s2); + } + + printf("Job size approximately %lu bytes\n", (unsigned long) JOBSIZE); + printf("Forking %d jobs; total load %luk\n", NJOBS, + (unsigned long) (NJOBS * JOBSIZE)/1024); + + for (i=0; i0) { + printf("%d subprocesses failed\n", failcount); + exit(1); + } + printf("Test complete\n"); + + semclose(&s1); + semclose(&s2); + semdestroy(&s1); + semdestroy(&s2); +} + +int +main(int argc, char *argv[]) +{ + bool dowait = false; + + if (argc == 0) { + /* broken/unimplemented argv handling; do nothing */ + } + else if (argc == 1) { + /* nothing */ + } + else if (argc == 2 && !strcmp(argv[1], "-w")) { + dowait = true; + } + else { + printf("Usage: parallelvm [-w]\n"); + return 1; + } + makeprocs(dowait); + return 0; +} diff --git a/userland/testbin/poisondisk/Makefile b/userland/testbin/poisondisk/Makefile new file mode 100644 index 0000000..5847974 --- /dev/null +++ b/userland/testbin/poisondisk/Makefile @@ -0,0 +1,16 @@ +# Makefile for poisondisk + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=poisondisk +SRCS=poisondisk.c \ + ../../sbin/mksfs/disk.c ../../sbin/mksfs/support.c +CFLAGS+=-I../../sbin/mksfs +HOST_CFLAGS+=-I../../sbin/mksfs +BINDIR=/testbin +HOSTBINDIR=/hostbin + + +.include "$(TOP)/mk/os161.prog.mk" +.include "$(TOP)/mk/os161.hostprog.mk" diff --git a/userland/testbin/poisondisk/poisondisk.c b/userland/testbin/poisondisk/poisondisk.c new file mode 100644 index 0000000..e329f91 --- /dev/null +++ b/userland/testbin/poisondisk/poisondisk.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2013, 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * poisondisk - fill a disk with nonzero poison values + * usage: poisondisk disk-image + */ + +#include +#include +#include +#include + +#ifdef HOST +#include "hostcompat.h" +#endif + +#include "disk.h" + +#define POISON_BYTE 0xa9 +#define BLOCKSIZE 512 + +static +void +poison(void) +{ + char buf[BLOCKSIZE]; + off_t sectors, i; + + memset(buf, POISON_BYTE, sizeof(buf)); + + sectors = diskblocks(); + for (i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef RANDOM_MAX +/* Note: this is correct for OS/161 but not for some Unix C libraries */ +#define RANDOM_MAX RAND_MAX +#endif + +#define PATH_KEYS "sortkeys" +#define PATH_SORTED "output" +#define PATH_TESTDIR "psortdir" +#define PATH_RANDOM "rand:" + +/* + * Workload sizing. + * + * We fork numprocs processes. Each one works on WORKNUM integers at a + * time, so the total VM load is WORKNUM * sizeof(int) * numprocs. For + * the best stress testing, this should be substantially larger than + * your available RAM. + * + * Meanwhile we generate and process numkeys integers, so the total + * filesystem load is numkeys * sizeof(int). For the best stress + * testing this should be substantially larger than your buffer cache. + * + * This test is supposed to adjust to arbitrary settings of WORKNUM, + * numprocs, and numkeys. For a small test try these settings: + * WORKNUM (16*1024) + * numprocs 4, or 2 + * numkeys 10000 + * + * This should fit in memory (memory footprint is 256K) and generate + * only small files (~40K) which will work on the pre-largefiles SFS. + * + * The default settings are: + * WORKNUM (96*1024) + * numprocs 4 + * numkeys 128*1024 + * + * so the memory footprint is 1.5M (comparable to the VM tests) and + * the base file size is 512K. Note that because there are a lot of + * temporary files, it pumps a good deal more than 512K of data. For + * the record, the solution set takes about 7.5 minutes of virtual + * time to run it, in either 1M or 2M of RAM and with 4 CPUs; this + * currently corresponds to about 13-14 minutes of real time. + * + * Note that the parent psort process serves as a director and doesn't + * itself compute; it has a workspace (because it's a static buffer) + * but doesn't use it. A VM system that doesn't do zerofill + * optimization will be a lot slower because it has to copy this space + * for every batch of forks. + * + * Also note that you can set numprocs and numkeys on the command + * line, but not WORKNUM. + * + * FUTURE: maybe make a build option to malloc the work space instead + * of using a static buffer, which would allow choosing WORKNUM on the + * command line too, at the cost of depending on malloc working. + */ + +/* Set the workload size. */ +#define WORKNUM (96*1024) +static int numprocs = 4; +static int numkeys = 128*1024; + +/* Per-process work buffer */ +static int workspace[WORKNUM]; + +/* Random seed for generating the data */ +static long randomseed = 15432753; + +/* other state */ +static off_t correctsize; +static unsigned long checksum; + +#define NOBODY (-1) +static int me = NOBODY; + +static const char *progname; + +//////////////////////////////////////////////////////////// + +static +void +sortints(int *v, int num) +{ + int pivotval, pivotpoint, pivotcount; + int frontpos, readpos, endpos, i, j; + int tmp; + + if (num < 2) { + return; + } + + pivotpoint = num/2; + pivotval = v[pivotpoint]; + pivotcount = 0; + + frontpos = 0; + readpos = 0; + endpos = num; + while (readpos < endpos) { + if (v[readpos] < pivotval) { + v[frontpos++] = v[readpos++]; + } + else if (v[readpos] == pivotval) { + readpos++; + pivotcount++; + } + else { + tmp = v[--endpos]; + v[endpos] = v[readpos]; + v[readpos] = tmp; + } + } + assert(readpos == endpos); + assert(frontpos + pivotcount == readpos); + + for (i=frontpos; i= 0) { + snprintf(buf, len, "%s: proc %d: ", progname, me); + } + else { + snprintf(buf, len, "%s: ", progname); + } + pos = strlen(buf); + + vsnprintf(buf+pos, len-pos, fmt, ap); + pos = strlen(buf); + + if (err >= 0) { + snprintf(buf+pos, len-pos, ": %s\n", strerror(err)); + } + else { + snprintf(buf+pos, len-pos, "\n"); + } +} + +static +void +complainx(const char *fmt, ...) +{ + char buf[256]; + va_list ap; + ssize_t junk; + + va_start(ap, fmt); + vscomplain(buf, sizeof(buf), fmt, ap, -1); + va_end(ap); + + /* Write the message in one go so it's atomic */ + junk = write(STDERR_FILENO, buf, strlen(buf)); + + /* + * This variable must be assigned and then ignored with some + * (broken) Linux C libraries. Ah, Linux... + */ + (void)junk; +} + +static +void +complain(const char *fmt, ...) +{ + char buf[256]; + va_list ap; + ssize_t junk; + int err = errno; + + va_start(ap, fmt); + vscomplain(buf, sizeof(buf), fmt, ap, err); + va_end(ap); + + /* Write the message in one go so it's atomic */ + junk = write(STDERR_FILENO, buf, strlen(buf)); + + /* + * This variable must be assigned and then ignored with some + * (broken) Linux C libraries. Ah, Linux... + */ + (void)junk; +} + +//////////////////////////////////////////////////////////// + +static +int +doopen(const char *path, int flags, int mode) +{ + int fd; + + fd = open(path, flags, mode); + if (fd<0) { + complain("%s", path); + exit(1); + } + return fd; +} + +static +void +doclose(const char *path, int fd) +{ + if (close(fd)) { + complain("%s: close", path); + exit(1); + } +} + +static +void +docreate(const char *path) +{ + int fd; + + fd = doopen(path, O_WRONLY|O_CREAT|O_TRUNC, 0664); + doclose(path, fd); +} + +static +void +doremove(const char *path) +{ + static int noremove; + + if (noremove) { + return; + } + + if (remove(path) < 0) { + if (errno == ENOSYS) { + /* Complain (and try) only once. */ + noremove = 1; + } + complain("%s: remove", path); + } +} + +static +off_t +getsize(const char *path) +{ + struct stat buf; + int fd; + static int no_stat, no_fstat; + + if (!no_stat) { + if (stat(path, &buf) == 0) { + return buf.st_size; + } + if (errno != ENOSYS) { + complain("%s: stat", path); + exit(1); + } + /* Avoid further "Unknown syscall 81" messages */ + no_stat = 1; + } + + fd = doopen(path, O_RDONLY, 0); + if (!no_fstat) { + if (fstat(fd, &buf) == 0) { + close(fd); + return buf.st_size; + } + if (errno != ENOSYS) { + complain("%s: stat", path); + exit(1); + } + /* Avoid further "Unknown syscall 82" messages */ + no_fstat = 1; + } + + /* otherwise, lseek */ + if (lseek(fd, 0, SEEK_END) >= 0) { + buf.st_size = lseek(fd, 0, SEEK_CUR); + if (buf.st_size >= 0) { + return buf.st_size; + } + } + complain("%s: getting file size with lseek", path); + close(fd); + exit(1); +} + +static +size_t +doread(const char *path, int fd, void *buf, size_t len) +{ + int result; + + result = read(fd, buf, len); + if (result < 0) { + complain("%s: read", path); + exit(1); + } + return (size_t) result; +} + +static +void +doexactread(const char *path, int fd, void *buf, size_t len) +{ + size_t result; + + result = doread(path, fd, buf, len); + if (result != len) { + complainx("%s: read: short count", path); + exit(1); + } +} + +static +void +dowrite(const char *path, int fd, const void *buf, size_t len) +{ + int result; + + result = write(fd, buf, len); + if (result < 0) { + complain("%s: write", path); + exit(1); + } + if ((size_t) result != len) { + complainx("%s: write: short count", path); + exit(1); + } +} + +static +void +dolseek(const char *name, int fd, off_t offset, int whence) +{ + if (lseek(fd, offset, whence) < 0) { + complain("%s: lseek", name); + exit(1); + } +} + +#if 0 /* let's not require subdirs */ +static +void +dochdir(const char *path) +{ + if (chdir(path) < 0) { + complain("%s: chdir", path); + exit(1); + } +} + +static +void +domkdir(const char *path, int mode) +{ + if (mkdir(path, mode) < 0) { + complain("%s: mkdir", path); + exit(1); + } +} +#endif /* 0 */ + +static +pid_t +dofork(void) +{ + pid_t pid; + + pid = fork(); + if (pid < 0) { + complain("fork"); + /* but don't exit */ + } + + return pid; +} + +//////////////////////////////////////////////////////////// + +static +int +dowait(int guy, pid_t pid) +{ + int status, result; + + result = waitpid(pid, &status, 0); + if (result < 0) { + complain("waitpid"); + return -1; + } + if (WIFSIGNALED(status)) { + complainx("proc %d: signal %d", guy, WTERMSIG(status)); + return -1; + } + assert(WIFEXITED(status)); + status = WEXITSTATUS(status); + if (status) { + complainx("proc %d: exit %d", guy, status); + return -1; + } + return 0; +} + +static +void +doforkall(const char *phasename, void (*func)(void)) +{ + int i, bad = 0; + pid_t pids[numprocs]; + + for (i=0; i 0 && dowait(i, pids[i])) { + bad = 1; + } + } + + if (bad) { + complainx("%s failed.", phasename); + exit(1); + } +} + +static +void +seekmyplace(const char *name, int fd) +{ + int keys_per, myfirst; + off_t offset; + + keys_per = numkeys / numprocs; + myfirst = me*keys_per; + offset = myfirst * sizeof(int); + + dolseek(name, fd, offset, SEEK_SET); +} + +static +int +getmykeys(void) +{ + int keys_per, myfirst, mykeys; + + keys_per = numkeys / numprocs; + myfirst = me*keys_per; + mykeys = (me < numprocs-1) ? keys_per : numkeys - myfirst; + + return mykeys; +} + +//////////////////////////////////////////////////////////// + +static +unsigned long +checksum_file(const char *path) +{ + int fd; + char buf[512]; + size_t count, i; + unsigned long sum = 0; + + fd = doopen(path, O_RDONLY, 0); + + while ((count = doread(path, fd, buf, sizeof(buf))) > 0) { + for (i=0; i WORKNUM) { + keys_to_do = WORKNUM; + } + + for (i=0; i= 0); + assert(value <= RANDOM_MAX); + + // do not allow the value to be zero or RANDOM_MAX + while (value == 0 || value == RANDOM_MAX) { + value = random(); + } + + workspace[i] = value; + } + + dowrite(PATH_KEYS, fd, workspace, keys_to_do*sizeof(int)); + keys_done += keys_to_do; + } + + doclose(PATH_KEYS, fd); +} + +static +void +genkeys(void) +{ + long seedspace[numprocs]; + int i; + + /* Create the file. */ + docreate(PATH_KEYS); + + /* Generate random seeds for each subprocess. */ + srandom(randomseed); + for (i=0; i WORKNUM) { + keys_to_do = WORKNUM; + } + + doexactread(PATH_KEYS, infd, workspace, + keys_to_do * sizeof(int)); + + for (i=0; i= 0); + assert(binnum < numprocs); + dowrite("bin", outfds[binnum], &key, sizeof(key)); + } + + keys_done += keys_to_do; + } + doclose(PATH_KEYS, infd); + + for (i=0; i (off_t) sizeof(workspace)) { + complainx("proc %d: %s: bin too large", me, name); + exit(1); + } + + fd = doopen(name, O_RDWR, 0); + doexactread(name, fd, workspace, binsize); + + sortints(workspace, binsize/sizeof(int)); + + dolseek(name, fd, 0, SEEK_SET); + dowrite(name, fd, workspace, binsize); + doclose(name, fd); + } +} + +static +void +mergebins(void) +{ + int infds[numprocs], outfd; + int values[numprocs], ready[numprocs]; + const char *name, *outname; + int i, result; + int numready, place, val, worknum; + + outname = mergedname(me); + outfd = doopen(outname, O_WRONLY|O_CREAT|O_TRUNC, 0664); + + for (i=0; i= 0); + + workspace[worknum++] = val; + if (worknum >= WORKNUM) { + assert(worknum == WORKNUM); + dowrite(outname, outfd, workspace, + worknum * sizeof(int)); + worknum = 0; + } + ready[place] = 0; + } + + dowrite(outname, outfd, workspace, worknum * sizeof(int)); + doclose(outname, outfd); + + for (i=0; i WORKNUM) { + keys_to_do = WORKNUM; + } + + doexactread(name, fd, workspace, keys_to_do * sizeof(int)); + + for (i=0; i= RANDOM_MAX) { + complain("%s: found too-large key", name); + exit(1); + } + + if (key < smallest) { + smallest = key; + } + if (key > largest) { + largest = key; + } + } + + keys_done += keys_to_do; + } + doclose(name, fd); + + name = validname(me); + fd = doopen(name, O_WRONLY|O_CREAT|O_TRUNC, 0664); + dowrite(name, fd, &smallest, sizeof(smallest)); + dowrite(name, fd, &largest, sizeof(largest)); + doclose(name, fd); +} + +static +void +validate(void) +{ + int smallest, largest, prev_largest; + int i, fd; + const char *name; + + complainx("Validating the sorted data using %d procs", numprocs); + doforkall("Validation", dovalidate); + checksize_valid(); + + prev_largest = 1; + + for (i=0; i= RANDOM_MAX) { + complainx("Validation: block %d: bad LARGEST", i); + exit(1); + } + if (smallest > largest) { + complainx("Validation: block %d: SMALLEST > LARGEST", + i); + exit(1); + } + + if (smallest < prev_largest) { + complain("Validation: block %d smallest key %d", + i, smallest); + complain("Validation: previous block largest key %d", + prev_largest); + complain("Validation failed"); + exit(1); + } + } + + + for (i=0; i 0 ? argv[0] : NULL); + + doargs(argc, argv); + correctsize = (off_t) (numkeys*sizeof(int)); + + setdir(); + + genkeys(); + sort(); + validate(); + complainx("Succeeded."); + + unsetdir(); + + return 0; +} diff --git a/userland/testbin/randcall/Makefile b/userland/testbin/randcall/Makefile new file mode 100644 index 0000000..15db61e --- /dev/null +++ b/userland/testbin/randcall/Makefile @@ -0,0 +1,24 @@ +# Makefile for badcall + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=randcall +SRCS=$(MYBUILDDIR)/calls.c main.c +BINDIR=/testbin + +CFLAGS+=-I. + +.include "$(TOP)/mk/os161.prog.mk" + +$(MYBUILDDIR)/calls.c: gencalls.sh callspecs.txt + ./gencalls.sh callspecs.txt > $(MYBUILDDIR)/calls.c + +predepend: + $(MAKE) $(MYBUILDDIR)/calls.c + +clean: myclean +myclean: + rm -f $(MYBUILDDIR)/calls.c + +.PHONY: predepend myclean diff --git a/userland/testbin/randcall/callspecs.txt b/userland/testbin/randcall/callspecs.txt new file mode 100644 index 0000000..ab42e52 --- /dev/null +++ b/userland/testbin/randcall/callspecs.txt @@ -0,0 +1,26 @@ +2 execv ptr ptr +2 waitpid int ptr int +2 open ptr int int +2 read int ptr size +2 write int ptr size +2 close int +5 ioctl int int ptr +2 lseek int off int +4 fsync int +4 ftruncate int off +4 fstat int ptr +4 remove ptr +4 rename ptr ptr +5 link ptr ptr +4 mkdir ptr int +4 rmdir ptr +2 chdir ptr +4 getdirentry int ptr size +5 symlink ptr ptr +5 readlink ptr ptr size +2 dup2 int int +5 pipe ptr +5 __time ptr ptr +2 __getcwd ptr size +5 stat ptr ptr +5 lstat ptr ptr diff --git a/userland/testbin/randcall/extern.h b/userland/testbin/randcall/extern.h new file mode 100644 index 0000000..8ca1da7 --- /dev/null +++ b/userland/testbin/randcall/extern.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +void *randptr(void); +int randint(void); +off_t randoff(void); +size_t randsize(void); + +void trycalls(int asst, int dofork, int count); diff --git a/userland/testbin/randcall/gencalls.sh b/userland/testbin/randcall/gencalls.sh new file mode 100755 index 0000000..2276e7a --- /dev/null +++ b/userland/testbin/randcall/gencalls.sh @@ -0,0 +1,143 @@ +#!/bin/sh +# +# gencalls.sh - generate calls.c and calls.h +# +# Usage: gencalls.sh callspecs-file + +if [ "x$1" = x ]; then + echo "Usage: $0 callspecs-file" + exit 1 +fi + +awk < $1 ' + + BEGIN { + type["ptr"] = "void *"; + type["int"] = "int"; + type["off"] = "off_t"; + type["size"] = "size_t"; + fmt["ptr"] = "%p"; + fmt["int"] = "%d"; + fmt["off"] = "%lld"; + fmt["size"] = "%lu"; + cast["ptr"] = ""; + cast["int"] = ""; + cast["off"] = "(long long)"; + cast["size"] = "(unsigned long)"; + + printf "/* Automatically generated file; do not edit */\n"; + printf "#include \n"; + printf "#include \n"; + printf "#include \n"; + printf "#include \n"; + printf "#include \n"; + printf "#include \n"; + printf "#include \n"; + printf "#include \n"; + printf "\n"; + printf "#include \"extern.h\"\n"; + printf "\n"; + + printf "typedef void (*tryfunc)(int dofork);\n"; + printf "\n"; + + n=0; + } + + { + printf "static\n"; + printf "void\n"; + printf "try_%s(int dofork)\n", $2; + printf "{\n"; + for (i=3; i<=NF; i++) { + printf "\t%s a%d = rand%s();\n", type[$i], i-3, $i; + } + printf "\tint result, pid, status;\n"; + printf "\tchar buf[128];\n"; + printf "\n"; + + printf "\tsnprintf(buf, sizeof(buf), \"%s(", $2; + for (i=3; i<=NF; i++) { + printf "%s", fmt[$i]; + if (i0) {\n"; + printf "\t\twaitpid(pid, &status, 0);\n"; + printf "\t\treturn;\n"; + printf "\t}\n"; + printf "\n"; + + printf "\tresult = %s(", $2; + for (i=3; i<=NF; i++) { + printf "a%d", i-3; + if (i=2 && asst<=5);\n"; + printf "\tlist = tables[asst-2];\n"; + printf "\n"; + + printf "\tfor (i=0; i +#include +#include + +#include "extern.h" + +static +void +randchar(char *c) +{ +#if RAND_MAX != 0x7fffffff +#error "This code assumes RAND_MAX is 0x7fffffff" +#endif + + static long lbits = 0; + static long lnum = 0; + + long bit; + int ct = 0; + + *c = 0; + + while (ct < CHAR_BIT) { + if (lnum==0) { + lbits = random(); + lnum = 31; + } + + bit = lbits & 1; + if (bit) { + (*c) |= 1; + } + (*c) <<= 1; + ct++; + lbits >>= 1; + lnum--; + } +} + +static +void +fillrand(void *p, size_t len) +{ + size_t i; + char *cp = p; + for (i=0; i 4) { + usage(); + } + } + + printf("Seed: %d Count: %d\n", seed, count); + + srandom(seed); + trycalls(an, dofork, count); + + return 0; +} diff --git a/userland/testbin/redirect/Makefile b/userland/testbin/redirect/Makefile new file mode 100644 index 0000000..e65d45f --- /dev/null +++ b/userland/testbin/redirect/Makefile @@ -0,0 +1,11 @@ +# Makefile for redirect + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=redirect +SRCS=redirect.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/redirect/redirect.c b/userland/testbin/redirect/redirect.c new file mode 100644 index 0000000..cca3f49 --- /dev/null +++ b/userland/testbin/redirect/redirect.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Test if redirecting stdin and stdout works. (Doesn't check stderr.) + * + * Normally it should without any extra effort, provided that dup2 has + * been implemented properly, but experience has shown that sometimes + * people get the idea that exec should reset the stdin, stdout, and + * stderr file handles to point to the console, which breaks things. + * Don't do that. + * + * (This test also depends on fork working properly.) + */ + +#include +#include +#include +#include + +#define PATH_CAT "/bin/cat" +#define INFILE "redirect.in" +#define OUTFILE "redirect.out" + +static const char slogan[] = "CECIDI, ET NON SURGERE POSSUM!\n"; + +static +int +doopen(const char *path, int openflags) +{ + int fd; + + fd = open(path, openflags, 0664); + if (fd < 0) { + err(1, "%s", path); + } + return fd; +} + +static +void +dodup2(int ofd, int nfd, const char *file) +{ + int r; + + r = dup2(ofd, nfd); + if (r < 0) { + err(1, "%s: dup2", file); + } + if (r != nfd) { + errx(1, "%s: dup2: Expected %d, got %d", nfd, r); + } +} + +static +void +doclose(int fd, const char *file) +{ + if (close(fd)) { + warnx("%s: close", file); + } +} + +static +void +mkfile(void) +{ + int fd; + ssize_t r; + + fd = doopen(INFILE, O_WRONLY|O_CREAT|O_TRUNC); + + r = write(fd, slogan, strlen(slogan)); + if (r < 0) { + err(1, "%s: write", INFILE); + } + if ((size_t)r != strlen(slogan)) { + errx(1, "%s: write: Short count (got %zd, expected %zu)", + INFILE, r, strlen(slogan)); + } + + doclose(fd, INFILE); +} + +static +void +chkfile(void) +{ + char buf[256]; + ssize_t r; + int fd; + + fd = doopen(OUTFILE, O_RDONLY); + + r = read(fd, buf, sizeof(buf)); + if (r < 0) { + err(1, "%s: read", OUTFILE); + } + if (r == 0) { + errx(1, "%s: read: Unexpected EOF", OUTFILE); + } + if ((size_t)r != strlen(slogan)) { + errx(1, "%s: read: Short count (got %zd, expected %zu)", + OUTFILE, r, strlen(slogan)); + } + + doclose(fd, OUTFILE); +} + +static +void +cat(void) +{ + pid_t pid; + int rfd, wfd, result, status; + const char *args[2]; + + rfd = doopen(INFILE, O_RDONLY); + wfd = doopen(OUTFILE, O_WRONLY|O_CREAT|O_TRUNC); + + pid = fork(); + if (pid < 0) { + err(1, "fork"); + } + + if (pid == 0) { + /* child */ + dodup2(rfd, STDIN_FILENO, INFILE); + dodup2(wfd, STDOUT_FILENO, OUTFILE); + doclose(rfd, INFILE); + doclose(wfd, OUTFILE); + args[0] = "cat"; + args[1] = NULL; + execv(PATH_CAT, (char **)args); + warn("%s: execv", PATH_CAT); + _exit(1); + } + + /* parent */ + doclose(rfd, INFILE); + doclose(wfd, OUTFILE); + + result = waitpid(pid, &status, 0); + if (result == -1) { + err(1, "waitpid"); + } + if (WIFSIGNALED(status)) { + errx(1, "pid %d: Signal %d", (int)pid, WTERMSIG(status)); + } + if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { + errx(1, "pid %d: Exit %d", (int)pid, WEXITSTATUS(status)); + } +} + +int +main(void) +{ + printf("Creating %s...\n", INFILE); + mkfile(); + + printf("Running cat < %s > %s\n", INFILE, OUTFILE); + cat(); + + printf("Checking %s...\n", OUTFILE); + chkfile(); + + printf("Passed.\n"); + (void)remove(INFILE); + (void)remove(OUTFILE); + return 0; +} diff --git a/userland/testbin/rmdirtest/Makefile b/userland/testbin/rmdirtest/Makefile new file mode 100644 index 0000000..4c5ef36 --- /dev/null +++ b/userland/testbin/rmdirtest/Makefile @@ -0,0 +1,11 @@ +# Makefile for rmdirtest + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=rmdirtest +SRCS=rmdirtest.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/rmdirtest/rmdirtest.c b/userland/testbin/rmdirtest/rmdirtest.c new file mode 100644 index 0000000..a244f67 --- /dev/null +++ b/userland/testbin/rmdirtest/rmdirtest.c @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * rmdirtest.c + * + * Tests file system synchronization and directory implementation by + * removing the current directory under itself and then trying to do + * things. It's ok for most of those things to fail, but the system + * shouldn't crash. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static const char testdir[] = "testdir"; +static char startpoint[PATH_MAX - sizeof(testdir)]; + +/* + * Create the test directory, and change into it, remembering + * where we came from. + */ + +static +void +startup(void) +{ + if (getcwd(startpoint, sizeof(startpoint))==NULL) { + err(1, "getcwd (not in test dir)"); + } + + if (mkdir(testdir, 0775) < 0) { + err(1, "%s: mkdir", testdir); + } + + if (chdir(testdir) < 0) { + err(1, "%s: chdir", testdir); + } +} + +/* + * Remove the test directory. + * + * Note that even though it's the current directory, we can't do it + * with rmdir(".") - what that would try to do is remove the "." entry + * from the current directory, which is justifiably prohibited. + */ + +static +void +killdir(void) +{ + char tmp[PATH_MAX]; + + snprintf(tmp, sizeof(tmp), "%s/%s", startpoint, testdir); + if (rmdir(tmp)<0) { + err(1, "%s: rmdir", tmp); + } +} + +/* + * Leave the test directory and go back to where we came from, so we + * can try again. + */ + +static +void +finish(void) +{ + if (chdir(startpoint)<0) { + err(1, "%s: chdir", startpoint); + } +} + +/*************************************************************/ + +/* + * Basic test - just try removing the directory without doing anything + * evil. + */ +static +void +test1(void) +{ + printf("Making %s\n", testdir); + startup(); + + printf("Removing %s while in it\n", testdir); + killdir(); + + printf("Leaving the test directory\n"); + finish(); +} + +/* + * Now do it while we also have the directory open. + */ + +static +void +test2(void) +{ + int fd; + + printf("Now trying with the directory open...\n"); + startup(); + fd = open(".", O_RDONLY); + if (fd<0) { + err(1, ".: open"); + } + killdir(); + finish(); + + /* close *after* leaving, just for excitement */ + if (close(fd)<0) { + err(1, "removed %s: close", testdir); + } +} + +/* + * Now see if . and .. work after rmdir. + */ + +static +void +test3(void) +{ + char buf[PATH_MAX]; + int fd; + + printf("Checking if . exists after rmdir\n"); + startup(); + killdir(); + + fd = open(".", O_RDONLY); + if (fd<0) { + switch (errno) { + case EINVAL: + case EIO: + case ENOENT: + break; + default: + err(1, "."); + break; + } + } + else { + close(fd); + } + + fd = open("..", O_RDONLY); + if (fd<0) { + switch (errno) { + case EINVAL: + case EIO: + case ENOENT: + break; + default: + err(1, ".."); + break; + } + } + else { + warnx("..: openable after rmdir - might be bad"); + close(fd); + } + + snprintf(buf, sizeof(buf), "../%s", testdir); + fd = open(buf, O_RDONLY); + if (fd<0) { + switch (errno) { + case EINVAL: + case EIO: + case ENOENT: + break; + default: + err(1, "%s", buf); + break; + } + } + else { + errx(1, "%s: works after rmdir", buf); + } + + finish(); +} + +/* + * Now try to create files. + */ + +static +void +test4(void) +{ + char buf[4096]; + int fd; + + printf("Checking if creating files works after rmdir...\n"); + startup(); + killdir(); + + fd = open("newfile", O_WRONLY|O_CREAT|O_TRUNC, 0664); + if (fd<0) { + switch (errno) { + case EINVAL: + case EIO: + case ENOENT: + break; + default: + err(1, "%s", buf); + break; + } + } + else { + warnx("newfile: creating files after rmdir works"); + warnx("(this is only ok if the space gets reclaimed)"); + + /* + * Waste a bunch of space so we'll be able to tell + */ + memset(buf, 'J', sizeof(buf)); + write(fd, buf, sizeof(buf)); + write(fd, buf, sizeof(buf)); + write(fd, buf, sizeof(buf)); + write(fd, buf, sizeof(buf)); + close(fd); + } + + finish(); +} + +/* + * Now try to create directories. + */ + +static +void +test5(void) +{ + printf("Checking if creating subdirs works after rmdir...\n"); + startup(); + killdir(); + + if (mkdir("newdir", 0775)<0) { + switch (errno) { + case EINVAL: + case EIO: + case ENOENT: + break; + default: + err(1, "mkdir in removed dir"); + break; + } + } + else { + warnx("newfile: creating directories after rmdir works"); + warnx("(this is only ok if the space gets reclaimed)"); + + /* + * Waste a bunch of space so we'll be able to tell + */ + mkdir("newdir/t0", 0775); + mkdir("newdir/t1", 0775); + mkdir("newdir/t2", 0775); + mkdir("newdir/t3", 0775); + mkdir("newdir/t4", 0775); + mkdir("newdir/t5", 0775); + } + + finish(); +} + +/* + * Now try listing the directory. + */ +static +void +test6(void) +{ + char buf[PATH_MAX]; + int fd, len; + + printf("Now trying to list the directory...\n"); + startup(); + fd = open(".", O_RDONLY); + if (fd<0) { + err(1, ".: open"); + } + killdir(); + + while ((len = getdirentry(fd, buf, sizeof(buf)-1))>0) { + if ((unsigned)len >= sizeof(buf)-1) { + errx(1, ".: getdirentry: returned invalid length"); + } + buf[len] = 0; + if (!strcmp(buf, ".") || !strcmp(buf, "..")) { + /* these are allowed to appear */ + continue; + } + errx(1, ".: getdirentry: returned unexpected name %s", buf); + } + if (len==0) { + /* EOF - ok */ + } + else { /* len < 0 */ + switch (errno) { + case EINVAL: + case EIO: + break; + default: + err(1, ".: getdirentry"); + break; + } + } + + finish(); + + /* close *after* leaving, just for excitement */ + if (close(fd)<0) { + err(1, "removed %s: close", testdir); + } +} + +/* + * Try getcwd. + */ +static +void +test7(void) +{ + char buf[PATH_MAX]; + + startup(); + killdir(); + if (getcwd(buf, sizeof(buf))==NULL) { + switch (errno) { + case EINVAL: + case EIO: + case ENOENT: + break; + default: + err(1, "getcwd after removing %s", testdir); + break; + } + } + else { + errx(1, "getcwd after removing %s: succeeded (got %s)", + testdir, buf); + } + + finish(); +} + +/**************************************************************/ + +int +main(void) +{ + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + + printf("Whew... survived.\n"); + return 0; +} diff --git a/userland/testbin/rmtest/Makefile b/userland/testbin/rmtest/Makefile new file mode 100644 index 0000000..2034d44 --- /dev/null +++ b/userland/testbin/rmtest/Makefile @@ -0,0 +1,11 @@ +# Makefile for rmtest + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=rmtest +SRCS=rmtest.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/rmtest/rmtest.c b/userland/testbin/rmtest/rmtest.c new file mode 100644 index 0000000..376236c --- /dev/null +++ b/userland/testbin/rmtest/rmtest.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * rmtest.c + * + * Tests file system synchronization by deleting an open file and + * then attempting to read it. + * + * This should run correctly when the file system assignment is complete. + */ + +#include +#include +#include +#include +#include +#include + +#define TEST "rmdata" +#define TESTDATA "I wish I was a headlight. -- Jerry Garcia" +#define TESTLEN (sizeof(TESTDATA)-1) + +static +void +dorm(int fd) +{ + /* + * This used to spawn a copy of /bin/rm, but that's silly. + * However, we will do the remove() from a subprocess, so + * that various kinds of improper hacks to make this test + * run won't work. + * + * Close the file in the subprocess, for similar reasons. + */ + + pid_t pid; + int status; + + pid = fork(); + if (pid<0) { + err(1, "fork"); + } + if (pid==0) { + /* child process */ + close(fd); + if (remove(TEST)) { + err(1, "%s: remove", TEST); + } + _exit(0); + } + /* parent process */ + if (waitpid(pid, &status, 0)<0) { + err(1, "waitpid"); + } + else if (WIFSIGNALED(status)) { + warn("child process exited with signal %d", WTERMSIG(status)); + } + else if (WEXITSTATUS(status) != 0) { + warnx("child process exited with code %d",WEXITSTATUS(status)); + } +} + +static +int +same(const char *a, const char *b, int len) +{ + while (len-- > 0) { + if (*a++ != *b++) return 0; + } + return 1; +} + +int +main(void) +{ + int file, len; + char buf[TESTLEN]; + + /* create test data file */ + file = open(TEST, O_WRONLY | O_CREAT | O_TRUNC, 0664); + write(file, TESTDATA, TESTLEN); + close(file); + + /* make sure the data is there */ + file = open(TEST, O_RDONLY); + len = read(file, buf, TESTLEN); + if (len < 0) { + warn("read: before deletion"); + } + else if (len < (int)TESTLEN) { + warnx("read: before deletion: short count %d", len); + } + if (!same(buf, TESTDATA, TESTLEN)) { + errx(1, "Failed: data read back was not the same"); + } + + /* rewind the file */ + if (lseek(file, 0, SEEK_SET)) { + err(1, "lseek"); + } + + /* now spawn our killer and wait for it to do its work */ + dorm(file); + + /* we should be still able to read the data */ + memset(buf, '\0', TESTLEN); + len = read(file, buf, TESTLEN); + if (len < 0) { + warn("read: after deletion"); + } + else if (len < (int)TESTLEN) { + warnx("read: after deletion: short count %d", len); + } + + if (!same(buf, TESTDATA, TESTLEN)) { + errx(1, "Failed: data read after deletion was not the same"); + } + + /* ok, close the file and it should go away */ + close(file); + + /* try to open it again */ + file = open(TEST, O_RDONLY); + if (file >= 0) { + close(file); + errx(1, "Failed: the file could still be opened"); + } + + if (errno!=ENOENT) { + err(1, "Unexpected error reopening the file"); + } + + printf("Succeeded!\n"); + + return 0; +} diff --git a/userland/testbin/sbrktest/Makefile b/userland/testbin/sbrktest/Makefile new file mode 100644 index 0000000..41a71fa --- /dev/null +++ b/userland/testbin/sbrktest/Makefile @@ -0,0 +1,11 @@ +# Makefile for sbrktest + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=sbrktest +SRCS=sbrktest.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/sbrktest/sbrktest.c b/userland/testbin/sbrktest/sbrktest.c new file mode 100644 index 0000000..b4a626b --- /dev/null +++ b/userland/testbin/sbrktest/sbrktest.c @@ -0,0 +1,1148 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define _PATH_RANDOM "random:" + +/* + * Caution: OS/161 doesn't provide any way to get this properly from + * the kernel. The page size is 4K on almost all hardware... but not + * all. If porting to certain weird machines this will need attention. + */ +#define PAGE_SIZE 4096 + +//////////////////////////////////////////////////////////// +// support code + +static +int +geti(void) +{ + int val=0; + int ch, digits=0; + + while (1) { + ch = getchar(); + if (ch=='\n' || ch=='\r') { + putchar('\n'); + break; + } + else if ((ch=='\b' || ch==127) && digits>0) { + printf("\b \b"); + val = val/10; + digits--; + } + else if (ch>='0' && ch<='9') { + putchar(ch); + val = val*10 + (ch-'0'); + digits++; + } + else { + putchar('\a'); + } + } + + if (digits==0) { + return -1; + } + return val; +} + +static +unsigned long +getseed(void) +{ + int fd, len; + unsigned long seed; + + fd = open(_PATH_RANDOM, O_RDONLY); + if (fd < 0) { + err(1, "%s", _PATH_RANDOM); + } + len = read(fd, &seed, sizeof(seed)); + if (len < 0) { + err(1, "%s", _PATH_RANDOM); + } + else if (len < (int)sizeof(seed)) { + errx(1, "%s: Short read", _PATH_RANDOM); + } + close(fd); + + return seed; +} + +static +pid_t +dofork(void) +{ + pid_t pid; + + pid = fork(); + if (pid < 0) { + err(1, "fork"); + } + return pid; +} + +static +void +dowait(pid_t pid) +{ + int status; + int result; + + result = waitpid(pid, &status, 0); + if (result == -1) { + err(1, "waitpid"); + } + if (WIFSIGNALED(status)) { + errx(1, "child: Signal %d", WTERMSIG(status)); + } + if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { + errx(1, "child: Exit %d", WEXITSTATUS(status)); + } +} + +static +void +say(const char *msg) +{ + /* Use one write so it's atomic (printf usually won't be) */ + write(STDOUT_FILENO, msg, strlen(msg)); +} + +//////////////////////////////////////////////////////////// +// memory checking + +/* + * Fill a page of memory with a test pattern. + */ +static +void +markpage(volatile void *baseptr, unsigned pageoffset) +{ + volatile char *pageptr; + size_t n, i; + volatile unsigned long *pl; + unsigned long val; + + pageptr = baseptr; + pageptr += (size_t)PAGE_SIZE * pageoffset; + + pl = (volatile unsigned long *)pageptr; + n = PAGE_SIZE / sizeof(unsigned long); + + for (i=0; i 0; ) { + (void)dosbrk(-PAGE_SIZE); + for (j=0; j 0 && i % dot == 0) { + printf("."); + } + } + if (dot > 0) { + printf("\n"); + } + + printf("Testing each page.\n"); + bad = false; + for (i=0; i 0)) { + if (dot > 0) { + printf("\n"); + } + warnx("FAILED: data corrupt"); + bad = true; + } + if (dot > 0 && i % dot == 0) { + printf("."); + } + } + if (dot > 0) { + printf("\n"); + } + if (bad) { + exit(1); + } + printf("Passed sbrk test 9 (part 2/5)\n"); + + printf("Freeing the memory.\n"); + (void)dosbrk(-size); + printf("Passed sbrk test 9 (part 3/5)\n"); + + printf("Allocating the memory again.\n"); + (void)dosbrk(size); + printf("Passed sbrk test 9 (part 4/5)\n"); + + printf("And really freeing it.\n"); + (void)dosbrk(-size); + printf("Passed sbrk test 9 (all)\n"); +} + +/* + * Allocate all of memory one page at a time. The same restrictions + * and considerations apply as above. + */ +static +void +test10(void) +{ + void *p, *op; + unsigned i, n; + bool bad; + + printf("Allocating all of memory one page at a time:\n"); + op = dosbrk(0); + n = 0; + while ((p = sbrk(PAGE_SIZE)) != (void *)-1) { + markpagelight(op, n); + n++; + } + printf("Got %u pages (%zu bytes).\n", n, (size_t)PAGE_SIZE * n); + + printf("Now freeing them.\n"); + bad = false; + for (i=0; i (large ? 128 : 32)) { + neg = 1; + } + if (neg) { + dosbrk(-(pages * PAGE_SIZE)); + num -= pages; + } + else { + dosbrk(pages * PAGE_SIZE); + for (j=0; j 1) { + for (i=1; i +#include +#include +#include + +#include "tasks.h" + +#define RIGHT 184621353 + +/* + * comparison functions for qsort + */ +static +int +uintcmp(const void *av, const void *bv) +{ + unsigned a = *(const unsigned *)av; + unsigned b = *(const unsigned *)bv; + + if (a < b) { + return -1; + } + if (a > b) { + return 1; + } + return 0; +} + +static +int +altcmp(const void *av, const void *bv) +{ + unsigned a = *(const unsigned *)av; + unsigned b = *(const unsigned *)bv; + unsigned ax = (a & 0xffff0000) >> 16; + unsigned ay = a & 0xffff; + unsigned bx = (b & 0xffff0000) >> 16; + unsigned by = b & 0xffff; + + if (ax < bx) { + return 1; + } + if (ax > bx) { + return -1; + } + if (ay < by) { + return -1; + } + if (ay > by) { + return 1; + } + return 0; +} + +#if 0 +/* + * Shuffle an array. + */ +static +void +shuffle(unsigned *p, unsigned n) +{ + unsigned i, x, t; + + for (i=0; i +#include +#include +#include +#include +#include +#include +#include + +#include "usem.h" +#include "tasks.h" +#include "results.h" + +#define STARTSEM "sem:start" + +struct usem startsem; + +/* + * Task hook function that does nothing. + */ +static +void +nop(unsigned groupid, unsigned count) +{ + (void)groupid; + (void)count; +} + +/* + * Wrapper for wait. + */ +static +unsigned +dowait(pid_t pid) +{ + int r; + int status; + + r = waitpid(pid, &status, 0); + if (r < 0) { + err(1, "waitpid"); + } + if (WIFSIGNALED(status)) { + warnx("pid %d signal %d", pid, WTERMSIG(status)); + return 1; + } + if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { + warnx("pid %d exit %d", pid, WEXITSTATUS(status)); + return 1; + } + return 0; +} + +/* + * Do a task group: fork the processes, then wait for them. + */ +static +void +runtaskgroup(unsigned count, + void (*prep)(unsigned, unsigned), + void (*task)(unsigned, unsigned), + void (*cleanup)(unsigned, unsigned), + unsigned groupid) +{ + pid_t mypids[count]; + unsigned i; + unsigned failures = 0; + time_t secs; + unsigned long nsecs; + + prep(groupid, count); + + for (i=0; i 0) { + calcresult(0, startsecs, startnsecs, buf, sizeof(buf)); + printf("Thinkers: %s\n", buf); + } + + if (numgrinders > 0) { + calcresult(1, startsecs, startnsecs, buf, sizeof(buf)); + printf("Grinders: %s\n", buf); + } + + for (i=0; i +#include +#include + +#include "usem.h" +#include "tasks.h" + +#define MAXCOUNT 64 +#define PONGLOOPS 1000 +//#define VERBOSE_PONG + +static struct usem sems[MAXCOUNT]; +static unsigned nsems; + +/* + * Set up the semaphores. This happens in the task director process, + * so if we have multiple pong groups each has its own sems[] array. + * (at least if the VM works) + * + * Note that we don't open the semaphores in the director process; + * that way each task process has its own file handles and they don't + * interfere with each other if file handle locking isn't so great. + */ +void +pong_prep(unsigned groupid, unsigned count) +{ + unsigned i; + + if (count > MAXCOUNT) { + err(1, "pong: too many pongers -- recompile pong.c"); + } + for (i=0; i 0 || id > 0) { + P(&sems[id]); + } +#ifdef VERBOSE_PONG + printf(" %u", id); +#else + if (nextid == 0 && i % 16 == 0) { + putchar('.'); + } +#endif + V(&sems[nextid]); + } + if (id == 0) { + P(&sems[id]); + } +#ifdef VERBOSE_PONG + putchar('\n'); +#else + if (nextid == 0) { + putchar('\n'); + } +#endif +} + +/* + * Pong back and forth. This runs the tasks with middle numbers more + * often. + */ +static +void +pong_reciprocating(unsigned id) +{ + unsigned i, n; + unsigned nextfwd, nextback; + unsigned gofwd = 1; + + if (id == 0) { + nextfwd = nextback = 1; + n = PONGLOOPS; + } + else if (id == nsems - 1) { + nextfwd = nextback = nsems - 2; + n = PONGLOOPS; + } + else { + nextfwd = id + 1; + nextback = id - 1; + n = PONGLOOPS * 2; + } + + for (i=0; i 0 || id > 0) { + P(&sems[id]); + } +#ifdef VERBOSE_PONG + printf(" %u", id); +#else + if (id == 0 && i % 16 == 0) { + putchar('.'); + } +#endif + if (gofwd) { + V(&sems[nextfwd]); + gofwd = 0; + } + else { + V(&sems[nextback]); + gofwd = 1; + } + } + if (id == 0) { + P(&sems[id]); + } +#ifdef VERBOSE_PONG + putchar('\n'); +#else + if (id == 0) { + putchar('\n'); + } +#endif +} + +/* + * Do the pong thing. + */ +void +pong(unsigned groupid, unsigned id) +{ + unsigned idfwd, idback; + + (void)groupid; + + idfwd = (id + 1) % nsems; + idback = (id + nsems - 1) % nsems; + usem_open(&sems[id]); + usem_open(&sems[idfwd]); + usem_open(&sems[idback]); + + waitstart(); + pong_cyclic(id); +#ifdef VERBOSE_PONG + printf("--------------------------------\n"); +#endif + pong_reciprocating(id); +#ifdef VERBOSE_PONG + printf("--------------------------------\n"); +#endif + pong_cyclic(id); + + usem_close(&sems[id]); + usem_close(&sems[idfwd]); + usem_close(&sems[idback]); +} diff --git a/userland/testbin/schedpong/results.c b/userland/testbin/schedpong/results.c new file mode 100644 index 0000000..bffd491 --- /dev/null +++ b/userland/testbin/schedpong/results.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2015 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +#include "results.h" + +#define RESULTSFILE "endtimes" + +static int resultsfile = -1; + +/* + * Create the file that the timing results are written to. + * This is done first, in the main process. + */ +void +createresultsfile(void) +{ + int fd; + + assert(resultsfile == -1); + + fd = open(RESULTSFILE, O_RDWR|O_CREAT|O_TRUNC, 0664); + if (fd < 0) { + err(1, "%s", RESULTSFILE); + } + if (close(fd) == -1) { + warn("%s: close", RESULTSFILE); + } +} + +/* + * Remove the timing results file. + * This is done last, in the main process. + */ +void +destroyresultsfile(void) +{ + if (remove(RESULTSFILE) == -1) { + if (errno != ENOSYS) { + warn("%s: remove", RESULTSFILE); + } + } +} + +/* + * Open the timing results file. This is done separately for writing + * in each process to avoid sharing the seek position (which would + * then require extra semaphoring to coordinate...) and afterwards + * done for reading in the main process. + */ +void +openresultsfile(int openflags) +{ + assert(openflags == O_RDONLY || openflags == O_WRONLY); + assert(resultsfile == -1); + + resultsfile = open(RESULTSFILE, openflags, 0); + if (resultsfile < 0) { + err(1, "%s", RESULTSFILE); + } +} + +/* + * Close the timing results file. + */ +void +closeresultsfile(void) +{ + assert(resultsfile >= 0); + + if (close(resultsfile) == -1) { + warn("%s: close", RESULTSFILE); + } + resultsfile = -1; +} + +/* + * Write a result into the timing results file. + */ +void +putresult(unsigned groupid, time_t secs, unsigned long nsecs) +{ + off_t pos; + ssize_t r; + + assert(resultsfile >= 0); + + pos = groupid * (sizeof(secs) + sizeof(nsecs)); + if (lseek(resultsfile, pos, SEEK_SET) == -1) { + err(1, "%s: lseek", RESULTSFILE); + } + r = write(resultsfile, &secs, sizeof(secs)); + if (r < 0) { + err(1, "%s: write (seconds)", RESULTSFILE); + } + if ((size_t)r < sizeof(secs)) { + errx(1, "%s: write (seconds): Short write", RESULTSFILE); + } + r = write(resultsfile, &nsecs, sizeof(nsecs)); + if (r < 0) { + err(1, "%s: write (nsecs)", RESULTSFILE); + } + if ((size_t)r < sizeof(nsecs)) { + errx(1, "%s: write (nsecs): Short write", RESULTSFILE); + } +} + +/* + * Read a result from the timing results file. + */ +void +getresult(unsigned groupid, time_t *secs, unsigned long *nsecs) +{ + off_t pos; + ssize_t r; + + assert(resultsfile >= 0); + + pos = groupid * (sizeof(*secs) + sizeof(*nsecs)); + if (lseek(resultsfile, pos, SEEK_SET) == -1) { + err(1, "%s: lseek", RESULTSFILE); + } + r = read(resultsfile, secs, sizeof(*secs)); + if (r < 0) { + err(1, "%s: read (seconds)", RESULTSFILE); + } + if ((size_t)r < sizeof(*secs)) { + errx(1, "%s: read (seconds): Unexpected EOF", RESULTSFILE); + } + r = read(resultsfile, nsecs, sizeof(*nsecs)); + if (r < 0) { + err(1, "%s: read (nsecs)", RESULTSFILE); + } + if ((size_t)r < sizeof(*nsecs)) { + errx(1, "%s: read (nsecs): Unexpected EOF", RESULTSFILE); + } +} diff --git a/userland/testbin/schedpong/results.h b/userland/testbin/schedpong/results.h new file mode 100644 index 0000000..b7363a4 --- /dev/null +++ b/userland/testbin/schedpong/results.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +void createresultsfile(void); +void destroyresultsfile(void); +void openresultsfile(int openflags); +void closeresultsfile(void); +void putresult(unsigned groupid, time_t secs, unsigned long nsecs); +void getresult(unsigned groupid, time_t *secs, unsigned long *nsecs); diff --git a/userland/testbin/schedpong/tasks.h b/userland/testbin/schedpong/tasks.h new file mode 100644 index 0000000..31c61ed --- /dev/null +++ b/userland/testbin/schedpong/tasks.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +void waitstart(void); + +void think(unsigned groupid, unsigned id); +void grind(unsigned groupid, unsigned id); + +void pong_prep(unsigned groupid, unsigned count); +void pong_cleanup(unsigned groupid, unsigned count); +void pong(unsigned groupid, unsigned id); diff --git a/userland/testbin/schedpong/think.c b/userland/testbin/schedpong/think.c new file mode 100644 index 0000000..a5188f5 --- /dev/null +++ b/userland/testbin/schedpong/think.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "tasks.h" + +/* + * think - cpu-bound task + * + * All we do is loop. + */ +void +think(unsigned groupid, unsigned id) +{ + volatile unsigned long k, m; + volatile unsigned i; + + (void)groupid; + (void)id; + + waitstart(); + + k = 15; + m = 7; +#define LOOPCOUNT 35000000 + for (i=0; i +#include +#include +#include +#include + +#include "usem.h" + +void +usem_init(struct usem *sem, const char *namefmt, ...) +{ + va_list ap; + + va_start(ap, namefmt); + vsnprintf(sem->name, sizeof(sem->name), namefmt, ap); + va_end(ap); + + sem->fd = open(sem->name, O_RDWR|O_CREAT|O_TRUNC, 0664); + if (sem->fd < 0) { + err(1, "%s: create", sem->name); + } + close(sem->fd); + sem->fd = -1; +} + +void +usem_open(struct usem *sem) +{ + sem->fd = open(sem->name, O_RDWR); + if (sem->fd < 0) { + err(1, "%s: open", sem->name); + } +} + +void +usem_close(struct usem *sem) +{ + if (close(sem->fd) == -1) { + warn("%s: close", sem->name); + } +} + +void +usem_cleanup(struct usem *sem) +{ + (void)remove(sem->name); +} + +void +Pn(struct usem *sem, unsigned count) +{ + ssize_t r; + char c[count]; + + r = read(sem->fd, c, count); + if (r < 0) { + err(1, "%s: read", sem->name); + } + if ((size_t)r < count) { + errx(1, "%s: read: unexpected EOF", sem->name); + } +} + +void +P(struct usem *sem) +{ + Pn(sem, 1); +} + +void +Vn(struct usem *sem, unsigned count) +{ + ssize_t r; + char c[count]; + + /* semfs does not use these values, but be conservative */ + memset(c, 0, count); + + r = write(sem->fd, c, count); + if (r < 0) { + err(1, "%s: write", sem->name); + } + if ((size_t)r < count) { + errx(1, "%s: write: Short count", sem->name); + } +} + +void +V(struct usem *sem) +{ + Vn(sem, 1); +} diff --git a/userland/testbin/schedpong/usem.h b/userland/testbin/schedpong/usem.h new file mode 100644 index 0000000..8646ee2 --- /dev/null +++ b/userland/testbin/schedpong/usem.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015 + * The President and Fellows of Harvard College. + * Written by David A. Holland. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Semaphore structure. + */ +struct usem { + char name[32]; + int fd; +}; + +/* XXX this should be in sys/cdefs.h */ +#if defined(__clang__) || defined(__GNUC__) +#define __PF(a, b) __attribute__((__format__(__printf__, a, b))) +#else +#define __PF(a, b) +#endif + +__PF(2, 3) void usem_init(struct usem *sem, const char *namefmt, ...); +void usem_open(struct usem *sem); +void usem_close(struct usem *sem); +void usem_cleanup(struct usem *sem); +void Pn(struct usem *sem, unsigned count); +void P(struct usem *sem); +void Vn(struct usem *sem, unsigned count); +void V(struct usem *sem); diff --git a/userland/testbin/sort/Makefile b/userland/testbin/sort/Makefile new file mode 100644 index 0000000..f79be88 --- /dev/null +++ b/userland/testbin/sort/Makefile @@ -0,0 +1,11 @@ +# Makefile for sort + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=sort +SRCS=sort.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/sort/sort.c b/userland/testbin/sort/sort.c new file mode 100644 index 0000000..6f90c4f --- /dev/null +++ b/userland/testbin/sort/sort.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* sort.c + * Test program to sort a large number of integers. + * + * Intention is to stress virtual memory system. + * + * Once the virtual memory assignment is complete, your system + * should survive this. + */ + +#include +#include +#include + +/* Larger than physical memory */ +#define SIZE (144*1024) + + +/* + * Quicksort. + * + * This used to be a bubble sort, which was ok but slow in nachos with + * 4k of memory and SIZE of 1024. However, with SIZE of 147,456 bubble + * sort is completely unacceptable. + * + * Also, quicksort has somewhat more interesting memory usage patterns. + */ + +static +void +sort(int *arr, int size) +{ + static int tmp[SIZE]; + int pivot, i, j, k; + + if (size<2) { + return; + } + + pivot = size/2; + sort(arr, pivot); + sort(&arr[pivot], size-pivot); + + i = 0; + j = pivot; + k = 0; + while (i A[i+1]) { + errx(1, "Failed: A[%d] is %d, A[%d] is %d", + i, A[i], i+1, A[i+1]); + } + } + warnx("Passed."); +} + +int +main(void) +{ + initarray(); + sort(A, SIZE); + check(); + return 0; +} diff --git a/userland/testbin/sparsefile/Makefile b/userland/testbin/sparsefile/Makefile new file mode 100644 index 0000000..cfdab81 --- /dev/null +++ b/userland/testbin/sparsefile/Makefile @@ -0,0 +1,11 @@ +# Makefile for sparsefile + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=sparsefile +SRCS=sparsefile.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/sparsefile/sparsefile.c b/userland/testbin/sparsefile/sparsefile.c new file mode 100644 index 0000000..93cd5bf --- /dev/null +++ b/userland/testbin/sparsefile/sparsefile.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Create a sparse file by writing one byte to the end of it. + * + * Should work on emufs (emu0:) once the basic system calls are done, + * and should work on SFS when the file system assignment is + * done. Sufficiently small files should work on SFS even before that + * assignment. + */ + +#include +#include +#include +#include +#include + +int +main(int argc, char *argv[]) +{ + const char *filename; + int size; + int fd; + int r; + char byte; + + if (argc != 3) { + errx(1, "Usage: sparsefile "); + } + + filename = argv[1]; + size = atoi(argv[2]); + byte = '\n'; + + if (size == 0) { + err(1, "Sparse files of length zero are not meaningful"); + } + + printf("Creating a sparse file of size %d\n", size); + + fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC); + if (fd < 0) { + err(1, "%s: create", filename); + } + + if (lseek(fd, size-1, SEEK_SET) == -1) { + err(1, "%s: lseek", filename); + } + r = write(fd, &byte, 1); + if (r < 0) { + err(1, "%s: write", filename); + } + else if (r != 1) { + errx(1, "%s: write: Unexpected result count %d", filename, r); + } + + close(fd); + + return 0; +} diff --git a/userland/testbin/tail/Makefile b/userland/testbin/tail/Makefile new file mode 100644 index 0000000..e0a28ce --- /dev/null +++ b/userland/testbin/tail/Makefile @@ -0,0 +1,11 @@ +# Makefile for tail + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=tail +SRCS=tail.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/tail/tail.c b/userland/testbin/tail/tail.c new file mode 100644 index 0000000..6c2b693 --- /dev/null +++ b/userland/testbin/tail/tail.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * tail.c + * + * Outputs a file beginning at a specific location. + * Usage: tail + * + * This may be useful for testing during the file system assignment. + */ + +#include +#include +#include + +#define BUFSIZE 1000 + +/* Put buffer in data space. We know that the program should allocate as */ +/* much data space as required, but stack space is tight. */ + +char buffer[BUFSIZE]; + +static +void +tail(int file, off_t where, const char *filename) +{ + int len; + + if (lseek(file, where, SEEK_SET)<0) { + err(1, "%s", filename); + } + + while ((len = read(file, buffer, sizeof(buffer))) > 0) { + write(STDOUT_FILENO, buffer, len); + } +} + +int +main(int argc, char **argv) +{ + int file; + + if (argc < 3) { + errx(1, "Usage: tail "); + } + file = open(argv[1], O_RDONLY); + if (file < 0) { + err(1, "%s", argv[1]); + } + tail(file, atoi(argv[2]), argv[1]); + close(file); + return 0; +} + diff --git a/userland/testbin/tictac/Makefile b/userland/testbin/tictac/Makefile new file mode 100644 index 0000000..3cd253a --- /dev/null +++ b/userland/testbin/tictac/Makefile @@ -0,0 +1,11 @@ +# Makefile for tictac + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=tictac +SRCS=tictac.c +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/tictac/tictac.c b/userland/testbin/tictac/tictac.c new file mode 100644 index 0000000..d65ec27 --- /dev/null +++ b/userland/testbin/tictac/tictac.c @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * These are some constants we use in our program. + * EMPTY is used to indicate empty spaces in the board. + * X_MARKER and O_MARKER are used to indicate where each + * players has moved + * DIM indicates the size of the board. For now + * we assume a conventional 3x3 playing board. + * + * This should work once the basic system calls are complete. + */ + +#include +#include + +#define NEWLINE 012 +#define EMPTY 0 +#define X_PLAYER 1 +#define O_PLAYER 2 +#define X_MARKER 1 +#define O_MARKER 2 +#define DIM 3 +#define DIMCHAR "2" +#define MAXSTRING 100 + +typedef enum { FALSE, TRUE } bool; + +/* Function Declarations */ +bool ask_yesno(const char *msg); +bool do_move(int player); +void initialize_board(void); +bool is_win(int x, int y); +int read_string(char *buf, int length); +void print_board(void); +void print_instructions(void); +bool win_column(int y, int marker); +bool win_diag_left(int x, int y, int marker); +bool win_diag_right(int x, int y, int marker); +bool win_row(int x, int marker); +bool Strcmp(const char *a, const char *b); + + +/* + * The board is gloabally defined. + */ +int board[DIM][DIM]; + +/* Console I/O routines */ + +int +main(void) +{ + bool win = FALSE; + int move, max_moves; + int player; + + print_instructions(); + max_moves = DIM * DIM; /* Maximum number of moves in a game */ + + while (TRUE) { + initialize_board(); + for (move = 1; move <= max_moves; move++) { + player = move % 2 == 0 ? 2 : 1; + win = do_move(player); + print_board(); + if (win) { + printf("Player %d, you WON!\n\n", player); + break; /* out of for loop */ + } + } + /* + * If we got here by falling through the loop, then it is a + * tie game. + */ + if (!win) + printf("Tie Game!\n\n"); + if (!ask_yesno("Do you wish to play again?")) + break; /* out of while loop */ + } + return 0; +} + +/* + * print_instructions + * Displays the instructions for the game. + * Input + * None + * Output + * None + * Error + * None + */ +void +print_instructions(void) +{ + printf("Welcome to tic-tac-toe!\n"); + printf("Player 1 always plays X and player 2 always play O\n"); + printf("Good luck!\n\n\n"); +} + +void +/* + * print_board + * Display the DIM by DIM board. + * Input + * None. + * Output + * None. + * Errors + * None. + */ +print_board(void) +{ + int i, j; + + /* Print labels across the top */ + printf("\n 0 1 2\n"); + + for (i = 0; i < DIM; i++) { + /* Print row labels */ + printf(" %d ", i); + for (j = 0; j < DIM; j++) { + switch (board[i][j]) { + case EMPTY: printf(" "); break; + case X_MARKER: printf(" X "); break; + case O_MARKER: printf(" O "); break; + default: printf("???"); break; + } + } + printf("\n"); + } + printf("\n"); +} + +/* + * ask_yesno (taken from histo.c) + * This function prints out the message and asks the user to respond + * with either a yes or a no. It continues asking the questions until + * a valid reply is encountered and returns TRUE/FALSE indicating + * the answer (True for yes, false for no). + * + * Input + * Question to be asked. + * Output + * TRUE if response is yes + * FALSE if response is no + * Error + * None + */ +bool +ask_yesno(const char *msg) +{ + char answer[MAXSTRING]; + + while (TRUE) { + printf("%s [yes/no] ", msg); + if (read_string(answer, MAXSTRING) < 0) + return(FALSE); + if (Strcmp(answer, "yes")) + return(TRUE); + else if (Strcmp(answer, "no")) + return(FALSE); + else + printf("Please answer either yes or no\n"); + } +} + +/* + * do_move + * Processes one player move. The player enters a row and column + * and we have to determine if the square is valid (on the board) + * and that there is no mark already there. We continue to ask + * for row/column pairs until we receive a valid combination. + * Then we mark the board, check for a win, and return. + * + * Input + * player Indicates which player (1 or 2) is moving + * Output + * TRUE if this move won the game. + * FALSE if this move did not win the game. + * Error + * None + */ +bool +do_move(int player) +{ + int x, y; + char answer[MAXSTRING]; + char cx; + + printf("Player %d (%c), your move\n", player, + player == X_PLAYER ? 'X' : 'O'); + + while (TRUE) { + printf("Which row [0-%d]: ", DIM-1); + if (read_string(answer, MAXSTRING) < 0) + return(FALSE); + cx = answer[0]; + x = cx - '0'; + if (x < 0 || x >= DIM) { + printf("Invalid row; must be >= 0 and < %d\n", DIM-1); + continue; + } + printf("Which column [0-%d]: ", DIM-1); + if (read_string(answer, MAXSTRING) < 0) + return(FALSE); + cx = answer[0]; + y = cx - '0'; + if (y < 0 || y >= DIM) { + printf("Invalid column; must be >= 0 and < %d\n", + DIM-1); + continue; + } + + if (board[x][y] != EMPTY) { + printf("That location is occupied; please try again\n"); + print_board(); + } else + break; + } + board[x][y] = player == X_PLAYER ? X_MARKER : O_MARKER; + + return(is_win(x, y)); + +} + +/* + * is_win + * Checks if the move into position x, y created a tic-tac-toe. + * There are four possible ways to win -- horizontal, vertical, + * and the two diagonals; check each one using a separate routine. + * + * Four routines for checking the wins are: + * win_row The horizontal spots are all the same as this current mark. + * win_column The vertical spots are all the same as this current mark. + * win_diag_left The diagonal spots from left to right are all the + * same as the current mark. + * win_diag_right The diagonal spots from right to left are all the + * same as the current mark. + * + * Input (for all routines) + * x x coordinate + * y y coordinate + * marker the value just placed on the board. + * Output + * TRUE if player won + * FALSE otherwise + */ +bool +is_win(int x, int y) +{ + int marker; + + marker = board[x][y]; + + /* + * Note that C "short circuit evaluation". As soon as any one + * of these functions returns TRUE, we know that the expression + * is true. Therefore, we can return TRUE without executing + * any of the other routines. + */ + return(win_row(x, marker) || win_column(y, marker) || + win_diag_left(x, y, marker) || win_diag_right(x, y, marker)); +} + +/* + * Four helper functions for determining a win. + */ +bool +win_column(int y, int marker) +{ + int i; + for (i = 0; i < DIM; i++) + if (board[i][y] != marker) + return(FALSE); + return(TRUE); +} + +bool +win_row(int x, int marker) +{ + int i; + for (i = 0; i < DIM; i++) + if (board[x][i] != marker) + return(FALSE); + return(TRUE); +} + +bool +win_diag_left(int x, int y, int marker) +{ + int i; + + /* Check that move is on the diagonal */ + if (x != y) + return(FALSE); + + for (i = 0; i < DIM; i++) + if (board[i][i] != marker) + return(FALSE); + return(TRUE); +} + +bool +win_diag_right(int x, int y, int marker) +{ + int i; + + /* Check that move is on the diagonal */ + if (x + y != DIM - 1) + return(FALSE); + for (i = 0; i < DIM; i++) + if (board[i][DIM - 1 - i] != marker) + return(FALSE); + return(TRUE); +} + +void +initialize_board(void) +{ + int i, j; + + for (i = 0; i < DIM; i++) + for (j = 0; j < DIM; j++) + board[i][j] = EMPTY; +} + +int +read_string(char *buf, int length) +{ + int char_read; + int i; + + i = 0; + while ((char_read = getchar()) != EOF && char_read != NEWLINE && + i < length) { + buf[i] = (char) char_read; + i++; + putchar(char_read); + } + + if (char_read == EOF) + return(-1); + + /* + * If the input overflows the buffer, just cut it short + * at length - 1 characters. + */ + if (i >= length) + i--; + buf[i] = 0; + return(i); +} + +bool +Strcmp(const char *a, const char *b) +{ + if (a == NULL) + return(b == NULL); + if (b == NULL) + return(FALSE); + + while (*a && *b) + if (*a++ != *b++) + return(FALSE); + + return(*a == *b); + +} diff --git a/userland/testbin/triplehuge/Makefile b/userland/testbin/triplehuge/Makefile new file mode 100644 index 0000000..ef8c5fa --- /dev/null +++ b/userland/testbin/triplehuge/Makefile @@ -0,0 +1,12 @@ +# Makefile for triplehuge + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=triplehuge +SRCS=triplehuge.c +LIBS=-ltest +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" + diff --git a/userland/testbin/triplehuge/triplehuge.c b/userland/testbin/triplehuge/triplehuge.c new file mode 100644 index 0000000..af457f8 --- /dev/null +++ b/userland/testbin/triplehuge/triplehuge.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * triplehuge.c + * + * Calls three copies of "huge". + * + * When the VM assignment is complete, your system should survive this. + */ + +#include + +int +main(void) +{ + triple("/testbin/huge"); + return 0; +} diff --git a/userland/testbin/triplemat/Makefile b/userland/testbin/triplemat/Makefile new file mode 100644 index 0000000..f4b10b7 --- /dev/null +++ b/userland/testbin/triplemat/Makefile @@ -0,0 +1,11 @@ +# Makefile for triplemat + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=triplemat +SRCS=triplemat.c +LIBS=-ltest +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" diff --git a/userland/testbin/triplemat/triplemat.c b/userland/testbin/triplemat/triplemat.c new file mode 100644 index 0000000..7c5a9ed --- /dev/null +++ b/userland/testbin/triplemat/triplemat.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * triplemat.c + * + * Calls three matmult programs. + * + * When the VM assignment is complete, your system should survive this. + */ + +#include + +int +main(void) +{ + triple("/testbin/matmult"); + return 0; +} diff --git a/userland/testbin/triplesort/Makefile b/userland/testbin/triplesort/Makefile new file mode 100644 index 0000000..6e72b89 --- /dev/null +++ b/userland/testbin/triplesort/Makefile @@ -0,0 +1,11 @@ +# Makefile for triplesort + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=triplesort +SRCS=triplesort.c +LIBS=-ltest +BINDIR=/testbin + +.include "$(TOP)/mk/os161.prog.mk" diff --git a/userland/testbin/triplesort/triplesort.c b/userland/testbin/triplesort/triplesort.c new file mode 100644 index 0000000..b93ba3a --- /dev/null +++ b/userland/testbin/triplesort/triplesort.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * triplesort.c + * + * Calls three copies of /testbin/sort. + * + * When the VM assignment is complete, your system should survive this. + */ + +#include + +int +main(void) +{ + triple("/testbin/sort"); + return 0; +} diff --git a/userland/testbin/usemtest/Makefile b/userland/testbin/usemtest/Makefile new file mode 100644 index 0000000..9371447 --- /dev/null +++ b/userland/testbin/usemtest/Makefile @@ -0,0 +1,13 @@ +# Makefile for usemtest + +TOP=../../.. +.include "$(TOP)/mk/os161.config.mk" + +PROG=usemtest +SRCS=usemtest.c +BINDIR=/testbin +HOSTBINDIR=/hostbin + +.include "$(TOP)/mk/os161.prog.mk" +.include "$(TOP)/mk/os161.hostprog.mk" + diff --git a/userland/testbin/usemtest/usemtest.c b/userland/testbin/usemtest/usemtest.c new file mode 100644 index 0000000..e812e86 --- /dev/null +++ b/userland/testbin/usemtest/usemtest.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2014 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Simple test for the user-level semaphores provided by semfs, aka + * "sem:". + * + * This should mostly run once you've implemented open, read, write, + * and fork, and run fully once you've also implemented waitpid. + * + * The last part of the test will generally hang, sometimes in fork, + * unless your filetable/open-file locking is just so. + */ + +#include +#include +#include +#include +#include +#include + +#define ONCELOOPS 3 +#define TWICELOOPS 2 +#define THRICELOOPS 1 +#define LOOPS (ONCELOOPS + 2*TWICELOOPS + 3*THRICELOOPS) +#define NUMJOBS 4 + +/* + * Print to the console, one character at a time to encourage + * interleaving if the semaphores aren't working. + */ +static +void +say(const char *str) +{ + size_t i; + + for (i=0; str[i]; i++) { + putchar(str[i]); + } +} + +#if 0 /* not used */ +static +void +sayf(const char *str, ...) +{ + char buf[256]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + say(str); +} +#endif + +/* + * This should probably be in libtest. + */ +static +void +dowait(pid_t pid, unsigned num) +{ + pid_t r; + int status; + + r = waitpid(pid, &status, 0); + if (r < 0) { + warn("waitpid"); + return; + } + if (WIFSIGNALED(status)) { + warnx("pid %d (subprocess %u): Signal %d", (int)pid, + num, WTERMSIG(status)); + } + else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { + warnx("pid %d (subprocess %u): Exit %d", (int)pid, + num, WEXITSTATUS(status)); + } +} + +//////////////////////////////////////////////////////////// +// semaphore access + +/* + * Semaphore structure. + */ +struct usem { + char name[32]; + int fd; +}; + +static +void +usem_init(struct usem *sem, const char *tag, unsigned num) +{ + snprintf(sem->name, sizeof(sem->name), "sem:usemtest.%s%u", tag, num); + sem->fd = open(sem->name, O_RDWR|O_CREAT|O_TRUNC, 0664); + if (sem->fd < 0) { + err(1, "%s: create", sem->name); + } + close(sem->fd); + sem->fd = -1; +} + +static +void +usem_open(struct usem *sem) +{ + sem->fd = open(sem->name, O_RDWR); + if (sem->fd < 0) { + err(1, "%s: open", sem->name); + } +} + +static +void +usem_close(struct usem *sem) +{ + if (close(sem->fd) == -1) { + warn("%s: close", sem->name); + } +} + +static +void +usem_cleanup(struct usem *sem) +{ + (void)remove(sem->name); +} + +static +void +P(struct usem *sem) +{ + ssize_t r; + char c; + + r = read(sem->fd, &c, 1); + if (r < 0) { + err(1, "%s: read", sem->name); + } + if (r == 0) { + errx(1, "%s: read: unexpected EOF", sem->name); + } +} + +static +void +V(struct usem *sem) +{ + ssize_t r; + char c; + + r = write(sem->fd, &c, 1); + if (r < 0) { + err(1, "%s: write", sem->name); + } + if (r == 0) { + errx(1, "%s: write: short count", sem->name); + } +} + +//////////////////////////////////////////////////////////// +// test components + +static +void +child_plain(struct usem *gosem, struct usem *waitsem, unsigned num) +{ + static const char *const strings[NUMJOBS] = { + "Nitwit!", + "Blubber!", + "Oddment!", + "Tweak!", + }; + + const char *string; + unsigned i; + + string = strings[num]; + for (i=0; i +#include + +#define NTHREADS 3 +#define MAX 1<<25 + +/* counter for the loop in the threads: + This variable is shared and incremented by each + thread during his computation */ +volatile int count = 0; + +/* the 2 threads : */ +void ThreadRunner(void); +void BladeRunner(void); + +int +main(int argc, char *argv[]) +{ + int i; + + (void)argc; + (void)argv; + + for (i=0; i +#include +#include +#include + +/* + * Some initialized data. This is here to increase the chance that + * zeros[] spans page boundaries. + */ +static unsigned data_stuff[] = { + 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, + 2, 4, 6, 8, 0, 2, 4, 6, 8, 0, 2, 4, 6, 8, 0, + 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, + 2, 4, 6, 8, 0, 2, 4, 6, 8, 0, 2, 4, 6, 8, 0, + 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, + 2, 4, 6, 8, 0, 2, 4, 6, 8, 0, 2, 4, 6, 8, 0, + 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, + 2, 4, 6, 8, 0, 2, 4, 6, 8, 0, 2, 4, 6, 8, 0, + 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, + 2, 4, 6, 8, 0, 2, 4, 6, 8, 0, 2, 4, 6, 8, 0, +}; + +#define SUM_OF_DATA_STUFF 525 + +/* + * Some uninitialized (BSS, zero) data. Make it more than one page + * even if we happen to be on a machine with 8K pages. + */ +static unsigned bss_stuff[3000]; + +static +void +check_data(void) +{ + unsigned i, num, k; + + num = sizeof(data_stuff) / sizeof(data_stuff[0]); + for (k=i=0; i