init: init nachos hw01, should pass jenkins os_group_20_hw job but fail on os_group_20_ta job

This commit is contained in:
TA
2024-09-19 18:59:13 +08:00
commit 6ad2fa368f
267 changed files with 71977 additions and 0 deletions

12
code/README Normal file
View File

@@ -0,0 +1,12 @@
Building Instructions:
* got to the directory build.<host>, where <host> is your working OS
* do a "make depend" to build depenencies (DO IT!)
* do a "make" to build NachOS
Usage:
see "nachos -u" for all command line options
Building and starting user-level programs in NachOS:
* use Mips cross-compiler to build and link coff-binaries
* use coff2noff to translate the binaries to the NachOS-format
* start binary with nachos -x <path_to_file/file>

367
code/build.cygwin/Makefile Normal file
View File

@@ -0,0 +1,367 @@
# Copyright (c) 1992-1996 The Regents of the University of California.
# All rights reserved. See copyright.h for copyright notice and limitation
# of liability and disclaimer of warranty provisions.
#
# This is a GNU Makefile. It must be used with the GNU make program.
# At UW, the GNU make program is /software/gnu/bin/make.
# In many other places it is known as "gmake".
# You may wish to include /software/gnu/bin/ early in your command
# search path, so that you will be using GNU make when you type "make".
#
# About this Makefile:
# --------------------
#
# This Makefile is used to build the Nachos system, which includes
# the MIPS machine simulation and a simple operating system.
#
# There is a separate Makefile, in the "test" directory, that is
# used to build the Nachos test programs (which run on the
# simulated machine).
#
# There are several "build" directories, one for each type
# of machine in the MFCF computing environment
# (build.solaris, build.sunos, and build.ultrix), as well
# as a build directory for Linux (build.linux) and a generic
# build directory (build.other) for those who wish to try
# building Nachos on other platforms.
#
# This Makefile appears to be located in all of the build directories.
# If you edit it in one directory, the copies in all of the other
# directories appear to change as well. This is the desired behaviour,
# since this file is machine independent. (The file actually lives
# in build.solaris, with symbolic links from the other build directories.)
#
# The platform-dependent parts of make's instructions are located
# in the file Makefile.dep.
# There is a different Makefile.dep in each build directory.
#
# If you are in the MFCF environment, you should not have to edit
# the Makefile.dep files by hand. Any changes to the make instructions
# can be made in this file (see the instructions below) - they will
# apply no matter where you build Nachos.
# If you are not in the MFCF environment, e.g., if you are trying
# to build Nachos on Linux at home, you will probably need
# to edit Makefile.dep (in the appropriate build directory) to
# customize the make procedure to your environment.
#
# How to build Nachos for the first time:
# ---------------------------------------
#
# (1) Make sure than you are in the build directory for the
# type of machine you are logged in to (the "host" machine):
#
# host type examples build directory
# ----------- ----------- ----------------
#
# sparc/SunOS cayley,napier, build.sunos
# (SunOS 4.1.3) descartes
#
# sparc/Solaris picard.math, build.solaris
# (SunOS 5.x) hermite.math,
# markov.math,
# hypatia.math,
# hume.math
#
# mips/ULTRIX cantor.math build.ultrix
# (ULTRIX 4.2) noether.math
#
# If you are not sure what type of machine you are on,
# try the command "uname -a".
#
# (2) Type "make depend"
# - this computes file dependencies and records them
# at the end of the file Makefile.dep in
# your build directory. Have a look...
#
# (3) Type "make nachos" (or just "make").
# - make echos the commands it is executing, so that
# you can observe its progress. When the
# build is finished, you should have an
# executable "nachos" in the build directory.
#
# (4) There is no 4th step. You are done. Try running "./nachos -u".
#
#
# How to Re-build Nachos after you have changed the code:
#--------------------------------------------------------
#
# - The Nachos source code is located in the code subdirectories:
# threads, userprog, filesys, network, and lib. You may
# change the files in any of these directories, and you can
# add new files and/or remove files. The "machine" subdirectory
# contains the hardware simulation (which is also part of
# Nachos. You may look at it, but
# you may not change it, except as noted in machine/machine.h
# - When you want to re-make Nachos, always do it in the
# "build" directory that is appropriate for the machine
# type that you are running on.
# DO NOT TRY TO MAKE NACHOS IN THE SOURCE CODE DIRECTORIES.
#
# - IF all you have done is changed C++ code in existing files
# (since the last time you made Nachos in this build directory),
# THEN all you need to do to re-make Nachos is to type
#
# "make nachos"
#
# in the build directory.
#
# - IF you have done any of the following since the last build in
# this directory:
# added new .cc files or new .h files
# added or deleted #include's from existing files
# THEN
# you must do
# "make depend"
# followed by
# "make nachos"
#
# in the build directory.
#
# Note that is is always safe to do "make depend" followed by
# "make nachos", so if you are not sure what changes you have
# made, do "make depend".
#
# - IF you have added new files (.cc or .h) since the last build,
# you should edit this Makefile before running "make depend"
# and "make nachos".
# For new .h files, simply update the appropriate "_H" list below.
# For example, if you create a file called
# "bigfile.h" in the filesys subdirectory, you should add
# "../filesys/bigfile.h" to FILESYS_H, which is defined below
# For new .cc files, update the appropriate "_C" and "_O" lists.
# For example, if you create a file called "filetable.cc" in
# the directory "userprog", you should add
# "../userprog/filetable.cc" to USERPROG_C,
# and you should add "filetable.o" to USERPROG_O.
# Note that the entry in the "_C" list includes the subdirectory
# name, while the entry on the "_O" list does not.
#
# Some Important Notes:
# ---------------------
#
# * You can clean up all of the .o and other files left behind
# by make by typeing "make clean" in the build directory.
# * You can clean up .o and other files, as well as the nachos
# executable, DISK, core, SOCKET, and other files by typing
# make "distclean"
#
# These are good ways to save space, but the next build that
# you do after cleaning will take longer than usual, since
# much of the stuff you cleaned will need to be rebuilt.
#
# * When you build Nachos on an ULTRIX machine (in build.ultrix),
# you will get lots of warning messages like this:
#
# openfile.o: does not have gp tables for all it's sectons
#
# from the loader. Ignore them. Or better yet, figure out
# how to make them go away.
#
# The Most Important Note:
# -----------------------
#
# * If "make" is behaving strangely and you cannot figure out
# why, you should REBUILD the program FROM SCRATCH.
# Yes, it is slow.
# But, there are lots of little things that can go wrong, especially
# with all of these different types of machines available.
# Rebuilding from scratch at least gives you a known starting
# place. To rebuild from scratch, go to the appropriate
# build directory and do:
#
# make distclean
# make depend
# make nachos
#
################################################################
# READ THIS: CONFIGURING NACHOS
#
# Change DEFINES (below) to
# DEFINES = -DUSE_TLB -DFILESYS_STUB
# if you want the simulated machine to use its TLB
#
# If you want to use the real Nachos file system (based on
# the simulated disk), rather than the stub, remove
# the -DFILESYS_STUB from DEFINES.
#
# There is a a fix to the MIPS simulator to enable it to properly
# handle unaligned data access. This fix is enabled by the addition
# of "-DSIM_FIX" to the DEFINES. This should be enabled by default
# and eventually will not require the symbol definition
################################################################
DEFINES = -DFILESYS_STUB -DRDATA -DSIM_FIX
#####################################################################
#
# You might want to play with the CFLAGS, but if you use -O it may
# break the thread system. You might want to use -fno-inline if
# you need to call some inline functions from the debugger.
CFLAGS = -g -Wall -fwritable-strings $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED
LDFLAGS =
#####################################################################
CPP= cpp
CC = g++
LD = g++
AS = as
RM = rm
INCPATH = -I../network -I../filesys -I../userprog -I../threads -I../machine -I../lib
PROGRAM = nachos
#
# Edit these lists as if you add files to the source directories.
# See the instructions at the top of the file for more information.
#
LIB_H = ../lib/bitmap.h\
../lib/copyright.h\
../lib/debug.h\
../lib/hash.h\
../lib/libtest.h\
../lib/list.h\
../lib/sysdep.h\
../lib/utility.h
LIB_C = ../lib/bitmap.cc\
../lib/debug.cc\
../lib/hash.cc\
../lib/libtest.cc\
../lib/list.cc\
../lib/sysdep.cc
LIB_O = bitmap.o debug.o libtest.o sysdep.o
MACHINE_H = ../machine/callback.h\
../machine/interrupt.h\
../machine/stats.h\
../machine/timer.h\
../machine/console.h\
../machine/machine.h\
../machine/mipssim.h\
../machine/translate.h\
../machine/network.h\
../machine/disk.h
MACHINE_C = ../machine/interrupt.cc\
../machine/stats.cc\
../machine/timer.cc\
../machine/console.cc\
../machine/machine.cc\
../machine/mipssim.cc\
../machine/translate.cc\
../machine/network.cc\
../machine/disk.cc
MACHINE_O = interrupt.o stats.o timer.o console.o machine.o mipssim.o\
translate.o network.o disk.o
THREAD_H = ../threads/alarm.h\
../threads/kernel.h\
../threads/main.h\
../threads/scheduler.h\
../threads/switch.h\
../threads/synch.h\
../threads/synchlist.h\
../threads/thread.h
THREAD_C = ../threads/alarm.cc\
../threads/kernel.cc\
../threads/main.cc\
../threads/scheduler.cc\
../threads/synch.cc\
../threads/synchlist.cc\
../threads/thread.cc
THREAD_O = alarm.o kernel.o main.o scheduler.o synch.o thread.o
USERPROG_H = ../userprog/addrspace.h\
../userprog/syscall.h\
../userprog/synchconsole.h\
../userprog/noff.h
USERPROG_C = ../userprog/addrspace.cc\
../userprog/exception.cc\
../userprog/synchconsole.cc
USERPROG_O = addrspace.o exception.o synchconsole.o
FILESYS_H =../filesys/directory.h \
../filesys/filehdr.h\
../filesys/filesys.h \
../filesys/openfile.h\
../filesys/pbitmap.h\
../filesys/synchdisk.h
FILESYS_C =../filesys/directory.cc\
../filesys/filehdr.cc\
../filesys/filesys.cc\
../filesys/pbitmap.cc\
../filesys/openfile.cc\
../filesys/synchdisk.cc\
FILESYS_O =directory.o filehdr.o filesys.o pbitmap.o openfile.o synchdisk.o
NETWORK_H = ../network/post.h
NETWORK_C = ../network/post.cc
NETWORK_O = post.o
##################################################################
# You probably don't want to change anything below this point in
# the file unless you are comfortable with GNU make and know what
# you are doing...
##################################################################
THREAD_S = ../threads/switch.s
HFILES = $(LIB_H) $(MACHINE_H) $(THREAD_H) $(USERPROG_H) $(FILESYS_H) $(NETWORK_H)
CFILES = $(LIB_C) $(MACHINE_C) $(THREAD_C) $(USERPROG_C) $(FILESYS_C) $(NETWORK_C)
C_OFILES = $(LIB_O) $(MACHINE_O) $(THREAD_O) $(USERPROG_O) $(FILESYS_O) $(NETWORK_O)
S_OFILES = switch.o
OFILES = $(C_OFILES) $(S_OFILES)
$(PROGRAM): $(OFILES)
$(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM)
$(C_OFILES): %.o:
$(CC) $(CFLAGS) -c $<
switch.o: ../threads/switch.s
$(CPP) $(CPP_AS_FLAGS) -P $(INCPATH) $(HOSTCFLAGS) ../threads/switch.s > swtch.s
$(AS) -o switch.o swtch.s
depend: $(CFILES) $(HFILES)
$(CC) $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -M $(CFILES) > makedep
@echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
@echo '$$r makedep' >>eddep
@echo 'w' >>eddep
@echo 'q' >>eddep
ed - Makefile.dep < eddep
rm eddep makedep
@echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile.dep
@echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile.dep
@echo '# see make depend above' >> Makefile.dep
clean:
$(RM) -f $(OFILES)
$(RM) -f swtch.s
$(RM) -f *.s *.ii
distclean: clean
$(RM) -f $(PROGRAM)
$(RM) -f $(PROGRAM).exe
$(RM) -f DISK_?
$(RM) -f core
$(RM) -f SOCKET_?
include Makefile.dep

View File

@@ -0,0 +1,544 @@
##################################################################
# Machine Dependencies - this file is included automatically
# into the main Makefile
#
# This file contains definitions below for x86 running Linux
# It has *not* been tested!
##################################################################
HOSTCFLAGS = -Dx86 -DLINUX -DCYGWIN
#-----------------------------------------------------------------
# Do not put anything below this point - it will be destroyed by
# "make depend"
#
# DO NOT DELETE THIS LINE -- make depend uses it
# DEPENDENCIES MUST END AT END OF FILE
bitmap.o: ../lib/bitmap.cc ../lib/copyright.h ../lib/debug.h \
../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../lib/bitmap.h
debug.o: ../lib/debug.cc ../lib/copyright.h ../lib/utility.h \
../lib/debug.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h
hash.o: ../lib/hash.cc ../lib/copyright.h
libtest.o: ../lib/libtest.cc ../lib/copyright.h ../lib/libtest.h \
../lib/bitmap.h ../lib/utility.h ../lib/list.h ../lib/debug.h \
../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../lib/list.cc ../lib/hash.h ../lib/hash.cc
list.o: ../lib/list.cc ../lib/copyright.h
sysdep.o: ../lib/sysdep.cc ../lib/copyright.h ../lib/debug.h \
../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h /usr/include/unistd.h /usr/include/sys/unistd.h \
/usr/include/getopt.h /usr/include/sys/time.h \
/usr/include/sys/select.h /usr/include/time.h \
/usr/include/machine/time.h /usr/include/sys/file.h \
/usr/include/fcntl.h /usr/include/sys/fcntl.h /usr/include/sys/stat.h \
/usr/include/cygwin/stat.h /usr/include/sys/socket.h \
/usr/include/features.h /usr/include/cygwin/socket.h \
/usr/include/asm/socket.h /usr/include/cygwin/if.h \
/usr/include/cygwin/sockios.h /usr/include/cygwin/uio.h \
/usr/include/sys/un.h /usr/include/signal.h /usr/include/sys/signal.h
interrupt.o: ../machine/interrupt.cc ../lib/copyright.h \
../machine/interrupt.h ../lib/list.h ../lib/debug.h ../lib/utility.h \
../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../lib/list.cc ../machine/callback.h \
../threads/main.h ../threads/kernel.h ../threads/thread.h \
../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \
../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \
../machine/stats.h ../threads/alarm.h ../machine/timer.h
stats.o: ../machine/stats.cc ../lib/copyright.h ../lib/debug.h \
../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../machine/stats.h
timer.o: ../machine/timer.cc ../lib/copyright.h ../machine/timer.h \
../lib/utility.h ../machine/callback.h ../threads/main.h \
../lib/debug.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../threads/kernel.h ../threads/thread.h \
../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \
../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \
../lib/list.h ../lib/list.cc ../machine/interrupt.h \
../machine/stats.h ../threads/alarm.h
console.o: ../machine/console.cc ../lib/copyright.h \
../machine/console.h ../lib/utility.h ../machine/callback.h \
../threads/main.h ../lib/debug.h ../lib/sysdep.h \
/usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \
/usr/include/g++-3/libio.h /usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../threads/kernel.h ../threads/thread.h \
../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \
../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \
../lib/list.h ../lib/list.cc ../machine/interrupt.h \
../machine/stats.h ../threads/alarm.h ../machine/timer.h
machine.o: ../machine/machine.cc ../lib/copyright.h \
../machine/machine.h ../lib/utility.h ../machine/translate.h \
../threads/main.h ../lib/debug.h ../lib/sysdep.h \
/usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \
/usr/include/g++-3/libio.h /usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../threads/kernel.h ../threads/thread.h \
../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \
../threads/scheduler.h ../lib/list.h ../lib/list.cc \
../machine/interrupt.h ../machine/callback.h ../machine/stats.h \
../threads/alarm.h ../machine/timer.h
mipssim.o: ../machine/mipssim.cc ../lib/copyright.h ../lib/debug.h \
../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../machine/machine.h ../machine/translate.h \
../machine/mipssim.h ../threads/main.h ../threads/kernel.h \
../threads/thread.h ../userprog/addrspace.h ../filesys/filesys.h \
../filesys/openfile.h ../threads/scheduler.h ../lib/list.h \
../lib/list.cc ../machine/interrupt.h ../machine/callback.h \
../machine/stats.h ../threads/alarm.h ../machine/timer.h
translate.o: ../machine/translate.cc ../lib/copyright.h \
../threads/main.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \
/usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \
/usr/include/g++-3/libio.h /usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../threads/kernel.h ../threads/thread.h \
../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \
../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \
../lib/list.h ../lib/list.cc ../machine/interrupt.h \
../machine/callback.h ../machine/stats.h ../threads/alarm.h \
../machine/timer.h
network.o: ../machine/network.cc ../lib/copyright.h \
../machine/network.h ../lib/utility.h ../machine/callback.h \
../threads/main.h ../lib/debug.h ../lib/sysdep.h \
/usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \
/usr/include/g++-3/libio.h /usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../threads/kernel.h ../threads/thread.h \
../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \
../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \
../lib/list.h ../lib/list.cc ../machine/interrupt.h \
../machine/stats.h ../threads/alarm.h ../machine/timer.h
disk.o: ../machine/disk.cc ../lib/copyright.h ../machine/disk.h \
../lib/utility.h ../machine/callback.h ../lib/debug.h ../lib/sysdep.h \
/usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \
/usr/include/g++-3/libio.h /usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../threads/main.h ../threads/kernel.h \
../threads/thread.h ../machine/machine.h ../machine/translate.h \
../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \
../threads/scheduler.h ../lib/list.h ../lib/list.cc \
../machine/interrupt.h ../machine/stats.h ../threads/alarm.h \
../machine/timer.h
alarm.o: ../threads/alarm.cc ../lib/copyright.h ../threads/alarm.h \
../lib/utility.h ../machine/callback.h ../machine/timer.h \
../threads/main.h ../lib/debug.h ../lib/sysdep.h \
/usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \
/usr/include/g++-3/libio.h /usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../threads/kernel.h ../threads/thread.h \
../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \
../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \
../lib/list.h ../lib/list.cc ../machine/interrupt.h \
../machine/stats.h
kernel.o: ../threads/kernel.cc ../lib/copyright.h ../lib/debug.h \
../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../threads/main.h ../threads/kernel.h \
../threads/thread.h ../machine/machine.h ../machine/translate.h \
../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \
../threads/scheduler.h ../lib/list.h ../lib/list.cc \
../machine/interrupt.h ../machine/callback.h ../machine/stats.h \
../threads/alarm.h ../machine/timer.h ../threads/synch.h \
../threads/synchlist.h ../threads/synchlist.cc ../lib/libtest.h \
../userprog/synchconsole.h ../machine/console.h \
../filesys/synchdisk.h ../machine/disk.h ../network/post.h \
../machine/network.h
main.o: ../threads/main.cc ../lib/copyright.h ../threads/main.h \
../lib/debug.h ../lib/utility.h ../lib/sysdep.h \
/usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \
/usr/include/g++-3/libio.h /usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../threads/kernel.h ../threads/thread.h \
../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \
../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \
../lib/list.h ../lib/list.cc ../machine/interrupt.h \
../machine/callback.h ../machine/stats.h ../threads/alarm.h \
../machine/timer.h
scheduler.o: ../threads/scheduler.cc ../lib/copyright.h ../lib/debug.h \
../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../threads/scheduler.h ../lib/list.h \
../lib/list.cc ../threads/thread.h ../machine/machine.h \
../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \
../filesys/openfile.h ../threads/main.h ../threads/kernel.h \
../machine/interrupt.h ../machine/callback.h ../machine/stats.h \
../threads/alarm.h ../machine/timer.h
synch.o: ../threads/synch.cc ../lib/copyright.h ../threads/synch.h \
../threads/thread.h ../lib/utility.h ../lib/sysdep.h \
/usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \
/usr/include/g++-3/libio.h /usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../machine/machine.h ../machine/translate.h \
../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \
../lib/list.h ../lib/debug.h ../lib/list.cc ../threads/main.h \
../threads/kernel.h ../threads/scheduler.h ../machine/interrupt.h \
../machine/callback.h ../machine/stats.h ../threads/alarm.h \
../machine/timer.h
synchlist.o: ../threads/synchlist.cc ../lib/copyright.h \
../threads/synchlist.h ../lib/list.h ../lib/debug.h ../lib/utility.h \
../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../lib/list.cc ../threads/synch.h \
../threads/thread.h ../machine/machine.h ../machine/translate.h \
../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \
../threads/main.h ../threads/kernel.h ../threads/scheduler.h \
../machine/interrupt.h ../machine/callback.h ../machine/stats.h \
../threads/alarm.h ../machine/timer.h ../threads/synchlist.cc
thread.o: ../threads/thread.cc ../lib/copyright.h ../threads/thread.h \
../lib/utility.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../machine/machine.h ../machine/translate.h \
../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \
../threads/switch.h ../threads/synch.h ../lib/list.h ../lib/debug.h \
../lib/list.cc ../threads/main.h ../threads/kernel.h \
../threads/scheduler.h ../machine/interrupt.h ../machine/callback.h \
../machine/stats.h ../threads/alarm.h ../machine/timer.h
addrspace.o: ../userprog/addrspace.cc ../lib/copyright.h \
../threads/main.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \
/usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \
/usr/include/g++-3/libio.h /usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../threads/kernel.h ../threads/thread.h \
../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \
../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \
../lib/list.h ../lib/list.cc ../machine/interrupt.h \
../machine/callback.h ../machine/stats.h ../threads/alarm.h \
../machine/timer.h ../userprog/noff.h
exception.o: ../userprog/exception.cc ../lib/copyright.h \
../threads/main.h ../lib/debug.h ../lib/utility.h ../lib/sysdep.h \
/usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \
/usr/include/g++-3/libio.h /usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../threads/kernel.h ../threads/thread.h \
../machine/machine.h ../machine/translate.h ../userprog/addrspace.h \
../filesys/filesys.h ../filesys/openfile.h ../threads/scheduler.h \
../lib/list.h ../lib/list.cc ../machine/interrupt.h \
../machine/callback.h ../machine/stats.h ../threads/alarm.h \
../machine/timer.h ../userprog/syscall.h ../userprog/errno.h \
../userprog/ksyscall.h
synchconsole.o: ../userprog/synchconsole.cc ../lib/copyright.h \
../userprog/synchconsole.h ../lib/utility.h ../machine/callback.h \
../machine/console.h ../threads/synch.h ../threads/thread.h \
../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../machine/machine.h ../machine/translate.h \
../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \
../lib/list.h ../lib/debug.h ../lib/list.cc ../threads/main.h \
../threads/kernel.h ../threads/scheduler.h ../machine/interrupt.h \
../machine/stats.h ../threads/alarm.h ../machine/timer.h
directory.o: ../filesys/directory.cc ../lib/copyright.h \
../lib/utility.h ../filesys/filehdr.h ../machine/disk.h \
../machine/callback.h ../filesys/pbitmap.h ../lib/bitmap.h \
../filesys/openfile.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../filesys/directory.h
filehdr.o: ../filesys/filehdr.cc ../lib/copyright.h \
../filesys/filehdr.h ../machine/disk.h ../lib/utility.h \
../machine/callback.h ../filesys/pbitmap.h ../lib/bitmap.h \
../filesys/openfile.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../lib/debug.h ../filesys/synchdisk.h \
../threads/synch.h ../threads/thread.h ../machine/machine.h \
../machine/translate.h ../userprog/addrspace.h ../filesys/filesys.h \
../lib/list.h ../lib/list.cc ../threads/main.h ../threads/kernel.h \
../threads/scheduler.h ../machine/interrupt.h ../machine/stats.h \
../threads/alarm.h ../machine/timer.h
filesys.o: ../filesys/filesys.cc
pbitmap.o: ../filesys/pbitmap.cc ../lib/copyright.h \
../filesys/pbitmap.h ../lib/bitmap.h ../lib/utility.h \
../filesys/openfile.h ../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h
openfile.o: ../filesys/openfile.cc
synchdisk.o: ../filesys/synchdisk.cc ../lib/copyright.h \
../filesys/synchdisk.h ../machine/disk.h ../lib/utility.h \
../machine/callback.h ../threads/synch.h ../threads/thread.h \
../lib/sysdep.h /usr/include/g++-3/iostream.h \
/usr/include/g++-3/streambuf.h /usr/include/g++-3/libio.h \
/usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../machine/machine.h ../machine/translate.h \
../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \
../lib/list.h ../lib/debug.h ../lib/list.cc ../threads/main.h \
../threads/kernel.h ../threads/scheduler.h ../machine/interrupt.h \
../machine/stats.h ../threads/alarm.h ../machine/timer.h
post.o: ../network/post.cc ../lib/copyright.h ../network/post.h \
../lib/utility.h ../machine/callback.h ../machine/network.h \
../threads/synchlist.h ../lib/list.h ../lib/debug.h ../lib/sysdep.h \
/usr/include/g++-3/iostream.h /usr/include/g++-3/streambuf.h \
/usr/include/g++-3/libio.h /usr/include/_G_config.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stddef.h \
/usr/include/sys/cdefs.h /usr/include/stdlib.h /usr/include/_ansi.h \
/usr/include/sys/config.h /usr/include/sys/reent.h \
/usr/include/sys/_types.h /usr/include/machine/stdlib.h \
/usr/include/alloca.h /usr/include/stdio.h \
/usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/include/stdarg.h \
/usr/include/sys/types.h /usr/include/machine/types.h \
/usr/include/sys/features.h /usr/include/cygwin/types.h \
/usr/include/sys/sysmacros.h /usr/include/sys/stdio.h \
/usr/include/string.h ../lib/list.cc ../threads/synch.h \
../threads/thread.h ../machine/machine.h ../machine/translate.h \
../userprog/addrspace.h ../filesys/filesys.h ../filesys/openfile.h \
../threads/main.h ../threads/kernel.h ../threads/scheduler.h \
../machine/interrupt.h ../machine/stats.h ../threads/alarm.h \
../machine/timer.h ../threads/synchlist.cc
# DEPENDENCIES MUST END AT END OF FILE
# IF YOU PUT STUFF HERE IT WILL GO AWAY
# see make depend above

BIN
code/build.linux/DISK_0 Normal file

Binary file not shown.

372
code/build.linux/Makefile Normal file
View File

@@ -0,0 +1,372 @@
# Copyright (c) 1992-1996 The Regents of the University of California.
# All rights reserved. See copyright.h for copyright notice and limitation
# of liability and disclaimer of warranty provisions.
#
# This is a GNU Makefile. It must be used with the GNU make program.
# At UW, the GNU make program is /software/gnu/bin/make.
# In many other places it is known as "gmake".
# You may wish to include /software/gnu/bin/ early in your command
# search path, so that you will be using GNU make when you type "make".
#
# About this Makefile:
# --------------------
#
# This Makefile is used to build the Nachos system, which includes
# the MIPS machine simulation and a simple operating system.
#
# There is a separate Makefile, in the "test" directory, that is
# used to build the Nachos test programs (which run on the
# simulated machine).
#
# There are several "build" directories, one for each type
# of machine in the MFCF computing environment
# (build.solaris, build.sunos, and build.ultrix), as well
# as a build directory for Linux (build.linux) and a generic
# build directory (build.other) for those who wish to try
# building Nachos on other platforms.
#
# This Makefile appears to be located in all of the build directories.
# If you edit it in one directory, the copies in all of the other
# directories appear to change as well. This is the desired behaviour,
# since this file is machine independent. (The file actually lives
# in build.solaris, with symbolic links from the other build directories.)
#
# The platform-dependent parts of make's instructions are located
# in the file Makefile.dep.
# There is a different Makefile.dep in each build directory.
#
# If you are in the MFCF environment, you should not have to edit
# the Makefile.dep files by hand. Any changes to the make instructions
# can be made in this file (see the instructions below) - they will
# apply no matter where you build Nachos.
# If you are not in the MFCF environment, e.g., if you are trying
# to build Nachos on Linux at home, you will probably need
# to edit Makefile.dep (in the appropriate build directory) to
# customize the make procedure to your environment.
#
# How to build Nachos for the first time:
# ---------------------------------------
#
# (1) Make sure than you are in the build directory for the
# type of machine you are logged in to (the "host" machine):
#
# host type examples build directory
# ----------- ----------- ----------------
#
# sparc/SunOS cayley,napier, build.sunos
# (SunOS 4.1.3) descartes
#
# sparc/Solaris picard.math, build.solaris
# (SunOS 5.x) hermite.math,
# markov.math,
# hypatia.math,
# hume.math
#
# mips/ULTRIX cantor.math build.ultrix
# (ULTRIX 4.2) noether.math
#
# If you are not sure what type of machine you are on,
# try the command "uname -a".
#
# (2) Type "make depend"
# - this computes file dependencies and records them
# at the end of the file Makefile.dep in
# your build directory. Have a look...
#
# (3) Type "make nachos" (or just "make").
# - make echos the commands it is executing, so that
# you can observe its progress. When the
# build is finished, you should have an
# executable "nachos" in the build directory.
#
# (4) There is no 4th step. You are done. Try running "./nachos -u".
#
#
# How to Re-build Nachos after you have changed the code:
#--------------------------------------------------------
#
# - The Nachos source code is located in the code subdirectories:
# threads, userprog, filesys, network, and lib. You may
# change the files in any of these directories, and you can
# add new files and/or remove files. The "machine" subdirectory
# contains the hardware simulation (which is also part of
# Nachos. You may look at it, but
# you may not change it, except as noted in machine/machine.h
# - When you want to re-make Nachos, always do it in the
# "build" directory that is appropriate for the machine
# type that you are running on.
# DO NOT TRY TO MAKE NACHOS IN THE SOURCE CODE DIRECTORIES.
#
# - IF all you have done is changed C++ code in existing files
# (since the last time you made Nachos in this build directory),
# THEN all you need to do to re-make Nachos is to type
#
# "make nachos"
#
# in the build directory.
#
# - IF you have done any of the following since the last build in
# this directory:
# added new .cc files or new .h files
# added or deleted #include's from existing files
# THEN
# you must do
# "make depend"
# followed by
# "make nachos"
#
# in the build directory.
#
# Note that is is always safe to do "make depend" followed by
# "make nachos", so if you are not sure what changes you have
# made, do "make depend".
#
# - IF you have added new files (.cc or .h) since the last build,
# you should edit this Makefile before running "make depend"
# and "make nachos".
# For new .h files, simply update the appropriate "_H" list below.
# For example, if you create a file called
# "bigfile.h" in the filesys subdirectory, you should add
# "../filesys/bigfile.h" to FILESYS_H, which is defined below
# For new .cc files, update the appropriate "_C" and "_O" lists.
# For example, if you create a file called "filetable.cc" in
# the directory "userprog", you should add
# "../userprog/filetable.cc" to USERPROG_C,
# and you should add "filetable.o" to USERPROG_O.
# Note that the entry in the "_C" list includes the subdirectory
# name, while the entry on the "_O" list does not.
#
# Some Important Notes:
# ---------------------
#
# * You can clean up all of the .o and other files left behind
# by make by typeing "make clean" in the build directory.
# * You can clean up .o and other files, as well as the nachos
# executable, DISK, core, SOCKET, and other files by typing
# make "distclean"
#
# These are good ways to save space, but the next build that
# you do after cleaning will take longer than usual, since
# much of the stuff you cleaned will need to be rebuilt.
#
# * When you build Nachos on an ULTRIX machine (in build.ultrix),
# you will get lots of warning messages like this:
#
# openfile.o: does not have gp tables for all it's sectons
#
# from the loader. Ignore them. Or better yet, figure out
# how to make them go away.
#
# The Most Important Note:
# -----------------------
#
# * If "make" is behaving strangely and you cannot figure out
# why, you should REBUILD the program FROM SCRATCH.
# Yes, it is slow.
# But, there are lots of little things that can go wrong, especially
# with all of these different types of machines available.
# Rebuilding from scratch at least gives you a known starting
# place. To rebuild from scratch, go to the appropriate
# build directory and do:
#
# make distclean
# make depend
# make nachos
#
################################################################
# READ THIS: CONFIGURING NACHOS
#
# Change DEFINES (below) to
# DEFINES = -DUSE_TLB -DFILESYS_STUB
# if you want the simulated machine to use its TLB
#
# If you want to use the real Nachos file system (based on
# the simulated disk), rather than the stub, remove
# the -DFILESYS_STUB from DEFINES.
#
# There is a a fix to the MIPS simulator to enable it to properly
# handle unaligned data access. This fix is enabled by the addition
# of "-DSIM_FIX" to the DEFINES. This should be enabled by default
# and eventually will not require the symbol definition
################################################################
DEFINES = -DFILESYS_STUB -DRDATA -DSIM_FIX
#####################################################################
#
# You might want to play with the CFLAGS, but if you use -O it may
# break the thread system. You might want to use -fno-inline if
# you need to call some inline functions from the debugger.
CFLAGS = -g -Wall $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32
LDFLAGS = -m32
CPP_AS_FLAGS= -m32
#####################################################################
CPP=/lib/cpp
CC = g++ -m32 -Wno-deprecated
LD = g++ -m32 -Wno-deprecated
AS = as --32
RM = /bin/rm
INCPATH = -I../network -I../filesys -I../userprog -I../threads -I../machine -I../lib -I-
PROGRAM = nachos
#
# Edit these lists as if you add files to the source directories.
# See the instructions at the top of the file for more information.
#
LIB_H = ../lib/bitmap.h\
../lib/copyright.h\
../lib/debug.h\
../lib/hash.h\
../lib/libtest.h\
../lib/list.h\
../lib/sysdep.h\
../lib/utility.h
LIB_C = ../lib/bitmap.cc\
../lib/debug.cc\
../lib/hash.cc\
../lib/libtest.cc\
../lib/list.cc\
../lib/sysdep.cc
LIB_O = bitmap.o debug.o libtest.o sysdep.o
MACHINE_H = ../machine/callback.h\
../machine/interrupt.h\
../machine/stats.h\
../machine/timer.h\
../machine/console.h\
../machine/machine.h\
../machine/mipssim.h\
../machine/translate.h\
../machine/network.h\
../machine/disk.h
MACHINE_C = ../machine/interrupt.cc\
../machine/stats.cc\
../machine/timer.cc\
../machine/console.cc\
../machine/machine.cc\
../machine/mipssim.cc\
../machine/translate.cc\
../machine/network.cc\
../machine/disk.cc
MACHINE_O = interrupt.o stats.o timer.o console.o machine.o mipssim.o\
translate.o network.o disk.o
THREAD_H = ../threads/alarm.h\
../threads/kernel.h\
../threads/main.h\
../threads/scheduler.h\
../threads/switch.h\
../threads/synch.h\
../threads/synchlist.h\
../threads/thread.h
THREAD_C = ../threads/alarm.cc\
../threads/kernel.cc\
../threads/main.cc\
../threads/scheduler.cc\
../threads/synch.cc\
../threads/synchlist.cc\
../threads/thread.cc
THREAD_O = alarm.o kernel.o main.o scheduler.o synch.o thread.o
USERPROG_H = ../userprog/addrspace.h\
../userprog/syscall.h\
../userprog/synchconsole.h\
../userprog/noff.h
USERPROG_C = ../userprog/addrspace.cc\
../userprog/exception.cc\
../userprog/synchconsole.cc
USERPROG_O = addrspace.o exception.o synchconsole.o
FILESYS_H =../filesys/directory.h \
../filesys/filehdr.h\
../filesys/filesys.h \
../filesys/openfile.h\
../filesys/pbitmap.h\
../filesys/synchdisk.h
FILESYS_C =../filesys/directory.cc\
../filesys/filehdr.cc\
../filesys/filesys.cc\
../filesys/pbitmap.cc\
../filesys/openfile.cc\
../filesys/synchdisk.cc\
FILESYS_O =directory.o filehdr.o filesys.o pbitmap.o openfile.o synchdisk.o
NETWORK_H = ../network/post.h
NETWORK_C = ../network/post.cc
NETWORK_O = post.o
##################################################################
# You probably don't want to change anything below this point in
# the file unless you are comfortable with GNU make and know what
# you are doing...
##################################################################
THREAD_S = ../threads/switch.s
HFILES = $(LIB_H) $(MACHINE_H) $(THREAD_H) $(USERPROG_H) $(FILESYS_H) $(NETWORK_H)
CFILES = $(LIB_C) $(MACHINE_C) $(THREAD_C) $(USERPROG_C) $(FILESYS_C) $(NETWORK_C)
C_OFILES = $(LIB_O) $(MACHINE_O) $(THREAD_O) $(USERPROG_O) $(FILESYS_O) $(NETWORK_O)
S_OFILES = switch.o
OFILES = $(C_OFILES) $(S_OFILES)
$(PROGRAM): $(OFILES)
$(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM)
$(C_OFILES): %.o:
$(CC) $(CFLAGS) -c $<
switch.o: ../threads/switch.S
$(CC) $(CPP_AS_FLAGS) -P $(INCPATH) $(HOSTCFLAGS) -c ../threads/switch.S
depend: $(CFILES) $(HFILES)
$(CC) $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -M $(CFILES) > makedep
@echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
@echo '$$r makedep' >>eddep
@echo 'w' >>eddep
@echo 'q' >>eddep
ed - Makefile.dep < eddep
rm eddep makedep
@echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile.dep
@echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile.dep
@echo '# see make depend above' >> Makefile.dep
clean:
$(RM) -f $(OFILES)
distclean: clean
$(RM) -f $(PROGRAM)
$(RM) -f DISK_?
$(RM) -f core
$(RM) -f SOCKET_?
@echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
@echo 'w' >>eddep
@echo 'q' >>eddep
ed - Makefile.dep < eddep
rm eddep
@echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile.dep
@echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile.dep
@echo '# see make depend above' >> Makefile.dep
include Makefile.dep

File diff suppressed because it is too large Load Diff

Binary file not shown.

BIN
code/build.linux/alarm.o Normal file

Binary file not shown.

BIN
code/build.linux/bitmap.o Normal file

Binary file not shown.

BIN
code/build.linux/console.o Normal file

Binary file not shown.

BIN
code/build.linux/debug.o Normal file

Binary file not shown.

Binary file not shown.

BIN
code/build.linux/disk.o Normal file

Binary file not shown.

Binary file not shown.

BIN
code/build.linux/filehdr.o Normal file

Binary file not shown.

BIN
code/build.linux/filesys.o Normal file

Binary file not shown.

Binary file not shown.

BIN
code/build.linux/kernel.o Normal file

Binary file not shown.

BIN
code/build.linux/libtest.o Normal file

Binary file not shown.

BIN
code/build.linux/machine.o Normal file

Binary file not shown.

BIN
code/build.linux/main.o Normal file

Binary file not shown.

BIN
code/build.linux/mipssim.o Normal file

Binary file not shown.

BIN
code/build.linux/nachos Executable file

Binary file not shown.

BIN
code/build.linux/network.o Normal file

Binary file not shown.

BIN
code/build.linux/openfile.o Normal file

Binary file not shown.

BIN
code/build.linux/pbitmap.o Normal file

Binary file not shown.

BIN
code/build.linux/post.o Normal file

Binary file not shown.

Binary file not shown.

BIN
code/build.linux/stats.o Normal file

Binary file not shown.

BIN
code/build.linux/switch.o Normal file

Binary file not shown.

BIN
code/build.linux/synch.o Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
code/build.linux/sysdep.o Normal file

Binary file not shown.

BIN
code/build.linux/thread.o Normal file

Binary file not shown.

BIN
code/build.linux/timer.o Normal file

Binary file not shown.

Binary file not shown.

365
code/build.macosx/Makefile Normal file
View File

@@ -0,0 +1,365 @@
# Copyright (c) 1992-1996 The Regents of the University of California.
# All rights reserved. See copyright.h for copyright notice and limitation
# of liability and disclaimer of warranty provisions.
#
# This is a GNU Makefile. It must be used with the GNU make program.
# At UW, the GNU make program is /software/gnu/bin/make.
# In many other places it is known as "gmake".
# You may wish to include /software/gnu/bin/ early in your command
# search path, so that you will be using GNU make when you type "make".
#
# About this Makefile:
# --------------------
#
# This Makefile is used to build the Nachos system, which includes
# the MIPS machine simulation and a simple operating system.
#
# There is a separate Makefile, in the "test" directory, that is
# used to build the Nachos test programs (which run on the
# simulated machine).
#
# There are several "build" directories, one for each type
# of machine in the MFCF computing environment
# (build.solaris, build.sunos, and build.ultrix), as well
# as a build directory for Linux (build.linux) and a generic
# build directory (build.other) for those who wish to try
# building Nachos on other platforms.
#
# This Makefile appears to be located in all of the build directories.
# If you edit it in one directory, the copies in all of the other
# directories appear to change as well. This is the desired behaviour,
# since this file is machine independent. (The file actually lives
# in build.solaris, with symbolic links from the other build directories.)
#
# The platform-dependent parts of make's instructions are located
# in the file Makefile.dep.
# There is a different Makefile.dep in each build directory.
#
# If you are in the MFCF environment, you should not have to edit
# the Makefile.dep files by hand. Any changes to the make instructions
# can be made in this file (see the instructions below) - they will
# apply no matter where you build Nachos.
# If you are not in the MFCF environment, e.g., if you are trying
# to build Nachos on Linux at home, you will probably need
# to edit Makefile.dep (in the appropriate build directory) to
# customize the make procedure to your environment.
#
# How to build Nachos for the first time:
# ---------------------------------------
#
# (1) Make sure than you are in the build directory for the
# type of machine you are logged in to (the "host" machine):
#
# host type examples build directory
# ----------- ----------- ----------------
#
# sparc/SunOS cayley,napier, build.sunos
# (SunOS 4.1.3) descartes
#
# sparc/Solaris picard.math, build.solaris
# (SunOS 5.x) hermite.math,
# markov.math,
# hypatia.math,
# hume.math
#
# mips/ULTRIX cantor.math build.ultrix
# (ULTRIX 4.2) noether.math
#
# If you are not sure what type of machine you are on,
# try the command "uname -a".
#
# (2) Type "make depend"
# - this computes file dependencies and records them
# at the end of the file Makefile.dep in
# your build directory. Have a look...
#
# (3) Type "make nachos" (or just "make").
# - make echos the commands it is executing, so that
# you can observe its progress. When the
# build is finished, you should have an
# executable "nachos" in the build directory.
#
# (4) There is no 4th step. You are done. Try running "./nachos -u".
#
#
# How to Re-build Nachos after you have changed the code:
#--------------------------------------------------------
#
# - The Nachos source code is located in the code subdirectories:
# threads, userprog, filesys, network, and lib. You may
# change the files in any of these directories, and you can
# add new files and/or remove files. The "machine" subdirectory
# contains the hardware simulation (which is also part of
# Nachos. You may look at it, but
# you may not change it, except as noted in machine/machine.h
# - When you want to re-make Nachos, always do it in the
# "build" directory that is appropriate for the machine
# type that you are running on.
# DO NOT TRY TO MAKE NACHOS IN THE SOURCE CODE DIRECTORIES.
#
# - IF all you have done is changed C++ code in existing files
# (since the last time you made Nachos in this build directory),
# THEN all you need to do to re-make Nachos is to type
#
# "make nachos"
#
# in the build directory.
#
# - IF you have done any of the following since the last build in
# this directory:
# added new .cc files or new .h files
# added or deleted #include's from existing files
# THEN
# you must do
# "make depend"
# followed by
# "make nachos"
#
# in the build directory.
#
# Note that is is always safe to do "make depend" followed by
# "make nachos", so if you are not sure what changes you have
# made, do "make depend".
#
# - IF you have added new files (.cc or .h) since the last build,
# you should edit this Makefile before running "make depend"
# and "make nachos".
# For new .h files, simply update the appropriate "_H" list below.
# For example, if you create a file called
# "bigfile.h" in the filesys subdirectory, you should add
# "../filesys/bigfile.h" to FILESYS_H, which is defined below
# For new .cc files, update the appropriate "_C" and "_O" lists.
# For example, if you create a file called "filetable.cc" in
# the directory "userprog", you should add
# "../userprog/filetable.cc" to USERPROG_C,
# and you should add "filetable.o" to USERPROG_O.
# Note that the entry in the "_C" list includes the subdirectory
# name, while the entry on the "_O" list does not.
#
# Some Important Notes:
# ---------------------
#
# * You can clean up all of the .o and other files left behind
# by make by typeing "make clean" in the build directory.
# * You can clean up .o and other files, as well as the nachos
# executable, DISK, core, SOCKET, and other files by typing
# make "distclean"
#
# These are good ways to save space, but the next build that
# you do after cleaning will take longer than usual, since
# much of the stuff you cleaned will need to be rebuilt.
#
# * When you build Nachos on an ULTRIX machine (in build.ultrix),
# you will get lots of warning messages like this:
#
# openfile.o: does not have gp tables for all it's sectons
#
# from the loader. Ignore them. Or better yet, figure out
# how to make them go away.
#
# The Most Important Note:
# -----------------------
#
# * If "make" is behaving strangely and you cannot figure out
# why, you should REBUILD the program FROM SCRATCH.
# Yes, it is slow.
# But, there are lots of little things that can go wrong, especially
# with all of these different types of machines available.
# Rebuilding from scratch at least gives you a known starting
# place. To rebuild from scratch, go to the appropriate
# build directory and do:
#
# make distclean
# make depend
# make nachos
#
################################################################
# READ THIS: CONFIGURING NACHOS
#
# Change DEFINES (below) to
# DEFINES = -DUSE_TLB -DFILESYS_STUB
# if you want the simulated machine to use its TLB
#
# If you want to use the real Nachos file system (based on
# the simulated disk), rather than the stub, remove
# the -DFILESYS_STUB from DEFINES.
#
# There is a a fix to the MIPS simulator to enable it to properly
# handle unaligned data access. This fix is enabled by the addition
# of "-DSIM_FIX" to the DEFINES. This should be enabled by default
# and eventually will not require the symbol definition
################################################################
DEFINES = -DFILESYS_STUB -DRDATA -DSIM_FIX
#####################################################################
#
# You might want to play with the CFLAGS, but if you use -O it may
# break the thread system. You might want to use -fno-inline if
# you need to call some inline functions from the debugger.
CFLAGS = -g -Wall -fwritable-strings $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED
LDFLAGS =
#####################################################################
CPP=/lib/cpp
CC = g++
LD = g++
AS = as
RM = /bin/rm
INCPATH = -I../network -I../filesys -I../userprog -I../threads -I../machine -I../lib
PROGRAM = nachos
#
# Edit these lists as if you add files to the source directories.
# See the instructions at the top of the file for more information.
#
LIB_H = ../lib/bitmap.h\
../lib/copyright.h\
../lib/debug.h\
../lib/hash.h\
../lib/libtest.h\
../lib/list.h\
../lib/sysdep.h\
../lib/utility.h
LIB_C = ../lib/bitmap.cc\
../lib/debug.cc\
../lib/hash.cc\
../lib/libtest.cc\
../lib/list.cc\
../lib/sysdep.cc
LIB_O = bitmap.o debug.o libtest.o sysdep.o
MACHINE_H = ../machine/callback.h\
../machine/interrupt.h\
../machine/stats.h\
../machine/timer.h\
../machine/console.h\
../machine/machine.h\
../machine/mipssim.h\
../machine/translate.h\
../machine/network.h\
../machine/disk.h
MACHINE_C = ../machine/interrupt.cc\
../machine/stats.cc\
../machine/timer.cc\
../machine/console.cc\
../machine/machine.cc\
../machine/mipssim.cc\
../machine/translate.cc\
../machine/network.cc\
../machine/disk.cc
MACHINE_O = interrupt.o stats.o timer.o console.o machine.o mipssim.o\
translate.o network.o disk.o
THREAD_H = ../threads/alarm.h\
../threads/kernel.h\
../threads/main.h\
../threads/scheduler.h\
../threads/switch.h\
../threads/synch.h\
../threads/synchlist.h\
../threads/thread.h
THREAD_C = ../threads/alarm.cc\
../threads/kernel.cc\
../threads/main.cc\
../threads/scheduler.cc\
../threads/synch.cc\
../threads/synchlist.cc\
../threads/thread.cc
THREAD_O = alarm.o kernel.o main.o scheduler.o synch.o thread.o
USERPROG_H = ../userprog/addrspace.h\
../userprog/syscall.h\
../userprog/synchconsole.h\
../userprog/noff.h
USERPROG_C = ../userprog/addrspace.cc\
../userprog/exception.cc\
../userprog/synchconsole.cc
USERPROG_O = addrspace.o exception.o synchconsole.o
FILESYS_H =../filesys/directory.h \
../filesys/filehdr.h\
../filesys/filesys.h \
../filesys/openfile.h\
../filesys/pbitmap.h\
../filesys/synchdisk.h
FILESYS_C =../filesys/directory.cc\
../filesys/filehdr.cc\
../filesys/filesys.cc\
../filesys/pbitmap.cc\
../filesys/openfile.cc\
../filesys/synchdisk.cc\
FILESYS_O =directory.o filehdr.o filesys.o pbitmap.o openfile.o synchdisk.o
NETWORK_H = ../network/post.h
NETWORK_C = ../network/post.cc
NETWORK_O = post.o
##################################################################
# You probably don't want to change anything below this point in
# the file unless you are comfortable with GNU make and know what
# you are doing...
##################################################################
THREAD_S = ../threads/switch.s
HFILES = $(LIB_H) $(MACHINE_H) $(THREAD_H) $(USERPROG_H) $(FILESYS_H) $(NETWORK_H)
CFILES = $(LIB_C) $(MACHINE_C) $(THREAD_C) $(USERPROG_C) $(FILESYS_C) $(NETWORK_C)
C_OFILES = $(LIB_O) $(MACHINE_O) $(THREAD_O) $(USERPROG_O) $(FILESYS_O) $(NETWORK_O)
S_OFILES = switch.o
OFILES = $(C_OFILES) $(S_OFILES)
$(PROGRAM): $(OFILES)
$(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM)
$(C_OFILES): %.o:
$(CC) $(CFLAGS) -c $<
switch.o: ../threads/switch.s
$(CPP) $(CPP_AS_FLAGS) -P $(INCPATH) $(HOSTCFLAGS) ../threads/switch.s > swtch.s
$(AS) -o switch.o swtch.s
depend: $(CFILES) $(HFILES)
$(CC) $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -M $(CFILES) > makedep
@echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
@echo '$$r makedep' >>eddep
@echo 'w' >>eddep
@echo 'q' >>eddep
ed - Makefile.dep < eddep
rm eddep makedep
@echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile.dep
@echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile.dep
@echo '# see make depend above' >> Makefile.dep
clean:
$(RM) -f $(OFILES)
$(RM) -f swtch.s
distclean: clean
$(RM) -f $(PROGRAM)
$(RM) -f DISK_?
$(RM) -f core
$(RM) -f SOCKET_?
include Makefile.dep

View File

@@ -0,0 +1,18 @@
##################################################################
# Machine Dependencies - this file is included automatically
# into the main Makefile
#
##################################################################
HOSTCFLAGS = -DHOST_IS_BIG_ENDIAN -DPowerPC -DBSD -DAIX -DApplePowerPC
CPP_AS_FLAGS = -D_ASM
CPP = cpp
#-----------------------------------------------------------------
# Do not put anything below this point - it will be destroyed by
# "make depend"
#
# DO NOT DELETE THIS LINE -- make depend uses it
# DEPENDENCIES MUST END AT END OF FILE
# IF YOU PUT STUFF HERE IT WILL GO AWAY
# see make depend above

196
code/filesys/directory.cc Normal file
View File

@@ -0,0 +1,196 @@
// directory.cc
// Routines to manage a directory of file names.
//
// The directory is a table of fixed length entries; each
// entry represents a single file, and contains the file name,
// and the location of the file header on disk. The fixed size
// of each directory entry means that we have the restriction
// of a fixed maximum size for file names.
//
// The constructor initializes an empty directory of a certain size;
// we use ReadFrom/WriteBack to fetch the contents of the directory
// from disk, and to write back any modifications back to disk.
//
// Also, this implementation has the restriction that the size
// of the directory cannot expand. In other words, once all the
// entries in the directory are used, no more files can be created.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "utility.h"
#include "filehdr.h"
#include "directory.h"
//----------------------------------------------------------------------
// Directory::Directory
// Initialize a directory; initially, the directory is completely
// empty. If the disk is being formatted, an empty directory
// is all we need, but otherwise, we need to call FetchFrom in order
// to initialize it from disk.
//
// "size" is the number of entries in the directory
//----------------------------------------------------------------------
Directory::Directory(int size)
{
table = new DirectoryEntry[size];
tableSize = size;
for (int i = 0; i < tableSize; i++)
table[i].inUse = FALSE;
}
//----------------------------------------------------------------------
// Directory::~Directory
// De-allocate directory data structure.
//----------------------------------------------------------------------
Directory::~Directory()
{
delete [] table;
}
//----------------------------------------------------------------------
// Directory::FetchFrom
// Read the contents of the directory from disk.
//
// "file" -- file containing the directory contents
//----------------------------------------------------------------------
void
Directory::FetchFrom(OpenFile *file)
{
(void) file->ReadAt((char *)table, tableSize * sizeof(DirectoryEntry), 0);
}
//----------------------------------------------------------------------
// Directory::WriteBack
// Write any modifications to the directory back to disk
//
// "file" -- file to contain the new directory contents
//----------------------------------------------------------------------
void
Directory::WriteBack(OpenFile *file)
{
(void) file->WriteAt((char *)table, tableSize * sizeof(DirectoryEntry), 0);
}
//----------------------------------------------------------------------
// Directory::FindIndex
// Look up file name in directory, and return its location in the table of
// directory entries. Return -1 if the name isn't in the directory.
//
// "name" -- the file name to look up
//----------------------------------------------------------------------
int
Directory::FindIndex(char *name)
{
for (int i = 0; i < tableSize; i++)
if (table[i].inUse && !strncmp(table[i].name, name, FileNameMaxLen))
return i;
return -1; // name not in directory
}
//----------------------------------------------------------------------
// Directory::Find
// Look up file name in directory, and return the disk sector number
// where the file's header is stored. Return -1 if the name isn't
// in the directory.
//
// "name" -- the file name to look up
//----------------------------------------------------------------------
int
Directory::Find(char *name)
{
int i = FindIndex(name);
if (i != -1)
return table[i].sector;
return -1;
}
//----------------------------------------------------------------------
// Directory::Add
// Add a file into the directory. Return TRUE if successful;
// return FALSE if the file name is already in the directory, or if
// the directory is completely full, and has no more space for
// additional file names.
//
// "name" -- the name of the file being added
// "newSector" -- the disk sector containing the added file's header
//----------------------------------------------------------------------
bool
Directory::Add(char *name, int newSector)
{
if (FindIndex(name) != -1)
return FALSE;
for (int i = 0; i < tableSize; i++)
if (!table[i].inUse) {
table[i].inUse = TRUE;
strncpy(table[i].name, name, FileNameMaxLen);
table[i].sector = newSector;
return TRUE;
}
return FALSE; // no space. Fix when we have extensible files.
}
//----------------------------------------------------------------------
// Directory::Remove
// Remove a file name from the directory. Return TRUE if successful;
// return FALSE if the file isn't in the directory.
//
// "name" -- the file name to be removed
//----------------------------------------------------------------------
bool
Directory::Remove(char *name)
{
int i = FindIndex(name);
if (i == -1)
return FALSE; // name not in directory
table[i].inUse = FALSE;
return TRUE;
}
//----------------------------------------------------------------------
// Directory::List
// List all the file names in the directory.
//----------------------------------------------------------------------
void
Directory::List()
{
for (int i = 0; i < tableSize; i++)
if (table[i].inUse)
printf("%s\n", table[i].name);
}
//----------------------------------------------------------------------
// Directory::Print
// List all the file names in the directory, their FileHeader locations,
// and the contents of each file. For debugging.
//----------------------------------------------------------------------
void
Directory::Print()
{
FileHeader *hdr = new FileHeader;
printf("Directory contents:\n");
for (int i = 0; i < tableSize; i++)
if (table[i].inUse) {
printf("Name: %s, Sector: %d\n", table[i].name, table[i].sector);
hdr->FetchFrom(table[i].sector);
hdr->Print();
}
printf("\n");
delete hdr;
}

83
code/filesys/directory.h Normal file
View File

@@ -0,0 +1,83 @@
// directory.h
// Data structures to manage a UNIX-like directory of file names.
//
// A directory is a table of pairs: <file name, sector #>,
// giving the name of each file in the directory, and
// where to find its file header (the data structure describing
// where to find the file's data blocks) on disk.
//
// We assume mutual exclusion is provided by the caller.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#ifndef DIRECTORY_H
#define DIRECTORY_H
#include "openfile.h"
#define FileNameMaxLen 9 // for simplicity, we assume
// file names are <= 9 characters long
// The following class defines a "directory entry", representing a file
// in the directory. Each entry gives the name of the file, and where
// the file's header is to be found on disk.
//
// Internal data structures kept public so that Directory operations can
// access them directly.
class DirectoryEntry {
public:
bool inUse; // Is this directory entry in use?
int sector; // Location on disk to find the
// FileHeader for this file
char name[FileNameMaxLen + 1]; // Text name for file, with +1 for
// the trailing '\0'
};
// The following class defines a UNIX-like "directory". Each entry in
// the directory describes a file, and where to find it on disk.
//
// The directory data structure can be stored in memory, or on disk.
// When it is on disk, it is stored as a regular Nachos file.
//
// The constructor initializes a directory structure in memory; the
// FetchFrom/WriteBack operations shuffle the directory information
// from/to disk.
class Directory {
public:
Directory(int size); // Initialize an empty directory
// with space for "size" files
~Directory(); // De-allocate the directory
void FetchFrom(OpenFile *file); // Init directory contents from disk
void WriteBack(OpenFile *file); // Write modifications to
// directory contents back to disk
int Find(char *name); // Find the sector number of the
// FileHeader for file: "name"
bool Add(char *name, int newSector); // Add a file name into the directory
bool Remove(char *name); // Remove a file from the directory
void List(); // Print the names of all the files
// in the directory
void Print(); // Verbose print of the contents
// of the directory -- all the file
// names and their contents.
private:
int tableSize; // Number of directory entries
DirectoryEntry *table; // Table of pairs:
// <file name, file header location>
int FindIndex(char *name); // Find the index into the directory
// table corresponding to "name"
};
#endif // DIRECTORY_H

156
code/filesys/filehdr.cc Normal file
View File

@@ -0,0 +1,156 @@
// filehdr.cc
// Routines for managing the disk file header (in UNIX, this
// would be called the i-node).
//
// The file header is used to locate where on disk the
// file's data is stored. We implement this as a fixed size
// table of pointers -- each entry in the table points to the
// disk sector containing that portion of the file data
// (in other words, there are no indirect or doubly indirect
// blocks). The table size is chosen so that the file header
// will be just big enough to fit in one disk sector,
//
// Unlike in a real system, we do not keep track of file permissions,
// ownership, last modification date, etc., in the file header.
//
// A file header can be initialized in two ways:
// for a new file, by modifying the in-memory data structure
// to point to the newly allocated data blocks
// for a file already on disk, by reading the file header from disk
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "filehdr.h"
#include "debug.h"
#include "synchdisk.h"
#include "main.h"
//----------------------------------------------------------------------
// FileHeader::Allocate
// Initialize a fresh file header for a newly created file.
// Allocate data blocks for the file out of the map of free disk blocks.
// Return FALSE if there are not enough free blocks to accomodate
// the new file.
//
// "freeMap" is the bit map of free disk sectors
// "fileSize" is the bit map of free disk sectors
//----------------------------------------------------------------------
bool
FileHeader::Allocate(PersistentBitmap *freeMap, int fileSize)
{
numBytes = fileSize;
numSectors = divRoundUp(fileSize, SectorSize);
if (freeMap->NumClear() < numSectors)
return FALSE; // not enough space
for (int i = 0; i < numSectors; i++) {
dataSectors[i] = freeMap->FindAndSet();
// since we checked that there was enough free space,
// we expect this to succeed
ASSERT(dataSectors[i] >= 0);
}
return TRUE;
}
//----------------------------------------------------------------------
// FileHeader::Deallocate
// De-allocate all the space allocated for data blocks for this file.
//
// "freeMap" is the bit map of free disk sectors
//----------------------------------------------------------------------
void
FileHeader::Deallocate(PersistentBitmap *freeMap)
{
for (int i = 0; i < numSectors; i++) {
ASSERT(freeMap->Test((int) dataSectors[i])); // ought to be marked!
freeMap->Clear((int) dataSectors[i]);
}
}
//----------------------------------------------------------------------
// FileHeader::FetchFrom
// Fetch contents of file header from disk.
//
// "sector" is the disk sector containing the file header
//----------------------------------------------------------------------
void
FileHeader::FetchFrom(int sector)
{
kernel->synchDisk->ReadSector(sector, (char *)this);
}
//----------------------------------------------------------------------
// FileHeader::WriteBack
// Write the modified contents of the file header back to disk.
//
// "sector" is the disk sector to contain the file header
//----------------------------------------------------------------------
void
FileHeader::WriteBack(int sector)
{
kernel->synchDisk->WriteSector(sector, (char *)this);
}
//----------------------------------------------------------------------
// FileHeader::ByteToSector
// Return which disk sector is storing a particular byte within the file.
// This is essentially a translation from a virtual address (the
// offset in the file) to a physical address (the sector where the
// data at the offset is stored).
//
// "offset" is the location within the file of the byte in question
//----------------------------------------------------------------------
int
FileHeader::ByteToSector(int offset)
{
return(dataSectors[offset / SectorSize]);
}
//----------------------------------------------------------------------
// FileHeader::FileLength
// Return the number of bytes in the file.
//----------------------------------------------------------------------
int
FileHeader::FileLength()
{
return numBytes;
}
//----------------------------------------------------------------------
// FileHeader::Print
// Print the contents of the file header, and the contents of all
// the data blocks pointed to by the file header.
//----------------------------------------------------------------------
void
FileHeader::Print()
{
int i, j, k;
char *data = new char[SectorSize];
printf("FileHeader contents. File size: %d. File blocks:\n", numBytes);
for (i = 0; i < numSectors; i++)
printf("%d ", dataSectors[i]);
printf("\nFile contents:\n");
for (i = k = 0; i < numSectors; i++) {
kernel->synchDisk->ReadSector(dataSectors[i], data);
for (j = 0; (j < SectorSize) && (k < numBytes); j++, k++) {
if ('\040' <= data[j] && data[j] <= '\176') // isprint(data[j])
printf("%c", data[j]);
else
printf("\\%x", (unsigned char)data[j]);
}
printf("\n");
}
delete [] data;
}

66
code/filesys/filehdr.h Normal file
View File

@@ -0,0 +1,66 @@
// filehdr.h
// Data structures for managing a disk file header.
//
// A file header describes where on disk to find the data in a file,
// along with other information about the file (for instance, its
// length, owner, etc.)
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#ifndef FILEHDR_H
#define FILEHDR_H
#include "disk.h"
#include "pbitmap.h"
#define NumDirect ((SectorSize - 2 * sizeof(int)) / sizeof(int))
#define MaxFileSize (NumDirect * SectorSize)
// The following class defines the Nachos "file header" (in UNIX terms,
// the "i-node"), describing where on disk to find all of the data in the file.
// The file header is organized as a simple table of pointers to
// data blocks.
//
// The file header data structure can be stored in memory or on disk.
// When it is on disk, it is stored in a single sector -- this means
// that we assume the size of this data structure to be the same
// as one disk sector. Without indirect addressing, this
// limits the maximum file length to just under 4K bytes.
//
// There is no constructor; rather the file header can be initialized
// by allocating blocks for the file (if it is a new file), or by
// reading it from disk.
class FileHeader {
public:
bool Allocate(PersistentBitmap *bitMap, int fileSize);// Initialize a file header,
// including allocating space
// on disk for the file data
void Deallocate(PersistentBitmap *bitMap); // De-allocate this file's
// data blocks
void FetchFrom(int sectorNumber); // Initialize file header from disk
void WriteBack(int sectorNumber); // Write modifications to file header
// back to disk
int ByteToSector(int offset); // Convert a byte offset into the file
// to the disk sector containing
// the byte
int FileLength(); // Return the length of the file
// in bytes
void Print(); // Print the contents of the file.
private:
int numBytes; // Number of bytes in the file
int numSectors; // Number of data sectors in the file
int dataSectors[NumDirect]; // Disk sector numbers for each data
// block in the file
};
#endif // FILEHDR_H

340
code/filesys/filesys.cc Normal file
View File

@@ -0,0 +1,340 @@
// filesys.cc
// Routines to manage the overall operation of the file system.
// Implements routines to map from textual file names to files.
//
// Each file in the file system has:
// A file header, stored in a sector on disk
// (the size of the file header data structure is arranged
// to be precisely the size of 1 disk sector)
// A number of data blocks
// An entry in the file system directory
//
// The file system consists of several data structures:
// A bitmap of free disk sectors (cf. bitmap.h)
// A directory of file names and file headers
//
// Both the bitmap and the directory are represented as normal
// files. Their file headers are located in specific sectors
// (sector 0 and sector 1), so that the file system can find them
// on bootup.
//
// The file system assumes that the bitmap and directory files are
// kept "open" continuously while Nachos is running.
//
// For those operations (such as Create, Remove) that modify the
// directory and/or bitmap, if the operation succeeds, the changes
// are written immediately back to disk (the two files are kept
// open during all this time). If the operation fails, and we have
// modified part of the directory and/or bitmap, we simply discard
// the changed version, without writing it back to disk.
//
// Our implementation at this point has the following restrictions:
//
// there is no synchronization for concurrent accesses
// files have a fixed size, set when the file is created
// files cannot be bigger than about 3KB in size
// there is no hierarchical directory structure, and only a limited
// number of files can be added to the system
// there is no attempt to make the system robust to failures
// (if Nachos exits in the middle of an operation that modifies
// the file system, it may corrupt the disk)
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef FILESYS_STUB
#include "copyright.h"
#include "debug.h"
#include "disk.h"
#include "pbitmap.h"
#include "directory.h"
#include "filehdr.h"
#include "filesys.h"
// Sectors containing the file headers for the bitmap of free sectors,
// and the directory of files. These file headers are placed in well-known
// sectors, so that they can be located on boot-up.
#define FreeMapSector 0
#define DirectorySector 1
// Initial file sizes for the bitmap and directory; until the file system
// supports extensible files, the directory size sets the maximum number
// of files that can be loaded onto the disk.
#define FreeMapFileSize (NumSectors / BitsInByte)
#define NumDirEntries 10
#define DirectoryFileSize (sizeof(DirectoryEntry) * NumDirEntries)
//----------------------------------------------------------------------
// FileSystem::FileSystem
// Initialize the file system. If format = TRUE, the disk has
// nothing on it, and we need to initialize the disk to contain
// an empty directory, and a bitmap of free sectors (with almost but
// not all of the sectors marked as free).
//
// If format = FALSE, we just have to open the files
// representing the bitmap and the directory.
//
// "format" -- should we initialize the disk?
//----------------------------------------------------------------------
FileSystem::FileSystem(bool format)
{
DEBUG(dbgFile, "Initializing the file system.");
if (format) {
PersistentBitmap *freeMap = new PersistentBitmap(NumSectors);
Directory *directory = new Directory(NumDirEntries);
FileHeader *mapHdr = new FileHeader;
FileHeader *dirHdr = new FileHeader;
DEBUG(dbgFile, "Formatting the file system.");
// First, allocate space for FileHeaders for the directory and bitmap
// (make sure no one else grabs these!)
freeMap->Mark(FreeMapSector);
freeMap->Mark(DirectorySector);
// Second, allocate space for the data blocks containing the contents
// of the directory and bitmap files. There better be enough space!
ASSERT(mapHdr->Allocate(freeMap, FreeMapFileSize));
ASSERT(dirHdr->Allocate(freeMap, DirectoryFileSize));
// Flush the bitmap and directory FileHeaders back to disk
// We need to do this before we can "Open" the file, since open
// reads the file header off of disk (and currently the disk has garbage
// on it!).
DEBUG(dbgFile, "Writing headers back to disk.");
mapHdr->WriteBack(FreeMapSector);
dirHdr->WriteBack(DirectorySector);
// OK to open the bitmap and directory files now
// The file system operations assume these two files are left open
// while Nachos is running.
freeMapFile = new OpenFile(FreeMapSector);
directoryFile = new OpenFile(DirectorySector);
// Once we have the files "open", we can write the initial version
// of each file back to disk. The directory at this point is completely
// empty; but the bitmap has been changed to reflect the fact that
// sectors on the disk have been allocated for the file headers and
// to hold the file data for the directory and bitmap.
DEBUG(dbgFile, "Writing bitmap and directory back to disk.");
freeMap->WriteBack(freeMapFile); // flush changes to disk
directory->WriteBack(directoryFile);
if (debug->IsEnabled('f')) {
freeMap->Print();
directory->Print();
}
delete freeMap;
delete directory;
delete mapHdr;
delete dirHdr;
} else {
// if we are not formatting the disk, just open the files representing
// the bitmap and directory; these are left open while Nachos is running
freeMapFile = new OpenFile(FreeMapSector);
directoryFile = new OpenFile(DirectorySector);
}
}
//----------------------------------------------------------------------
// FileSystem::Create
// Create a file in the Nachos file system (similar to UNIX create).
// Since we can't increase the size of files dynamically, we have
// to give Create the initial size of the file.
//
// The steps to create a file are:
// Make sure the file doesn't already exist
// Allocate a sector for the file header
// Allocate space on disk for the data blocks for the file
// Add the name to the directory
// Store the new file header on disk
// Flush the changes to the bitmap and the directory back to disk
//
// Return TRUE if everything goes ok, otherwise, return FALSE.
//
// Create fails if:
// file is already in directory
// no free space for file header
// no free entry for file in directory
// no free space for data blocks for the file
//
// Note that this implementation assumes there is no concurrent access
// to the file system!
//
// "name" -- name of file to be created
// "initialSize" -- size of file to be created
//----------------------------------------------------------------------
bool
FileSystem::Create(char *name, int initialSize)
{
Directory *directory;
PersistentBitmap *freeMap;
FileHeader *hdr;
int sector;
bool success;
DEBUG(dbgFile, "Creating file " << name << " size " << initialSize);
directory = new Directory(NumDirEntries);
directory->FetchFrom(directoryFile);
if (directory->Find(name) != -1)
success = FALSE; // file is already in directory
else {
freeMap = new PersistentBitmap(freeMapFile,NumSectors);
sector = freeMap->FindAndSet(); // find a sector to hold the file header
if (sector == -1)
success = FALSE; // no free block for file header
else if (!directory->Add(name, sector))
success = FALSE; // no space in directory
else {
hdr = new FileHeader;
if (!hdr->Allocate(freeMap, initialSize))
success = FALSE; // no space on disk for data
else {
success = TRUE;
// everthing worked, flush all changes back to disk
hdr->WriteBack(sector);
directory->WriteBack(directoryFile);
freeMap->WriteBack(freeMapFile);
}
delete hdr;
}
delete freeMap;
}
delete directory;
return success;
}
//----------------------------------------------------------------------
// FileSystem::Open
// Open a file for reading and writing.
// To open a file:
// Find the location of the file's header, using the directory
// Bring the header into memory
//
// "name" -- the text name of the file to be opened
//----------------------------------------------------------------------
OpenFile *
FileSystem::Open(char *name)
{
Directory *directory = new Directory(NumDirEntries);
OpenFile *openFile = NULL;
int sector;
DEBUG(dbgFile, "Opening file" << name);
directory->FetchFrom(directoryFile);
sector = directory->Find(name);
if (sector >= 0)
openFile = new OpenFile(sector); // name was found in directory
delete directory;
return openFile; // return NULL if not found
}
//----------------------------------------------------------------------
// FileSystem::Remove
// Delete a file from the file system. This requires:
// Remove it from the directory
// Delete the space for its header
// Delete the space for its data blocks
// Write changes to directory, bitmap back to disk
//
// Return TRUE if the file was deleted, FALSE if the file wasn't
// in the file system.
//
// "name" -- the text name of the file to be removed
//----------------------------------------------------------------------
bool
FileSystem::Remove(char *name)
{
Directory *directory;
PersistentBitmap *freeMap;
FileHeader *fileHdr;
int sector;
directory = new Directory(NumDirEntries);
directory->FetchFrom(directoryFile);
sector = directory->Find(name);
if (sector == -1) {
delete directory;
return FALSE; // file not found
}
fileHdr = new FileHeader;
fileHdr->FetchFrom(sector);
freeMap = new PersistentBitmap(freeMapFile,NumSectors);
fileHdr->Deallocate(freeMap); // remove data blocks
freeMap->Clear(sector); // remove header block
directory->Remove(name);
freeMap->WriteBack(freeMapFile); // flush to disk
directory->WriteBack(directoryFile); // flush to disk
delete fileHdr;
delete directory;
delete freeMap;
return TRUE;
}
//----------------------------------------------------------------------
// FileSystem::List
// List all the files in the file system directory.
//----------------------------------------------------------------------
void
FileSystem::List()
{
Directory *directory = new Directory(NumDirEntries);
directory->FetchFrom(directoryFile);
directory->List();
delete directory;
}
//----------------------------------------------------------------------
// FileSystem::Print
// Print everything about the file system:
// the contents of the bitmap
// the contents of the directory
// for each file in the directory,
// the contents of the file header
// the data in the file
//----------------------------------------------------------------------
void
FileSystem::Print()
{
FileHeader *bitHdr = new FileHeader;
FileHeader *dirHdr = new FileHeader;
PersistentBitmap *freeMap = new PersistentBitmap(freeMapFile,NumSectors);
Directory *directory = new Directory(NumDirEntries);
printf("Bit map file header:\n");
bitHdr->FetchFrom(FreeMapSector);
bitHdr->Print();
printf("Directory file header:\n");
dirHdr->FetchFrom(DirectorySector);
dirHdr->Print();
freeMap->Print();
directory->FetchFrom(directoryFile);
directory->Print();
delete bitHdr;
delete dirHdr;
delete freeMap;
delete directory;
}
#endif // FILESYS_STUB

98
code/filesys/filesys.h Normal file
View File

@@ -0,0 +1,98 @@
// filesys.h
// Data structures to represent the Nachos file system.
//
// A file system is a set of files stored on disk, organized
// into directories. Operations on the file system have to
// do with "naming" -- creating, opening, and deleting files,
// given a textual file name. Operations on an individual
// "open" file (read, write, close) are to be found in the OpenFile
// class (openfile.h).
//
// We define two separate implementations of the file system.
// The "STUB" version just re-defines the Nachos file system
// operations as operations on the native UNIX file system on the machine
// running the Nachos simulation.
//
// The other version is a "real" file system, built on top of
// a disk simulator. The disk is simulated using the native UNIX
// file system (in a file named "DISK").
//
// In the "real" implementation, there are two key data structures used
// in the file system. There is a single "root" directory, listing
// all of the files in the file system; unlike UNIX, the baseline
// system does not provide a hierarchical directory structure.
// In addition, there is a bitmap for allocating
// disk sectors. Both the root directory and the bitmap are themselves
// stored as files in the Nachos file system -- this causes an interesting
// bootstrap problem when the simulated disk is initialized.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef FS_H
#define FS_H
#include "copyright.h"
#include "sysdep.h"
#include "openfile.h"
#ifdef FILESYS_STUB // Temporarily implement file system calls as
// calls to UNIX, until the real file system
// implementation is available
class FileSystem {
public:
FileSystem() { for (int i = 0; i < 20; i++) fileDescriptorTable[i] = NULL; }
bool Create(char *name) {
int fileDescriptor = OpenForWrite(name);
if (fileDescriptor == -1) return FALSE;
Close(fileDescriptor);
return TRUE;
}
OpenFile* Open(char *name) {
int fileDescriptor = OpenForReadWrite(name, FALSE);
if (fileDescriptor == -1) return NULL;
return new OpenFile(fileDescriptor);
}
bool Remove(char *name) { return Unlink(name) == 0; }
OpenFile *fileDescriptorTable[20];
};
#else // FILESYS
class FileSystem {
public:
FileSystem(bool format); // Initialize the file system.
// Must be called *after* "synchDisk"
// has been initialized.
// If "format", there is nothing on
// the disk, so initialize the directory
// and the bitmap of free blocks.
bool Create(char *name, int initialSize);
// Create a file (UNIX creat)
OpenFile* Open(char *name); // Open a file (UNIX open)
bool Remove(char *name); // Delete a file (UNIX unlink)
void List(); // List all the files in the file system
void Print(); // List all the files and their contents
private:
OpenFile* freeMapFile; // Bit map of free disk blocks,
// represented as a file
OpenFile* directoryFile; // "Root" directory -- list of
// file names, represented as a file
};
#endif // FILESYS
#endif // FS_H

196
code/filesys/openfile.cc Normal file
View File

@@ -0,0 +1,196 @@
// openfile.cc
// Routines to manage an open Nachos file. As in UNIX, a
// file must be open before we can read or write to it.
// Once we're all done, we can close it (in Nachos, by deleting
// the OpenFile data structure).
//
// Also as in UNIX, for convenience, we keep the file header in
// memory while the file is open.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef FILESYS_STUB
#include "copyright.h"
#include "main.h"
#include "filehdr.h"
#include "openfile.h"
#include "synchdisk.h"
//----------------------------------------------------------------------
// OpenFile::OpenFile
// Open a Nachos file for reading and writing. Bring the file header
// into memory while the file is open.
//
// "sector" -- the location on disk of the file header for this file
//----------------------------------------------------------------------
OpenFile::OpenFile(int sector)
{
hdr = new FileHeader;
hdr->FetchFrom(sector);
seekPosition = 0;
}
//----------------------------------------------------------------------
// OpenFile::~OpenFile
// Close a Nachos file, de-allocating any in-memory data structures.
//----------------------------------------------------------------------
OpenFile::~OpenFile()
{
delete hdr;
}
//----------------------------------------------------------------------
// OpenFile::Seek
// Change the current location within the open file -- the point at
// which the next Read or Write will start from.
//
// "position" -- the location within the file for the next Read/Write
//----------------------------------------------------------------------
void
OpenFile::Seek(int position)
{
seekPosition = position;
}
//----------------------------------------------------------------------
// OpenFile::Read/Write
// Read/write a portion of a file, starting from seekPosition.
// Return the number of bytes actually written or read, and as a
// side effect, increment the current position within the file.
//
// Implemented using the more primitive ReadAt/WriteAt.
//
// "into" -- the buffer to contain the data to be read from disk
// "from" -- the buffer containing the data to be written to disk
// "numBytes" -- the number of bytes to transfer
//----------------------------------------------------------------------
int
OpenFile::Read(char *into, int numBytes)
{
int result = ReadAt(into, numBytes, seekPosition);
seekPosition += result;
return result;
}
int
OpenFile::Write(char *into, int numBytes)
{
int result = WriteAt(into, numBytes, seekPosition);
seekPosition += result;
return result;
}
//----------------------------------------------------------------------
// OpenFile::ReadAt/WriteAt
// Read/write a portion of a file, starting at "position".
// Return the number of bytes actually written or read, but has
// no side effects (except that Write modifies the file, of course).
//
// There is no guarantee the request starts or ends on an even disk sector
// boundary; however the disk only knows how to read/write a whole disk
// sector at a time. Thus:
//
// For ReadAt:
// We read in all of the full or partial sectors that are part of the
// request, but we only copy the part we are interested in.
// For WriteAt:
// We must first read in any sectors that will be partially written,
// so that we don't overwrite the unmodified portion. We then copy
// in the data that will be modified, and write back all the full
// or partial sectors that are part of the request.
//
// "into" -- the buffer to contain the data to be read from disk
// "from" -- the buffer containing the data to be written to disk
// "numBytes" -- the number of bytes to transfer
// "position" -- the offset within the file of the first byte to be
// read/written
//----------------------------------------------------------------------
int
OpenFile::ReadAt(char *into, int numBytes, int position)
{
int fileLength = hdr->FileLength();
int i, firstSector, lastSector, numSectors;
char *buf;
if ((numBytes <= 0) || (position >= fileLength))
return 0; // check request
if ((position + numBytes) > fileLength)
numBytes = fileLength - position;
DEBUG(dbgFile, "Reading " << numBytes << " bytes at " << position << " from file of length " << fileLength);
firstSector = divRoundDown(position, SectorSize);
lastSector = divRoundDown(position + numBytes - 1, SectorSize);
numSectors = 1 + lastSector - firstSector;
// read in all the full and partial sectors that we need
buf = new char[numSectors * SectorSize];
for (i = firstSector; i <= lastSector; i++)
kernel->synchDisk->ReadSector(hdr->ByteToSector(i * SectorSize),
&buf[(i - firstSector) * SectorSize]);
// copy the part we want
bcopy(&buf[position - (firstSector * SectorSize)], into, numBytes);
delete [] buf;
return numBytes;
}
int
OpenFile::WriteAt(char *from, int numBytes, int position)
{
int fileLength = hdr->FileLength();
int i, firstSector, lastSector, numSectors;
bool firstAligned, lastAligned;
char *buf;
if ((numBytes <= 0) || (position >= fileLength))
return 0; // check request
if ((position + numBytes) > fileLength)
numBytes = fileLength - position;
DEBUG(dbgFile, "Writing " << numBytes << " bytes at " << position << " from file of length " << fileLength);
firstSector = divRoundDown(position, SectorSize);
lastSector = divRoundDown(position + numBytes - 1, SectorSize);
numSectors = 1 + lastSector - firstSector;
buf = new char[numSectors * SectorSize];
firstAligned = (position == (firstSector * SectorSize));
lastAligned = ((position + numBytes) == ((lastSector + 1) * SectorSize));
// read in first and last sector, if they are to be partially modified
if (!firstAligned)
ReadAt(buf, SectorSize, firstSector * SectorSize);
if (!lastAligned && ((firstSector != lastSector) || firstAligned))
ReadAt(&buf[(lastSector - firstSector) * SectorSize],
SectorSize, lastSector * SectorSize);
// copy in the bytes we want to change
bcopy(from, &buf[position - (firstSector * SectorSize)], numBytes);
// write modified sectors back
for (i = firstSector; i <= lastSector; i++)
kernel->synchDisk->WriteSector(hdr->ByteToSector(i * SectorSize),
&buf[(i - firstSector) * SectorSize]);
delete [] buf;
return numBytes;
}
//----------------------------------------------------------------------
// OpenFile::Length
// Return the number of bytes in the file.
//----------------------------------------------------------------------
int
OpenFile::Length()
{
return hdr->FileLength();
}
#endif //FILESYS_STUB

97
code/filesys/openfile.h Normal file
View File

@@ -0,0 +1,97 @@
// openfile.h
// Data structures for opening, closing, reading and writing to
// individual files. The operations supported are similar to
// the UNIX ones -- type 'man open' to the UNIX prompt.
//
// There are two implementations. One is a "STUB" that directly
// turns the file operations into the underlying UNIX operations.
// (cf. comment in filesys.h).
//
// The other is the "real" implementation, that turns these
// operations into read and write disk sector requests.
// In this baseline implementation of the file system, we don't
// worry about concurrent accesses to the file system
// by different threads.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef OPENFILE_H
#define OPENFILE_H
#include "copyright.h"
#include "utility.h"
#include "sysdep.h"
#ifdef FILESYS_STUB // Temporarily implement calls to
// Nachos file system as calls to UNIX!
// See definitions listed under #else
class OpenFile {
public:
OpenFile(int f) { file = f; currentOffset = 0; } // open the file
~OpenFile() { Close(file); } // close the file
int ReadAt(char *into, int numBytes, int position) {
Lseek(file, position, 0);
return ReadPartial(file, into, numBytes);
}
int WriteAt(char *from, int numBytes, int position) {
Lseek(file, position, 0);
WriteFile(file, from, numBytes);
return numBytes;
}
int Read(char *into, int numBytes) {
int numRead = ReadAt(into, numBytes, currentOffset);
currentOffset += numRead;
return numRead;
}
int Write(char *from, int numBytes) {
int numWritten = WriteAt(from, numBytes, currentOffset);
currentOffset += numWritten;
return numWritten;
}
int Length() { Lseek(file, 0, 2); return Tell(file); }
private:
int file;
int currentOffset;
};
#else // FILESYS
class FileHeader;
class OpenFile {
public:
OpenFile(int sector); // Open a file whose header is located
// at "sector" on the disk
~OpenFile(); // Close the file
void Seek(int position); // Set the position from which to
// start reading/writing -- UNIX lseek
int Read(char *into, int numBytes); // Read/write bytes from the file,
// starting at the implicit position.
// Return the # actually read/written,
// and increment position in file.
int Write(char *from, int numBytes);
int ReadAt(char *into, int numBytes, int position);
// Read/write bytes from the file,
// bypassing the implicit position.
int WriteAt(char *from, int numBytes, int position);
int Length(); // Return the number of bytes in the
// file (this interface is simpler
// than the UNIX idiom -- lseek to
// end of file, tell, lseek back
private:
FileHeader *hdr; // Header for this file
int seekPosition; // Current position within the file
};
#endif // FILESYS
#endif // OPENFILE_H

79
code/filesys/pbitmap.cc Normal file
View File

@@ -0,0 +1,79 @@
// pbitmap.c
// Routines to manage a persistent bitmap -- a bitmap that is
// stored on disk.
//
// Copyright (c) 1992,1993,1995 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "pbitmap.h"
//----------------------------------------------------------------------
// PersistentBitmap::PersistentBitmap(int)
// Initialize a bitmap with "numItems" bits, so that every bit is clear.
// it can be added somewhere on a list.
//
// "numItems" is the number of bits in the bitmap.
//
// This constructor does not initialize the bitmap from a disk file
//----------------------------------------------------------------------
PersistentBitmap::PersistentBitmap(int numItems):Bitmap(numItems)
{
}
//----------------------------------------------------------------------
// PersistentBitmap::PersistentBitmap(OpenFile*,int)
// Initialize a persistent bitmap with "numItems" bits,
// so that every bit is clear.
//
// "numItems" is the number of bits in the bitmap.
// "file" refers to an open file containing the bitmap (written
// by a previous call to PersistentBitmap::WriteBack
//
// This constructor initializes the bitmap from a disk file
//----------------------------------------------------------------------
PersistentBitmap::PersistentBitmap(OpenFile *file, int numItems):Bitmap(numItems)
{
// map has already been initialized by the BitMap constructor,
// but we will just overwrite that with the contents of the
// map found in the file
file->ReadAt((char *)map, numWords * sizeof(unsigned), 0);
}
//----------------------------------------------------------------------
// PersistentBitmap::~PersistentBitmap
// De-allocate a persistent bitmap.
//----------------------------------------------------------------------
PersistentBitmap::~PersistentBitmap()
{
}
//----------------------------------------------------------------------
// PersistentBitmap::FetchFrom
// Initialize the contents of a persistent bitmap from a Nachos file.
//
// "file" is the place to read the bitmap from
//----------------------------------------------------------------------
void
PersistentBitmap::FetchFrom(OpenFile *file)
{
file->ReadAt((char *)map, numWords * sizeof(unsigned), 0);
}
//----------------------------------------------------------------------
// PersistentBitmap::WriteBack
// Store the contents of a persistent bitmap to a Nachos file.
//
// "file" is the place to write the bitmap to
//----------------------------------------------------------------------
void
PersistentBitmap::WriteBack(OpenFile *file)
{
file->WriteAt((char *)map, numWords * sizeof(unsigned), 0);
}

35
code/filesys/pbitmap.h Normal file
View File

@@ -0,0 +1,35 @@
// pbitmap.h
// Data structures defining a "persistent" bitmap -- a bitmap
// that can be stored and fetched off of disk
//
// A persistent bitmap can either be initialized from the disk
// when it is created, or it can be initialized later using
// the FetchFrom method
//
// Copyright (c) 1992,1993,1995 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef PBITMAP_H
#define PBITMAP_H
#include "copyright.h"
#include "bitmap.h"
#include "openfile.h"
// The following class defines a persistent bitmap. It inherits all
// the behavior of a bitmap (see bitmap.h), adding the ability to
// be read from and stored to the disk.
class PersistentBitmap : public Bitmap {
public:
PersistentBitmap(OpenFile *file,int numItems); //initialize bitmap from disk
PersistentBitmap(int numItems); // or don't...
~PersistentBitmap(); // deallocate bitmap
void FetchFrom(OpenFile *file); // read bitmap from the disk
void WriteBack(OpenFile *file); // write bitmap contents to disk
};
#endif // PBITMAP_H

94
code/filesys/synchdisk.cc Normal file
View File

@@ -0,0 +1,94 @@
// synchdisk.cc
// Routines to synchronously access the disk. The physical disk
// is an asynchronous device (disk requests return immediately, and
// an interrupt happens later on). This is a layer on top of
// the disk providing a synchronous interface (requests wait until
// the request completes).
//
// Use a semaphore to synchronize the interrupt handlers with the
// pending requests. And, because the physical disk can only
// handle one operation at a time, use a lock to enforce mutual
// exclusion.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "synchdisk.h"
//----------------------------------------------------------------------
// SynchDisk::SynchDisk
// Initialize the synchronous interface to the physical disk, in turn
// initializing the physical disk.
//
//----------------------------------------------------------------------
SynchDisk::SynchDisk()
{
semaphore = new Semaphore("synch disk", 0);
lock = new Lock("synch disk lock");
disk = new Disk(this);
}
//----------------------------------------------------------------------
// SynchDisk::~SynchDisk
// De-allocate data structures needed for the synchronous disk
// abstraction.
//----------------------------------------------------------------------
SynchDisk::~SynchDisk()
{
delete disk;
delete lock;
delete semaphore;
}
//----------------------------------------------------------------------
// SynchDisk::ReadSector
// Read the contents of a disk sector into a buffer. Return only
// after the data has been read.
//
// "sectorNumber" -- the disk sector to read
// "data" -- the buffer to hold the contents of the disk sector
//----------------------------------------------------------------------
void
SynchDisk::ReadSector(int sectorNumber, char* data)
{
lock->Acquire(); // only one disk I/O at a time
disk->ReadRequest(sectorNumber, data);
semaphore->P(); // wait for interrupt
lock->Release();
}
//----------------------------------------------------------------------
// SynchDisk::WriteSector
// Write the contents of a buffer into a disk sector. Return only
// after the data has been written.
//
// "sectorNumber" -- the disk sector to be written
// "data" -- the new contents of the disk sector
//----------------------------------------------------------------------
void
SynchDisk::WriteSector(int sectorNumber, char* data)
{
lock->Acquire(); // only one disk I/O at a time
disk->WriteRequest(sectorNumber, data);
semaphore->P(); // wait for interrupt
lock->Release();
}
//----------------------------------------------------------------------
// SynchDisk::CallBack
// Disk interrupt handler. Wake up any thread waiting for the disk
// request to finish.
//----------------------------------------------------------------------
void
SynchDisk::CallBack()
{
semaphore->V();
}

55
code/filesys/synchdisk.h Normal file
View File

@@ -0,0 +1,55 @@
// synchdisk.h
// Data structures to export a synchronous interface to the raw
// disk device.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#ifndef SYNCHDISK_H
#define SYNCHDISK_H
#include "disk.h"
#include "synch.h"
#include "callback.h"
// The following class defines a "synchronous" disk abstraction.
// As with other I/O devices, the raw physical disk is an asynchronous device --
// requests to read or write portions of the disk return immediately,
// and an interrupt occurs later to signal that the operation completed.
// (Also, the physical characteristics of the disk device assume that
// only one operation can be requested at a time).
//
// This class provides the abstraction that for any individual thread
// making a request, it waits around until the operation finishes before
// returning.
class SynchDisk : public CallBackObj {
public:
SynchDisk(); // Initialize a synchronous disk,
// by initializing the raw Disk.
~SynchDisk(); // De-allocate the synch disk data
void ReadSector(int sectorNumber, char* data);
// Read/write a disk sector, returning
// only once the data is actually read
// or written. These call
// Disk::ReadRequest/WriteRequest and
// then wait until the request is done.
void WriteSector(int sectorNumber, char* data);
void CallBack(); // Called by the disk device interrupt
// handler, to signal that the
// current disk operation is complete.
private:
Disk *disk; // Raw disk device
Semaphore *semaphore; // To synchronize requesting thread
// with the interrupt handler
Lock *lock; // Only one read/write request
// can be sent to the disk at a time
};
#endif // SYNCHDISK_H

191
code/lib/bitmap.cc Normal file
View File

@@ -0,0 +1,191 @@
// bitmap.cc
// Routines to manage a bitmap -- an array of bits each of which
// can be either on or off. Represented as an array of integers.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "debug.h"
#include "bitmap.h"
//----------------------------------------------------------------------
// BitMap::BitMap
// Initialize a bitmap with "numItems" bits, so that every bit is clear.
// it can be added somewhere on a list.
//
// "numItems" is the number of bits in the bitmap.
//----------------------------------------------------------------------
Bitmap::Bitmap(int numItems)
{
int i;
ASSERT(numItems > 0);
numBits = numItems;
numWords = divRoundUp(numBits, BitsInWord);
map = new unsigned int[numWords];
for (i = 0; i < numWords; i++) {
map[i] = 0; // initialize map to keep Purify happy
}
for (i = 0; i < numBits; i++) {
Clear(i);
}
}
//----------------------------------------------------------------------
// Bitmap::~Bitmap
// De-allocate a bitmap.
//----------------------------------------------------------------------
Bitmap::~Bitmap()
{
delete map;
}
//----------------------------------------------------------------------
// Bitmap::Set
// Set the "nth" bit in a bitmap.
//
// "which" is the number of the bit to be set.
//----------------------------------------------------------------------
void
Bitmap::Mark(int which)
{
ASSERT(which >= 0 && which < numBits);
map[which / BitsInWord] |= 1 << (which % BitsInWord);
ASSERT(Test(which));
}
//----------------------------------------------------------------------
// Bitmap::Clear
// Clear the "nth" bit in a bitmap.
//
// "which" is the number of the bit to be cleared.
//----------------------------------------------------------------------
void
Bitmap::Clear(int which)
{
ASSERT(which >= 0 && which < numBits);
map[which / BitsInWord] &= ~(1 << (which % BitsInWord));
ASSERT(!Test(which));
}
//----------------------------------------------------------------------
// Bitmap::Test
// Return TRUE if the "nth" bit is set.
//
// "which" is the number of the bit to be tested.
//----------------------------------------------------------------------
bool
Bitmap::Test(int which) const
{
ASSERT(which >= 0 && which < numBits);
if (map[which / BitsInWord] & (1 << (which % BitsInWord))) {
return TRUE;
} else {
return FALSE;
}
}
//----------------------------------------------------------------------
// Bitmap::FindAndSet
// Return the number of the first bit which is clear.
// As a side effect, set the bit (mark it as in use).
// (In other words, find and allocate a bit.)
//
// If no bits are clear, return -1.
//----------------------------------------------------------------------
int
Bitmap::FindAndSet()
{
for (int i = 0; i < numBits; i++) {
if (!Test(i)) {
Mark(i);
return i;
}
}
return -1;
}
//----------------------------------------------------------------------
// Bitmap::NumClear
// Return the number of clear bits in the bitmap.
// (In other words, how many bits are unallocated?)
//----------------------------------------------------------------------
int
Bitmap::NumClear() const
{
int count = 0;
for (int i = 0; i < numBits; i++) {
if (!Test(i)) {
count++;
}
}
return count;
}
//----------------------------------------------------------------------
// Bitmap::Print
// Print the contents of the bitmap, for debugging.
//
// Could be done in a number of ways, but we just print the #'s of
// all the bits that are set in the bitmap.
//----------------------------------------------------------------------
void
Bitmap::Print() const
{
cout << "Bitmap set:\n";
for (int i = 0; i < numBits; i++) {
if (Test(i)) {
cout << i << ", ";
}
}
cout << "\n";
}
//----------------------------------------------------------------------
// Bitmap::SelfTest
// Test whether this module is working.
//----------------------------------------------------------------------
void
Bitmap::SelfTest()
{
int i;
ASSERT(numBits >= BitsInWord); // bitmap must be big enough
ASSERT(NumClear() == numBits); // bitmap must be empty
ASSERT(FindAndSet() == 0);
Mark(31);
ASSERT(Test(0) && Test(31));
ASSERT(FindAndSet() == 1);
Clear(0);
Clear(1);
Clear(31);
for (i = 0; i < numBits; i++) {
Mark(i);
}
ASSERT(FindAndSet() == -1); // bitmap should be full!
for (i = 0; i < numBits; i++) {
Clear(i);
}
}

59
code/lib/bitmap.h Normal file
View File

@@ -0,0 +1,59 @@
// bitmap.h
// Data structures defining a bitmap -- an array of bits each of which
// can be either on or off.
//
// Represented as an array of unsigned integers, on which we do
// modulo arithmetic to find the bit we are interested in.
//
// The bitmap can be parameterized with with the number of bits being
// managed.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef BITMAP_H
#define BITMAP_H
#include "copyright.h"
#include "utility.h"
// Definitions helpful for representing a bitmap as an array of integers
const int BitsInByte = 8;
const int BitsInWord = sizeof(unsigned int) * BitsInByte;
// The following class defines a "bitmap" -- an array of bits,
// each of which can be independently set, cleared, and tested.
//
// Most useful for managing the allocation of the elements of an array --
// for instance, disk sectors, or main memory pages.
// Each bit represents whether the corresponding sector or page is
// in use or free.
class Bitmap {
public:
Bitmap(int numItems); // Initialize a bitmap, with "numItems" bits
// initially, all bits are cleared.
~Bitmap(); // De-allocate bitmap
void Mark(int which); // Set the "nth" bit
void Clear(int which); // Clear the "nth" bit
bool Test(int which) const; // Is the "nth" bit set?
int FindAndSet(); // Return the # of a clear bit, and as a side
// effect, set the bit.
// If no bits are clear, return -1.
int NumClear() const; // Return the number of clear bits
void Print() const; // Print contents of bitmap
void SelfTest(); // Test whether bitmap is working
protected:
int numBits; // number of bits in the bitmap
int numWords; // number of words of bitmap storage
// (rounded up if numBits is not a
// multiple of the number of bits in
// a word)
unsigned int *map; // bit storage
};
#endif // BITMAP_H

24
code/lib/copyright.h Normal file
View File

@@ -0,0 +1,24 @@
/*
Copyright (c) 1992-1996 The Regents of the University of California.
All rights reserved.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose, without fee, and without written agreement is
hereby granted, provided that the above copyright notice and the following
two paragraphs appear in all copies of this software.
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifdef MAIN /* include the copyright message in every executable */
static char *copyright = "Copyright (c) 1992-1993 The Regents of the University of California. All rights reserved.";
#endif // MAIN

45
code/lib/debug.cc Normal file
View File

@@ -0,0 +1,45 @@
// debug.cc
// Debugging routines. Allows users to control whether to
// print DEBUG statements, based on a command line argument.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "utility.h"
#include "debug.h"
#include "string.h"
//----------------------------------------------------------------------
// Debug::Debug
// Initialize so that only DEBUG messages with a flag in flagList
// will be printed.
//
// If the flag is "+", we enable all DEBUG messages.
//
// "flagList" is a string of characters for whose DEBUG messages are
// to be enabled.
//----------------------------------------------------------------------
Debug::Debug(char *flagList)
{
enableFlags = flagList;
}
//----------------------------------------------------------------------
// Debug::IsEnabled
// Return TRUE if DEBUG messages with "flag" are to be printed.
//----------------------------------------------------------------------
bool
Debug::IsEnabled(char flag)
{
if (enableFlags != NULL) {
return ((strchr(enableFlags, flag) != 0)
|| (strchr(enableFlags, '+') != 0));
} else {
return FALSE;
}
}

96
code/lib/debug.h Normal file
View File

@@ -0,0 +1,96 @@
// debug.h
// Data structures for debugging routines.
//
// The debugging routines allow the user to turn on selected
// debugging messages, controllable from the command line arguments
// passed to Nachos (-d). You are encouraged to add your own
// debugging flags. Please....
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef DEBUG_H
#define DEBUG_H
#include "copyright.h"
#include "utility.h"
#include "sysdep.h"
// The pre-defined debugging flags are:
const char dbgAll = '+'; // turn on all debug messages
const char dbgThread = 't'; // threads
const char dbgSynch = 's'; // locks, semaphores, condition vars
const char dbgInt = 'i'; // interrupt emulation
const char dbgMach = 'm'; // machine emulation
const char dbgDisk = 'd'; // disk emulation
const char dbgFile = 'f'; // file system
const char dbgAddr = 'a'; // address spaces
const char dbgNet = 'n'; // network emulation
const char dbgSys = 'u'; // systemcall
class Debug {
public:
Debug(char *flagList);
bool IsEnabled(char flag);
private:
char *enableFlags; // controls which DEBUG messages are printed
};
extern Debug *debug;
//----------------------------------------------------------------------
// DEBUG
// If flag is enabled, print a message.
//----------------------------------------------------------------------
#define DEBUG(flag,expr) \
if (!debug->IsEnabled(flag)) {} else { \
cerr << expr << "\n"; \
}
//----------------------------------------------------------------------
// ASSERT
// If condition is false, print a message and dump core.
// Useful for documenting assumptions in the code.
//
// NOTE: needs to be a #define, to be able to print the location
// where the error occurred.
//----------------------------------------------------------------------
#define ASSERT(condition) \
if (condition) {} else { \
cerr << "Assertion failed: line " << __LINE__ << " file " << __FILE__ << "\n"; \
Abort(); \
}
//----------------------------------------------------------------------
// ASSERTNOTREACHED
// Print a message and dump core (equivalent to ASSERT(FALSE) without
// making the compiler whine). Useful for documenting when
// code should not be reached.
//
// NOTE: needs to be a #define, to be able to print the location
// where the error occurred.
//----------------------------------------------------------------------
#define ASSERTNOTREACHED() \
{ \
cerr << "Assertion failed: line " << __LINE__ << " file " << __FILE__ << "\n"; \
Abort(); \
}
//----------------------------------------------------------------------
// ASSERTUNIMPLEMENTED
// Print a message that unimplemented code is executed and dump core
//----------------------------------------------------------------------
#define UNIMPLEMENTED() \
{ \
cerr << "Reached UNIMPLEMENTED function " << __FUNCTION__ << " in file: " \
<< __FILE__ << " line: " << __LINE__ << ".\n"; \
}
#endif // DEBUG_H

360
code/lib/hash.cc Normal file
View File

@@ -0,0 +1,360 @@
// hash.cc
// Routines to manage a self-expanding hash table of arbitrary things.
// The hashing function is supplied by the objects being put into
// the table; we use chaining to resolve hash conflicts.
//
// The hash table is implemented as an array of sorted lists,
// and we expand the hash table if the number of elements in the table
// gets too big.
//
// NOTE: Mutual exclusion must be provided by the caller.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
const int InitialBuckets = 4; // how big a hash table do we start with
const int ResizeRatio = 3; // when do we grow the hash table?
const int IncreaseSizeBy = 4; // how much do we grow table when needed?
#include "copyright.h"
//----------------------------------------------------------------------
// HashTable<Key,T>::HashTable
// Initialize a hash table, empty to start with.
// Elements can now be added to the table.
//----------------------------------------------------------------------
template <class Key, class T>
HashTable<Key,T>::HashTable(Key (*get)(T x), unsigned (*hFunc)(Key x))
{
numItems = 0;
InitBuckets(InitialBuckets);
getKey = get;
hash = hFunc;
}
//----------------------------------------------------------------------
// HashTable<Key,T>::InitBuckets
// Initialize the bucket array for a hash table.
// Called by the constructor and by ReHash().
//----------------------------------------------------------------------
template <class Key, class T>
void
HashTable<Key,T>::InitBuckets(int sz)
{
numBuckets = sz;
buckets = new Bucket[numBuckets];
for (int i = 0; i < sz; i++) {
buckets[i] = new List<T>;
}
}
//----------------------------------------------------------------------
// HashTable<T>::~HashTable
// Prepare a hash table for deallocation.
//----------------------------------------------------------------------
template <class Key, class T>
HashTable<Key,T>::~HashTable()
{
ASSERT(IsEmpty()); // make sure table is empty
DeleteBuckets(buckets, numBuckets);
}
//----------------------------------------------------------------------
// HashTable<Key,T>::DeleteBuckets
// De-Initialize the bucket array for a hash table.
// Called by the destructor and by ReHash().
//----------------------------------------------------------------------
template <class Key, class T>
void
HashTable<Key,T>::DeleteBuckets(List<T> **table, int sz)
{
for (int i = 0; i < sz; i++) {
delete table[i];
}
delete [] table;
}
//----------------------------------------------------------------------
// HashTable<Key,T>::HashValue
// Return hash table bucket that would contain key.
//----------------------------------------------------------------------
template <class Key, class T>
int
HashTable<Key, T>::HashValue(Key key) const
{
int result = (*hash)(key) % numBuckets;
ASSERT(result >= 0 && result < numBuckets);
return result;
}
//----------------------------------------------------------------------
// HashTable<Key,T>::Insert
// Put an item into the hashtable.
//
// Resize the table if the # of elements / # of buckets is too big.
// Then allocate a HashElement to keep track of the key, item pair,
// and add it to the right bucket.
//
// "key" is the key we'll use to find this item.
// "item" is the thing to put in the table.
//----------------------------------------------------------------------
template <class Key, class T>
void
HashTable<Key,T>::Insert(T item)
{
Key key = getKey(item);
ASSERT(!IsInTable(key));
if ((numItems / numBuckets) >= ResizeRatio) {
ReHash();
}
buckets[HashValue(key)]->Append(item);
numItems++;
ASSERT(IsInTable(key));
}
//----------------------------------------------------------------------
// HashTable<Key,T>::ReHash
// Increase the size of the hashtable, by
// (i) making a new table
// (ii) moving all the elements into the new table
// (iii) deleting the old table
//----------------------------------------------------------------------
template <class Key, class T>
void
HashTable<Key,T>::ReHash()
{
Bucket *oldTable = buckets;
int oldSize = numBuckets;
T item;
SanityCheck();
InitBuckets(numBuckets * IncreaseSizeBy);
for (int i = 0; i < oldSize; i++) {
while (!oldTable[i]->IsEmpty()) {
item = oldTable[i]->RemoveFront();
buckets[HashValue(getKey(item))]->Append(item);
}
}
DeleteBuckets(oldTable, oldSize);
SanityCheck();
}
//----------------------------------------------------------------------
// HashTable<Key,T>::FindInBucket
// Find an item in a hash table bucket, from it's key
//
// "bucket" -- the list storing the item, if it's in the table
// "key" -- the key uniquely identifying the item
//
// Returns:
// Whether item is found, and if found, the item.
//----------------------------------------------------------------------
template <class Key, class T>
bool
HashTable<Key,T>::FindInBucket(int bucket,
Key key, T *itemPtr) const
{
ListIterator<T> iterator(buckets[bucket]);
for (; !iterator.IsDone(); iterator.Next()) {
if (key == getKey(iterator.Item())) { // found!
*itemPtr = iterator.Item();
return TRUE;
}
}
*itemPtr = NULL;
return FALSE;
}
//----------------------------------------------------------------------
// HashTable<Key,T>::Find
// Find an item from the hash table.
//
// Returns:
// The item or NULL if not found.
//----------------------------------------------------------------------
template <class Key, class T>
bool
HashTable<Key,T>::Find(Key key, T *itemPtr) const
{
int bucket = HashValue(key);
return FindInBucket(bucket, key, itemPtr);
}
//----------------------------------------------------------------------
// HashTable<Key,T>::Remove
// Remove an item from the hash table. The item must be in the table.
//
// Returns:
// The removed item.
//----------------------------------------------------------------------
template <class Key, class T>
T
HashTable<Key,T>::Remove(Key key)
{
int bucket = HashValue(key);
T item;
bool found = FindInBucket(bucket, key, &item);
ASSERT(found); // item must be in table
buckets[bucket]->Remove(item);
numItems--;
ASSERT(!IsInTable(key));
return item;
}
//----------------------------------------------------------------------
// HashTable<Key,T>::Apply
// Apply function to every item in the hash table.
//
// "func" -- the function to apply
//----------------------------------------------------------------------
template <class Key,class T>
void
HashTable<Key,T>::Apply(void (*func)(T)) const
{
for (int bucket = 0; bucket < numBuckets; bucket++) {
buckets[bucket]->Apply(func);
}
}
//----------------------------------------------------------------------
// HashTable<Key,T>::FindNextFullBucket
// Find the next bucket in the hash table that has any items in it.
//
// "bucket" -- where to start looking for full buckets
//----------------------------------------------------------------------
template <class Key,class T>
int
HashTable<Key,T>::FindNextFullBucket(int bucket) const
{
for (; bucket < numBuckets; bucket++) {
if (!buckets[bucket]->IsEmpty()) {
break;
}
}
return bucket;
}
//----------------------------------------------------------------------
// HashTable<Key,T>::SanityCheck
// Test whether this is still a legal hash table.
//
// Tests: are all the buckets legal?
// does the table have the right # of elements?
// do all the elements hash to where they are stored?
//----------------------------------------------------------------------
template <class Key, class T>
void
HashTable<Key,T>::SanityCheck() const
{
int numFound = 0;
ListIterator<T> *iterator;
for (int i = 0; i < numBuckets; i++) {
buckets[i]->SanityCheck();
numFound += buckets[i]->NumInList();
iterator = new ListIterator<T>(buckets[i]);
for (; !iterator->IsDone(); iterator->Next()) {
ASSERT(i == HashValue(getKey(iterator->Item())));
}
delete iterator;
}
ASSERT(numItems == numFound);
}
//----------------------------------------------------------------------
// HashTable<Key,T>::SelfTest
// Test whether this module is working.
//----------------------------------------------------------------------
template <class Key, class T>
void
HashTable<Key,T>::SelfTest(T *p, int numEntries)
{
int i;
HashIterator<Key, T> *iterator = new HashIterator<Key,T>(this);
SanityCheck();
ASSERT(IsEmpty()); // check that table is empty in various ways
for (; !iterator->IsDone(); iterator->Next()) {
ASSERTNOTREACHED();
}
delete iterator;
for (i = 0; i < numEntries; i++) {
Insert(p[i]);
ASSERT(IsInTable(getKey(p[i])));
ASSERT(!IsEmpty());
}
// should be able to get out everything we put in
for (i = 0; i < numEntries; i++) {
ASSERT(Remove(getKey(p[i])) == p[i]);
}
ASSERT(IsEmpty());
SanityCheck();
}
//----------------------------------------------------------------------
// HashIterator<Key,T>::HashIterator
// Initialize a data structure to allow us to step through
// every entry in a has table.
//----------------------------------------------------------------------
template <class Key, class T>
HashIterator<Key,T>::HashIterator(HashTable<Key,T> *tbl)
{
table = tbl;
bucket = table->FindNextFullBucket(0);
bucketIter = NULL;
if (bucket < table->numBuckets) {
bucketIter = new ListIterator<T>(table->buckets[bucket]);
}
}
//----------------------------------------------------------------------
// HashIterator<Key,T>::Next
// Update iterator to point to the next item in the table.
//----------------------------------------------------------------------
template <class Key,class T>
void
HashIterator<Key,T>::Next()
{
bucketIter->Next();
if (bucketIter->IsDone()) {
delete bucketIter;
bucketIter = NULL;
bucket = table->FindNextFullBucket(++bucket);
if (bucket < table->numBuckets) {
bucketIter = new ListIterator<T>(table->buckets[bucket]);
}
}
}

123
code/lib/hash.h Normal file
View File

@@ -0,0 +1,123 @@
// hash.h
// Data structures to manage a hash table to relate arbitrary
// keys to arbitrary values. A hash table allows efficient lookup
// for the value given the key.
//
// I've only tested this implementation when both the key and the
// value are primitive types (ints or pointers). There is no
// guarantee that it will work in general. In particular, it
// assumes that the "==" operator works for both keys and values.
//
// In addition, the key must have Hash() defined:
// unsigned Hash(Key k);
// returns a randomized # based on value of key
//
// The value must have a function defined to retrieve the key:
// Key GetKey(T x);
//
// The hash table automatically resizes itself as items are
// put into the table. The implementation uses chaining
// to resolve hash conflicts.
//
// Allocation and deallocation of the items in the table are to
// be done by the caller.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef HASH_H
#define HASH_H
#include "copyright.h"
#include "list.h"
// The following class defines a "hash table" -- allowing quick
// lookup according to the hash function defined for the items
// being put into the table.
template <class Key,class T> class HashIterator;
template <class Key, class T>
class HashTable {
public:
HashTable(Key (*get)(T x), unsigned (*hFunc)(Key x));
// initialize a hash table
~HashTable(); // deallocate a hash table
void Insert(T item); // Put item into hash table
T Remove(Key key); // Remove item from hash table.
bool Find(Key key, T *itemPtr) const;
// Find an item from its key
bool IsInTable(Key key) { T dummy; return Find(key, &dummy); }
// Is the item in the table?
bool IsEmpty() { return numItems == 0; }
// does the table have anything in it
void Apply(void (*f)(T)) const;
// apply function to all elements in table
void SanityCheck() const;// is this still a legal hash table?
void SelfTest(T *p, int numItems);
// is the module working?
private:
typedef List<T> *Bucket;
Bucket *buckets; // the array of hash buckets
int numBuckets; // the number of buckets
int numItems; // the number of items in the table
Key (*getKey)(T x); // get Key from value
unsigned (*hash)(Key x); // the hash function
void InitBuckets(int size);// initialize bucket array
void DeleteBuckets(Bucket *table, int size);
// deallocate bucket array
int HashValue(Key key) const;
// which bucket does the key hash to?
void ReHash(); // expand the hash table
bool FindInBucket(int bucket, Key key, T *itemPtr) const;
// find item in bucket
int FindNextFullBucket(int start) const;
// find next full bucket starting from this one
friend class HashIterator<Key,T>;
};
// The following class can be used to step through a hash table --
// same interface as ListIterator. Example code:
// HashIterator<Key, T> iter(table);
//
// for (; !iter->IsDone(); iter->Next()) {
// Operation on iter->Item()
// }
template <class Key,class T>
class HashIterator {
public:
HashIterator(HashTable<Key,T> *table); // initialize an iterator
~HashIterator() { if (bucketIter != NULL) delete bucketIter;};
// destruct an iterator
bool IsDone() { return (bucket == table->numBuckets); };
// return TRUE if no more items in table
T Item() { ASSERT(!IsDone()); return bucketIter->Item(); };
// return current item in table
void Next(); // update iterator to point to next
private:
HashTable<Key,T> *table; // the hash table we're stepping through
int bucket; // current bucket we are in
ListIterator<T> *bucketIter; // where we are in the bucket
};
#include "hash.cc" // templates are really like macros
// so needs to be included in every
// file that uses the template
#endif // HASH_H

85
code/lib/libtest.cc Normal file
View File

@@ -0,0 +1,85 @@
// libtest.cc
// Driver code to call self-test routines for standard library
// classes -- bitmaps, lists, sorted lists, and hash tables.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "libtest.h"
#include "bitmap.h"
#include "list.h"
#include "hash.h"
#include "sysdep.h"
//----------------------------------------------------------------------
// IntCompare
// Compare two integers together. Serves as the comparison
// function for testing SortedLists
//----------------------------------------------------------------------
static int
IntCompare(int x, int y) {
if (x < y) return -1;
else if (x == y) return 0;
else return 1;
}
//----------------------------------------------------------------------
// HashInt, HashKey
// Compute a hash function on an integer. Serves as the
// hashing function for testing HashTables.
//----------------------------------------------------------------------
static unsigned int
HashInt(int key) {
return (unsigned int) key;
}
//----------------------------------------------------------------------
// HashKey
// Convert a string into an integer. Serves as the function
// to retrieve the key from the item in the hash table, for
// testing HashTables. Should be able to use "atoi" directly,
// but some compilers complain about that.
//----------------------------------------------------------------------
static int
HashKey(char *str) {
return atoi(str);
}
// Array of values to be inserted into a List or SortedList.
static int listTestVector[] = { 9, 5, 7 };
// Array of values to be inserted into the HashTable
// There are enough here to force a ReHash().
static char *hashTestVector[] = { "0", "1", "2", "3", "4", "5", "6",
"7", "8", "9", "10", "11", "12", "13", "14"};
//----------------------------------------------------------------------
// LibSelfTest
// Run self tests on bitmaps, lists, sorted lists, and
// hash tables.
//----------------------------------------------------------------------
void
LibSelfTest () {
Bitmap *map = new Bitmap(200);
List<int> *list = new List<int>;
SortedList<int> *sortList = new SortedList<int>(IntCompare);
HashTable<int, char *> *hashTable =
new HashTable<int, char *>(HashKey, HashInt);
map->SelfTest();
list->SelfTest(listTestVector, sizeof(listTestVector)/sizeof(int));
sortList->SelfTest(listTestVector, sizeof(listTestVector)/sizeof(int));
hashTable->SelfTest(hashTestVector, sizeof(hashTestVector)/sizeof(char *));
delete map;
delete list;
delete sortList;
delete hashTable;
}

15
code/lib/libtest.h Normal file
View File

@@ -0,0 +1,15 @@
// libtest.h
// Defines self test module for standard library routines.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef LIBTEST_H
#define LIBTEST_H
#include "copyright.h"
extern void LibSelfTest();
#endif // LIBTEST_H

408
code/lib/list.cc Normal file
View File

@@ -0,0 +1,408 @@
// list.cc
// Routines to manage a singly linked list of "things".
// Lists are implemented as templates so that we can store
// anything on the list in a type-safe manner.
//
// A "ListElement" is allocated for each item to be put on the
// list; it is de-allocated when the item is removed. This means
// we don't need to keep a "next" pointer in every object we
// want to put on a list.
//
// NOTE: Mutual exclusion must be provided by the caller.
// If you want a synchronized list, you must use the routines
// in synchlist.cc.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
//----------------------------------------------------------------------
// ListElement<T>::ListElement
// Initialize a list element, so it can be added somewhere on a list.
//
// "itm" is the thing to be put on the list.
//----------------------------------------------------------------------
template <class T>
ListElement<T>::ListElement(T itm)
{
item = itm;
next = NULL; // always initialize to something!
}
//----------------------------------------------------------------------
// List<T>::List
// Initialize a list, empty to start with.
// Elements can now be added to the list.
//----------------------------------------------------------------------
template <class T>
List<T>::List()
{
first = last = NULL;
numInList = 0;
}
//----------------------------------------------------------------------
// List<T>::~List
// Prepare a list for deallocation.
// This does *NOT* free list elements, nor does it
// free the data those elements point to.
// Normally, the list should be empty when this is called.
//----------------------------------------------------------------------
template <class T>
List<T>::~List()
{
}
//----------------------------------------------------------------------
// List<T>::Append
// Append an "item" to the end of the list.
//
// Allocate a ListElement to keep track of the item.
// If the list is empty, then this will be the only element.
// Otherwise, put it at the end.
//
// "item" is the thing to put on the list.
//----------------------------------------------------------------------
template <class T>
void List<T>::Append(T item)
{
ListElement<T> *element = new ListElement<T>(item);
ASSERT(!this->IsInList(item));
if (IsEmpty())
{ // list is empty
first = element;
last = element;
}
else
{ // else put it after last
last->next = element;
last = element;
}
numInList++;
ASSERT(this->IsInList(item));
}
//----------------------------------------------------------------------
// List<T>::Prepend
// Same as Append, only put "item" on the front.
//----------------------------------------------------------------------
template <class T>
void List<T>::Prepend(T item)
{
ListElement<T> *element = new ListElement<T>(item);
ASSERT(!this->IsInList(item));
if (IsEmpty())
{ // list is empty
first = element;
last = element;
}
else
{ // else put it before first
element->next = first;
first = element;
}
numInList++;
ASSERT(this->IsInList(item));
}
//----------------------------------------------------------------------
// List<T>::RemoveFront
// Remove the first "item" from the front of the list.
// List must not be empty.
//
// Returns:
// The removed item.
//----------------------------------------------------------------------
template <class T>
T List<T>::RemoveFront()
{
ListElement<T> *element = first;
T thing;
ASSERT(!IsEmpty());
thing = first->item;
if (first == last)
{ // list had one item, now has none
first = NULL;
last = NULL;
}
else
{
first = element->next;
}
numInList--;
delete element;
return thing;
}
//----------------------------------------------------------------------
// List<T>::Remove
// Remove a specific item from the list. Must be in the list!
//----------------------------------------------------------------------
template <class T>
void List<T>::Remove(T item)
{
ListElement<T> *prev, *ptr;
T removed;
ASSERT(this->IsInList(item));
// if first item on list is match, then remove from front
if (item == first->item)
{
removed = RemoveFront();
ASSERT(item == removed);
}
else
{
prev = first;
for (ptr = first->next; ptr != NULL; prev = ptr, ptr = ptr->next)
{
if (item == ptr->item)
{
prev->next = ptr->next;
if (prev->next == NULL)
{
last = prev;
}
delete ptr;
numInList--;
break;
}
}
ASSERT(ptr != NULL); // should always find item!
}
ASSERT(!this->IsInList(item));
}
//----------------------------------------------------------------------
// List<T>::IsInList
// Return TRUE if the item is in the list.
//----------------------------------------------------------------------
template <class T>
bool List<T>::IsInList(T item) const
{
ListElement<T> *ptr;
for (ptr = first; ptr != NULL; ptr = ptr->next)
{
if (item == ptr->item)
{
return TRUE;
}
}
return FALSE;
}
//----------------------------------------------------------------------
// List<T>::Apply
// Apply function to every item on a list.
//
// "func" -- the function to apply
//----------------------------------------------------------------------
template <class T>
void List<T>::Apply(void (*func)(T)) const
{
ListElement<T> *ptr;
for (ptr = first; ptr != NULL; ptr = ptr->next)
{
(*func)(ptr->item);
}
}
//----------------------------------------------------------------------
// SortedList::Insert
// Insert an "item" into a list, so that the list elements are
// sorted in increasing order.
//
// Allocate a ListElement to keep track of the item.
// If the list is empty, then this will be the only element.
// Otherwise, walk through the list, one element at a time,
// to find where the new item should be placed.
//
// "item" is the thing to put on the list.
//----------------------------------------------------------------------
template <class T>
void SortedList<T>::Insert(T item)
{
ListElement<T> *element = new ListElement<T>(item);
ListElement<T> *ptr; // keep track
ASSERT(!this->IsInList(item));
if (this->IsEmpty())
{ // if list is empty, put at front
this->first = element;
this->last = element;
}
else if (compare(item, this->first->item) < 0)
{ // item goes at front
element->next = this->first;
this->first = element;
}
else
{ // look for first elt in list bigger than item
for (ptr = this->first; ptr->next != NULL; ptr = ptr->next)
{
if (compare(item, ptr->next->item) < 0)
{
element->next = ptr->next;
ptr->next = element;
this->numInList++;
return;
}
}
this->last->next = element; // item goes at end of list
this->last = element;
}
this->numInList++;
ASSERT(this->IsInList(item));
}
//----------------------------------------------------------------------
// List::SanityCheck
// Test whether this is still a legal list.
//
// Tests: do I get to last starting from first?
// does the list have the right # of elements?
//----------------------------------------------------------------------
template <class T>
void List<T>::SanityCheck() const
{
ListElement<T> *ptr;
int numFound;
if (first == NULL)
{
ASSERT((numInList == 0) && (last == NULL));
}
else if (first == last)
{
ASSERT((numInList == 1) && (last->next == NULL));
}
else
{
for (numFound = 1, ptr = first; ptr != last; ptr = ptr->next)
{
numFound++;
ASSERT(numFound <= numInList); // prevent infinite loop
}
ASSERT(numFound == numInList);
ASSERT(last->next == NULL);
}
}
//----------------------------------------------------------------------
// List::SelfTest
// Test whether this module is working.
//----------------------------------------------------------------------
template <class T>
void List<T>::SelfTest(T *p, int numEntries)
{
int i;
ListIterator<T> *iterator = new ListIterator<T>(this);
SanityCheck();
// check various ways that list is empty
ASSERT(IsEmpty() && (first == NULL));
for (; !iterator->IsDone(); iterator->Next())
{
ASSERTNOTREACHED(); // nothing on list
}
for (i = 0; i < numEntries; i++)
{
Append(p[i]);
ASSERT(this->IsInList(p[i]));
ASSERT(!IsEmpty());
}
SanityCheck();
// should be able to get out everything we put in
for (i = 0; i < numEntries; i++)
{
Remove(p[i]);
ASSERT(!this->IsInList(p[i]));
}
ASSERT(IsEmpty());
SanityCheck();
delete iterator;
}
//----------------------------------------------------------------------
// SortedList::SanityCheck
// Test whether this is still a legal sorted list.
//
// Test: is the list sorted?
//----------------------------------------------------------------------
template <class T>
void SortedList<T>::SanityCheck() const
{
ListElement<T> *prev, *ptr;
List<T>::SanityCheck();
if (this->first != this->last)
{
for (prev = this->first, ptr = this->first->next; ptr != NULL;
prev = ptr, ptr = ptr->next)
{
ASSERT(compare(prev->item, ptr->item) <= 0);
}
}
}
//----------------------------------------------------------------------
// SortedList::SelfTest
// Test whether this module is working.
//----------------------------------------------------------------------
template <class T>
void SortedList<T>::SelfTest(T *p, int numEntries)
{
int i;
T *q = new T[numEntries];
List<T>::SelfTest(p, numEntries);
for (i = 0; i < numEntries; i++)
{
Insert(p[i]);
ASSERT(this->IsInList(p[i]));
}
SanityCheck();
// should be able to get out everything we put in
for (i = 0; i < numEntries; i++)
{
q[i] = this->RemoveFront();
ASSERT(!this->IsInList(q[i]));
}
ASSERT(this->IsEmpty());
// make sure everything came out in the right order
for (i = 0; i < (numEntries - 1); i++)
{
ASSERT(compare(q[i], q[i + 1]) <= 0);
}
SanityCheck();
delete q;
}

142
code/lib/list.h Normal file
View File

@@ -0,0 +1,142 @@
// list.h
// Data structures to manage LISP-like lists.
//
// As in LISP, a list can contain any type of data structure
// as an item on the list: thread control blocks,
// pending interrupts, etc. Allocation and deallocation of the
// items on the list are to be done by the caller.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef LIST_H
#define LIST_H
#include "copyright.h"
#include "debug.h"
// The following class defines a "list element" -- which is
// used to keep track of one item on a list. It is equivalent to a
// LISP cell, with a "car" ("next") pointing to the next element on the list,
// and a "cdr" ("item") pointing to the item on the list.
//
// This class is private to this module (and classes that inherit
// from this module). Made public for notational convenience.
template <class T>
class ListElement {
public:
ListElement(T itm); // initialize a list element
ListElement *next; // next element on list, NULL if this is last
T item; // item on the list
};
// The following class defines a "list" -- a singly linked list of
// list elements, each of which points to a single item on the list.
// The class has been tested only for primitive types (ints, pointers);
// no guarantees it will work in general. For instance, all types
// to be inserted into a list must have a "==" operator defined.
template <class T> class ListIterator;
template <class T>
class List {
public:
List(); // initialize the list
virtual ~List(); // de-allocate the list
virtual void Prepend(T item);// Put item at the beginning of the list
virtual void Append(T item); // Put item at the end of the list
T Front() { return first->item; }
// Return first item on list
// without removing it
T RemoveFront(); // Take item off the front of the list
void Remove(T item); // Remove specific item from list
bool IsInList(T item) const;// is the item in the list?
unsigned int NumInList() { return numInList;};
// how many items in the list?
bool IsEmpty() { return (numInList == 0); };
// is the list empty?
void Apply(void (*f)(T)) const;
// apply function to all elements in list
virtual void SanityCheck() const;
// has this list been corrupted?
void SelfTest(T *p, int numEntries);
// verify module is working
protected:
ListElement<T> *first; // Head of the list, NULL if list is empty
ListElement<T> *last; // Last element of list
int numInList; // number of elements in list
friend class ListIterator<T>;
};
// The following class defines a "sorted list" -- a singly linked list of
// list elements, arranged so that "Remove" always returns the smallest
// element.
// All types to be inserted onto a sorted list must have a "Compare"
// function defined:
// int Compare(T x, T y)
// returns -1 if x < y
// returns 0 if x == y
// returns 1 if x > y
template <class T>
class SortedList : public List<T> {
public:
SortedList(int (*comp)(T x, T y)) : List<T>() { compare = comp;};
~SortedList() {}; // base class destructor called automatically
void Insert(T item); // insert an item onto the list in sorted order
void SanityCheck() const; // has this list been corrupted?
void SelfTest(T *p, int numEntries);
// verify module is working
private:
int (*compare)(T x, T y); // function for sorting list elements
void Prepend(T item) { Insert(item); } // *pre*pending has no meaning
// in a sorted list
void Append(T item) { Insert(item); } // neither does *ap*pend
};
// The following class can be used to step through a list.
// Example code:
// ListIterator<T> *iter(list);
//
// for (; !iter->IsDone(); iter->Next()) {
// Operation on iter->Item()
// }
template <class T>
class ListIterator {
public:
ListIterator(List<T> *list) { current = list->first; }
// initialize an iterator
bool IsDone() { return current == NULL; };
// return TRUE if we are at the end of the list
T Item() { ASSERT(!IsDone()); return current->item; };
// return current element on list
void Next() { current = current->next; };
// update iterator to point to next
private:
ListElement<T> *current; // where we are in the list
};
#include "list.cc" // templates are really like macros
// so needs to be included in every
// file that uses the template
#endif // LIST_H

571
code/lib/sysdep.cc Normal file
View File

@@ -0,0 +1,571 @@
// sysdep.cc
// Implementation of system-dependent interface. Nachos uses the
// routines defined here, rather than directly calling the UNIX library,
// to simplify porting between versions of UNIX, and even to
// other systems, such as MSDOS.
//
// On UNIX, almost all of these routines are simple wrappers
// for the underlying UNIX system calls.
//
// NOTE: all of these routines refer to operations on the underlying
// host machine (e.g., the DECstation, SPARC, etc.), supporting the
// Nachos simulation code. Nachos implements similar operations,
// (such as opening a file), but those are implemented in terms
// of hardware devices, which are simulated by calls to the underlying
// routines in the host workstation OS.
//
// This file includes lots of calls to C routines. C++ requires
// us to wrap all C definitions with a "extern "C" block".
// This prevents the internal forms of the names from being
// changed by the C++ compiler.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "debug.h"
#include "sysdep.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <cerrno>
#ifdef SOLARIS
// KMS
// for open()
#include <fcntl.h>
#endif
#ifdef LINUX // at this point, linux doesn't support mprotect
#define NO_MPROT
#endif
#ifdef DOS // neither does DOS
#define NO_MPROT
#endif
extern "C" {
#include <signal.h>
#include <sys/types.h>
#ifndef NO_MPROT
#include <sys/mman.h>
#endif
// UNIX routines called by procedures in this file
#if defined CYGWIN
size_t getpagesize(void);
#else
int getpagesize(void);
#endif
unsigned sleep(unsigned);
//#ifdef SOLARIS
//int usleep(useconds_t);
//#else
//void usleep(unsigned int); // rcgood - to avoid spinning processes.
//#endif
#ifndef NO_MPROT
#ifdef OSF
#define OSF_OR_AIX
#endif
#ifdef AIX
#define OSF_OR_AIX
#endif
#ifdef OSF_OR_AIX
int mprotect(const void *, long unsigned int, int);
#else
int mprotect(char *, unsigned int, int);
#endif
#endif
#if defined(BSD) || defined(SOLARIS) || defined(LINUX)
//KMS
// added Solaris and LINUX
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout);
#else
int select(int numBits, void *readFds, void *writeFds, void *exceptFds,
struct timeval *timeout);
#endif
int socket(int, int, int);
#if defined(SUNOS) || defined(ULTRIX)
long tell(int);
int bind (int, const void*, int);
int recvfrom (int, void*, int, int, void*, int *);
int sendto (int, const void*, int, int, void*, int);
#endif
}
//----------------------------------------------------------------------
// CallOnUserAbort
// Arrange that "func" will be called when the user aborts (e.g., by
// hitting ctl-C.
//----------------------------------------------------------------------
void
CallOnUserAbort(void (*func)(int))
{
(void)signal(SIGINT, func);
}
//----------------------------------------------------------------------
// Delay
// Put the UNIX process running Nachos to sleep for x seconds,
// to give the user time to start up another invocation of Nachos
// in a different UNIX shell.
//----------------------------------------------------------------------
void
Delay(int seconds)
{
(void) sleep((unsigned) seconds);
}
//----------------------------------------------------------------------
// UDelay
// Put the UNIX process running Nachos to sleep for x microseconds,
// to prevent an idle Nachos process from spinning...
//----------------------------------------------------------------------
void
UDelay(unsigned int useconds)
{
//#ifdef SOLARIS
// usleep(useconds_t useconds);
//#else
// usleep(useconds);
//#endif /* SOLARIS */
}
//----------------------------------------------------------------------
// Abort
// Quit and drop core.
//----------------------------------------------------------------------
void
Abort()
{
abort();
}
//----------------------------------------------------------------------
// Exit
// Quit without dropping core.
//----------------------------------------------------------------------
void
Exit(int exitCode)
{
exit(exitCode);
}
//----------------------------------------------------------------------
// RandomInit
// Initialize the pseudo-random number generator. We use the
// now obsolete "srand" and "rand" because they are more portable!
//----------------------------------------------------------------------
void
RandomInit(unsigned seed)
{
srand(seed);
}
//----------------------------------------------------------------------
// RandomNumber
// Return a pseudo-random number.
//----------------------------------------------------------------------
unsigned int
RandomNumber()
{
return rand();
}
//----------------------------------------------------------------------
// AllocBoundedArray
// Return an array, with the two pages just before
// and after the array unmapped, to catch illegal references off
// the end of the array. Particularly useful for catching overflow
// beyond fixed-size thread execution stacks.
//
// Note: Just return the useful part!
//
// "size" -- amount of useful space needed (in bytes)
//----------------------------------------------------------------------
char *
AllocBoundedArray(int size)
{
#ifdef NO_MPROT
return new char[size];
#else
int pgSize = getpagesize();
char *ptr = new char[pgSize * 2 + size];
mprotect(ptr, pgSize, 0);
mprotect(ptr + pgSize + size, pgSize, 0);
return ptr + pgSize;
#endif
}
//----------------------------------------------------------------------
// DeallocBoundedArray
// Deallocate an array of integers, unprotecting its two boundary pages.
//
// "ptr" -- the array to be deallocated
// "size" -- amount of useful space in the array (in bytes)
//----------------------------------------------------------------------
#ifdef NO_MPROT
void
DeallocBoundedArray(char *ptr, int /* size */)
{
delete [] ptr;
}
#else
void
DeallocBoundedArray(char *ptr, int size)
{
int pgSize = getpagesize();
mprotect(ptr - pgSize, pgSize, PROT_READ | PROT_WRITE | PROT_EXEC);
mprotect(ptr + size, pgSize, PROT_READ | PROT_WRITE | PROT_EXEC);
delete [] (ptr - pgSize);
}
#endif
//----------------------------------------------------------------------
// PollFile
// Check open file or open socket to see if there are any
// characters that can be read immediately. If so, read them
// in, and return TRUE.
//
// "fd" -- the file descriptor of the file to be polled
//----------------------------------------------------------------------
bool
PollFile(int fd)
{
#if defined(SOLARIS) || defined(LINUX)
// KMS
fd_set rfd,wfd,xfd;
#else
int rfd = (1 << fd), wfd = 0, xfd = 0;
#endif
int retVal;
struct timeval pollTime;
#if defined(SOLARIS) || defined(LINUX)
// KMS
FD_ZERO(&rfd);
FD_ZERO(&wfd);
FD_ZERO(&xfd);
FD_SET(fd,&rfd);
#endif
// don't wait if there are no characters on the file
pollTime.tv_sec = 0;
pollTime.tv_usec = 0;
// poll file or socket
#if defined(BSD)
retVal = select(32, (fd_set*)&rfd, (fd_set*)&wfd, (fd_set*)&xfd, &pollTime);
#elif defined(SOLARIS) || defined(LINUX)
// KMS
retVal = select(32, &rfd, &wfd, &xfd, &pollTime);
#else
retVal = select(32, &rfd, &wfd, &xfd, &pollTime);
#endif
ASSERT((retVal == 0) || (retVal == 1));
if (retVal == 0)
return FALSE; // no char waiting to be read
return TRUE;
}
//----------------------------------------------------------------------
// OpenForWrite
// Open a file for writing. Create it if it doesn't exist; truncate it
// if it does already exist. Return the file descriptor.
//
// "name" -- file name
//----------------------------------------------------------------------
int
OpenForWrite(char *name)
{
int fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0666);
ASSERT(fd >= 0);
return fd;
}
//----------------------------------------------------------------------
// OpenForReadWrite
// Open a file for reading or writing.
// Return the file descriptor, or error if it doesn't exist.
//
// "name" -- file name
//----------------------------------------------------------------------
int
OpenForReadWrite(char *name, bool crashOnError)
{
int fd = open(name, O_RDWR, 0);
ASSERT(!crashOnError || fd >= 0);
return fd;
}
//----------------------------------------------------------------------
// Read
// Read characters from an open file. Abort if read fails.
//----------------------------------------------------------------------
void
Read(int fd, char *buffer, int nBytes)
{
int retVal = read(fd, buffer, nBytes);
ASSERT(retVal == nBytes);
}
//----------------------------------------------------------------------
// ReadPartial
// Read characters from an open file, returning as many as are
// available.
//----------------------------------------------------------------------
int
ReadPartial(int fd, char *buffer, int nBytes)
{
return read(fd, buffer, nBytes);
}
//----------------------------------------------------------------------
// WriteFile
// Write characters to an open file. Abort if write fails.
//----------------------------------------------------------------------
void
WriteFile(int fd, char *buffer, int nBytes)
{
int retVal = write(fd, buffer, nBytes);
ASSERT(retVal == nBytes);
}
//----------------------------------------------------------------------
// Lseek
// Change the location within an open file. Abort on error.
//----------------------------------------------------------------------
void
Lseek(int fd, int offset, int whence)
{
int retVal = lseek(fd, offset, whence);
ASSERT(retVal >= 0);
}
//----------------------------------------------------------------------
// Tell
// Report the current location within an open file.
//----------------------------------------------------------------------
int
Tell(int fd)
{
#if defined(BSD) || defined(SOLARIS) || defined(LINUX)
return lseek(fd,0,SEEK_CUR); // 386BSD doesn't have the tell() system call
// neither do Solaris and Linux -KMS
#else
return tell(fd);
#endif
}
//----------------------------------------------------------------------
// Close
// Close a file. Abort on error.
//----------------------------------------------------------------------
int
Close(int fd)
{
int retVal = close(fd);
ASSERT(retVal >= 0);
return retVal;
}
//----------------------------------------------------------------------
// Unlink
// Delete a file.
//----------------------------------------------------------------------
bool
Unlink(char *name)
{
return unlink(name);
}
//----------------------------------------------------------------------
// OpenSocket
// Open an interprocess communication (IPC) connection. For now,
// just open a datagram port where other Nachos (simulating
// workstations on a network) can send messages to this Nachos.
//----------------------------------------------------------------------
int
OpenSocket()
{
int sockID;
sockID = socket(AF_UNIX, SOCK_DGRAM, 0);
ASSERT(sockID >= 0);
return sockID;
}
//----------------------------------------------------------------------
// CloseSocket
// Close the IPC connection.
//----------------------------------------------------------------------
void
CloseSocket(int sockID)
{
(void) close(sockID);
}
//----------------------------------------------------------------------
// InitSocketName
// Initialize a UNIX socket address -- magical!
//----------------------------------------------------------------------
static void
InitSocketName(struct sockaddr_un *uname, char *name)
{
uname->sun_family = AF_UNIX;
strcpy(uname->sun_path, name);
}
//----------------------------------------------------------------------
// AssignNameToSocket
// Give a UNIX file name to the IPC port, so other instances of Nachos
// can locate the port.
//----------------------------------------------------------------------
void
AssignNameToSocket(char *socketName, int sockID)
{
struct sockaddr_un uName;
int retVal;
(void) unlink(socketName); // in case it's still around from last time
InitSocketName(&uName, socketName);
retVal = bind(sockID, (struct sockaddr *) &uName, sizeof(uName));
ASSERT(retVal >= 0);
DEBUG(dbgNet, "Created socket " << socketName);
}
//----------------------------------------------------------------------
// DeAssignNameToSocket
// Delete the UNIX file name we assigned to our IPC port, on cleanup.
//----------------------------------------------------------------------
void
DeAssignNameToSocket(char *socketName)
{
(void) unlink(socketName);
}
//----------------------------------------------------------------------
// PollSocket
// Return TRUE if there are any messages waiting to arrive on the
// IPC port.
//----------------------------------------------------------------------
bool
PollSocket(int sockID)
{
return PollFile(sockID); // on UNIX, socket ID's are just file ID's
}
//----------------------------------------------------------------------
// ReadFromSocket
// Read a fixed size packet off the IPC port. Abort on error.
//----------------------------------------------------------------------
void
ReadFromSocket(int sockID, char *buffer, int packetSize)
{
int retVal;
struct sockaddr_un uName;
#ifdef LINUX
socklen_t size = sizeof(uName);
#else
int size = sizeof(uName);
#endif
retVal = recvfrom(sockID, buffer, packetSize, 0,
(struct sockaddr *) &uName, &size);
if (retVal != packetSize) {
perror("in recvfrom");
#if defined CYGWIN
cerr << "called with " << packetSize << ", got back " << retVal
<< ", and " << "\n";
#else
cerr << "called with " << packetSize << ", got back " << retVal
<< ", and " << errno << "\n";
#endif
}
ASSERT(retVal == packetSize);
}
//----------------------------------------------------------------------
// modified by KMS to add retry...
// SendToSocket
// Transmit a fixed size packet to another Nachos' IPC port.
// Try 10 times with a one second delay between attempts.
// This is useful, e.g., to give the other socket a chance
// to get set up.
// Terminate if we still fail after 10 tries.
//----------------------------------------------------------------------
void
SendToSocket(int sockID, char *buffer, int packetSize, char *toName)
{
struct sockaddr_un uName;
int retVal;
int retryCount;
InitSocketName(&uName, toName);
for(retryCount=0;retryCount < 10;retryCount++) {
retVal = sendto(sockID, buffer, packetSize, 0,
(struct sockaddr *) &uName, sizeof(uName));
if (retVal == packetSize) return;
// if we did not succeed, we should see a negative
// return value indicating complete failure. If we
// don't, something fishy is going on...
ASSERT(retVal < 0);
// wait a second before trying again
Delay(1);
}
// At this point, we have failed many times
// The most common reason for this is that the target machine
// has halted and its socket no longer exists.
// We simply do nothing (drop the packet).
// This may mask other kinds of failures, but it is the
// right thing to do in the common case.
}

75
code/lib/sysdep.h Normal file
View File

@@ -0,0 +1,75 @@
// sysdep.h
// System-dependent interface. Nachos uses the routines defined
// here, rather than directly calling the UNIX library functions, to
// simplify porting between versions of UNIX, and even to
// other systems, such as MSDOS and the Macintosh.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef SYSDEP_H
#define SYSDEP_H
#include "copyright.h"
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
using namespace std;
// Process control: abort, exit, and sleep
extern void Abort();
extern void Exit(int exitCode);
extern void Delay(int seconds);
extern void UDelay(unsigned int usec);// rcgood - to avoid spinners.
// Initialize system so that cleanUp routine is called when user hits ctl-C
extern void CallOnUserAbort(void (*cleanup)(int));
// Initialize the pseudo random number generator
extern void RandomInit(unsigned seed);
extern unsigned int RandomNumber();
// Allocate, de-allocate an array, such that de-referencing
// just beyond either end of the array will cause an error
extern char *AllocBoundedArray(int size);
extern void DeallocBoundedArray(char *p, int size);
// Check file to see if there are any characters to be read.
// If no characters in the file, return without waiting.
extern bool PollFile(int fd);
// File operations: open/read/write/lseek/close, and check for error
// For simulating the disk and the console devices.
extern int OpenForWrite(char *name);
extern int OpenForReadWrite(char *name, bool crashOnError);
extern void Read(int fd, char *buffer, int nBytes);
extern int ReadPartial(int fd, char *buffer, int nBytes);
extern void WriteFile(int fd, char *buffer, int nBytes);
extern void Lseek(int fd, int offset, int whence);
extern int Tell(int fd);
extern int Close(int fd);
extern bool Unlink(char *name);
// Other C library routines that are used by Nachos.
// These are assumed to be portable, so we don't include a wrapper.
extern "C" {
int atoi(const char *str);
double atof(const char *str);
int abs(int i);
void bcopy(const void *s1, void *s2, size_t n);
void bzero(void *s, size_t n);
}
// Interprocess communication operations, for simulating the network
extern int OpenSocket();
extern void CloseSocket(int sockID);
extern void AssignNameToSocket(char *socketName, int sockID);
extern void DeAssignNameToSocket(char *socketName);
extern bool PollSocket(int sockID);
extern void ReadFromSocket(int sockID, char *buffer, int packetSize);
extern void SendToSocket(int sockID, char *buffer, int packetSize,char *toName);
#endif // SYSDEP_H

38
code/lib/utility.h Normal file
View File

@@ -0,0 +1,38 @@
// utility.h
// Miscellaneous useful definitions.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef UTILITY_H
#define UTILITY_H
#include "copyright.h"
// Miscellaneous useful routines
#define NULL 0
#define TRUE true
#define FALSE false
// #define bool int // necessary on the Mac?
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
// Divide and either round up or down
#define divRoundDown(n,s) ((n) / (s))
#define divRoundUp(n,s) (((n) / (s)) + ((((n) % (s)) > 0) ? 1 : 0))
// This declares the type "VoidFunctionPtr" to be a "pointer to a
// function taking an arbitrary pointer argument and returning nothing". With
// such a function pointer (say it is "func"), we can call it like this:
//
// (*func) ("help!");
//
// This is used by Thread::Fork as well as a couple of other places.
typedef void (*VoidFunctionPtr)(void *arg);
typedef void (*VoidNoArgFunctionPtr)();
#endif // UTILITY_H

44
code/machine/callback.h Normal file
View File

@@ -0,0 +1,44 @@
// callback.h
// Data structure to allow an object to register a "callback".
// On an asynchronous operation, the call to start the operation
// returns immediately. When the operation completes, the called
// object must somehow notify the caller of the completion.
// In the general case, the called object doesn't know the type
// of the caller.
//
// We implement this using virtual functions in C++. An object
// that needs to register a callback is set up as a derived class of
// the abstract base class "CallbackObj". When we pass a
// pointer to the object to a lower level module, that module
// calls back via "obj->CallBack()", without knowing the
// type of the object being called back.
//
// Note that this isn't a general-purpose mechanism,
// because a class can only register a single callback.
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
//
#ifndef CALLBACK_H
#define CALLBACK_H
#include "copyright.h"
// Abstract base class for objects that register callbacks
class CallBackObj {
public:
virtual void CallBack() = 0;
protected:
CallBackObj() {}; // to prevent anyone from creating
// an instance of this class. Only
// allow creation of instances of
// classes derived from this class.
virtual ~CallBackObj() {};
};
#endif

174
code/machine/console.cc Normal file
View File

@@ -0,0 +1,174 @@
// console.cc
// Routines to simulate a serial port to a console device.
// A console has input (a keyboard) and output (a display).
// These are each simulated by operations on UNIX files.
// The simulated device is asynchronous, so we have to invoke
// the interrupt handler (after a simulated delay), to signal that
// a byte has arrived and/or that a written byte has departed.
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "console.h"
#include "main.h"
#include "stdio.h"
//----------------------------------------------------------------------
// ConsoleInput::ConsoleInput
// Initialize the simulation of the input for a hardware console device.
//
// "readFile" -- UNIX file simulating the keyboard (NULL -> use stdin)
// "toCall" is the interrupt handler to call when a character arrives
// from the keyboard
//----------------------------------------------------------------------
ConsoleInput::ConsoleInput(char *readFile, CallBackObj *toCall)
{
if (readFile == NULL)
readFileNo = 0; // keyboard = stdin
else
readFileNo = OpenForReadWrite(readFile, TRUE); // should be read-only
// set up the stuff to emulate asynchronous interrupts
callWhenAvail = toCall;
incoming = EOF;
// start polling for incoming keystrokes
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleReadInt);
}
//----------------------------------------------------------------------
// ConsoleInput::~ConsoleInput
// Clean up console input emulation
//----------------------------------------------------------------------
ConsoleInput::~ConsoleInput()
{
if (readFileNo != 0)
Close(readFileNo);
}
//----------------------------------------------------------------------
// ConsoleInput::CallBack()
// Simulator calls this when a character may be available to be
// read in from the simulated keyboard (eg, the user typed something).
//
// First check to make sure character is available.
// Then invoke the "callBack" registered by whoever wants the character.
//----------------------------------------------------------------------
void
ConsoleInput::CallBack()
{
char c;
int readCount;
ASSERT(incoming == EOF);
if (!PollFile(readFileNo)) { // nothing to be read
// schedule the next time to poll for a packet
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleReadInt);
} else {
// otherwise, try to read a character
readCount = ReadPartial(readFileNo, &c, sizeof(char));
if (readCount == 0) {
// this seems to happen at end of file, when the
// console input is a regular file
// don't schedule an interrupt, since there will never
// be any more input
// just do nothing....
}
else {
// save the character and notify the OS that
// it is available
ASSERT(readCount == sizeof(char));
incoming = c;
kernel->stats->numConsoleCharsRead++;
}
callWhenAvail->CallBack();
}
}
//----------------------------------------------------------------------
// ConsoleInput::GetChar()
// Read a character from the input buffer, if there is any there.
// Either return the character, or EOF if none buffered.
//----------------------------------------------------------------------
char
ConsoleInput::GetChar()
{
char ch = incoming;
if (incoming != EOF) { // schedule when next char will arrive
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleReadInt);
}
incoming = EOF;
return ch;
}
//----------------------------------------------------------------------
// ConsoleOutput::ConsoleOutput
// Initialize the simulation of the output for a hardware console device.
//
// "writeFile" -- UNIX file simulating the display (NULL -> use stdout)
// "toCall" is the interrupt handler to call when a write to
// the display completes.
//----------------------------------------------------------------------
ConsoleOutput::ConsoleOutput(char *writeFile, CallBackObj *toCall)
{
if (writeFile == NULL)
writeFileNo = 1; // display = stdout
else
writeFileNo = OpenForWrite(writeFile);
callWhenDone = toCall;
putBusy = FALSE;
}
//----------------------------------------------------------------------
// ConsoleOutput::~ConsoleOutput
// Clean up console output emulation
//----------------------------------------------------------------------
ConsoleOutput::~ConsoleOutput()
{
if (writeFileNo != 1)
Close(writeFileNo);
}
//----------------------------------------------------------------------
// ConsoleOutput::CallBack()
// Simulator calls this when the next character can be output to the
// display.
//----------------------------------------------------------------------
void
ConsoleOutput::CallBack()
{
putBusy = FALSE;
kernel->stats->numConsoleCharsWritten++;
callWhenDone->CallBack();
}
//----------------------------------------------------------------------
// ConsoleOutput::PutChar()
// Write a character to the simulated display, schedule an interrupt
// to occur in the future, and return.
//----------------------------------------------------------------------
void
ConsoleOutput::PutChar(char ch)
{
ASSERT(putBusy == FALSE);
WriteFile(writeFileNo, &ch, sizeof(char));
putBusy = TRUE;
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
}

90
code/machine/console.h Normal file
View File

@@ -0,0 +1,90 @@
// console.h
// Data structures to simulate the behavior of a terminal
// I/O device. A terminal has two parts -- a keyboard input,
// and a display output, each of which produces/accepts
// characters sequentially.
//
// The console hardware device is asynchronous. When a character is
// written to the device, the routine returns immediately, and an
// interrupt handler is called later when the I/O completes.
// For reads, an interrupt handler is called when a character arrives.
//
// In either case, the serial line connecting the computer
// to the console has limited bandwidth (like a modem!), and so
// each character takes measurable time.
//
// The user of the device registers itself to be called "back" when
// the read/write interrupts occur. There is a separate interrupt
// for read and write, and the device is "duplex" -- a character
// can be outgoing and incoming at the same time.
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef CONSOLE_H
#define CONSOLE_H
#include "copyright.h"
#include "utility.h"
#include "callback.h"
// The following two classes define the input (and output) side of a
// hardware console device. Input (and output) to the device is simulated
// by reading (and writing) to the UNIX file "readFile" (and "writeFile").
//
// Since input (and output) to the device is asynchronous, the interrupt
// handler "callWhenAvail" is called when a character has arrived to be
// read in (and "callWhenDone" is called when an output character has been
// "put" so that the next character can be written).
//
// In practice, usually a single hardware thing that does both
// serial input and serial output. But conceptually simpler to
// use two objects.
class ConsoleInput : public CallBackObj {
public:
ConsoleInput(char *readFile, CallBackObj *toCall);
// initialize hardware console input
~ConsoleInput(); // clean up console emulation
char GetChar(); // Poll the console input. If a char is
// available, return it. Otherwise, return EOF.
// "callWhenAvail" is called whenever there is
// a char to be gotten
void CallBack(); // Invoked when a character arrives
// from the keyboard.
private:
int readFileNo; // UNIX file emulating the keyboard
CallBackObj *callWhenAvail; // Interrupt handler to call when
// there is a char to be read
char incoming; // Contains the character to be read,
// if there is one available.
// Otherwise contains EOF.
};
class ConsoleOutput : public CallBackObj {
public:
ConsoleOutput(char *writeFile, CallBackObj *toCall);
// initialize hardware console output
~ConsoleOutput(); // clean up console emulation
void PutChar(char ch); // Write "ch" to the console display,
// and return immediately. "callWhenDone"
// will called when the I/O completes.
void CallBack(); // Invoked when next character can be put
// out to the display.
private:
int writeFileNo; // UNIX file emulating the display
CallBackObj *callWhenDone; // Interrupt handler to call when
// the next char can be put
bool putBusy; // Is a PutChar operation in progress?
// If so, you can't do another one!
};
#endif // CONSOLE_H

268
code/machine/disk.cc Normal file
View File

@@ -0,0 +1,268 @@
// disk.cc
// Routines to simulate a physical disk device; reading and writing
// to the disk is simulated as reading and writing to a UNIX file.
// See disk.h for details about the behavior of disks (and
// therefore about the behavior of this simulation).
//
// Disk operations are asynchronous, so we have to invoke an interrupt
// handler when the simulated operation completes.
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "disk.h"
#include "debug.h"
#include "sysdep.h"
#include "main.h"
// We put a magic number at the front of the UNIX file representing the
// disk, to make it less likely we will accidentally treat a useful file
// as a disk (which would probably trash the file's contents).
const int MagicNumber = 0x456789ab;
const int MagicSize = sizeof(int);
const int DiskSize = (MagicSize + (NumSectors * SectorSize));
//----------------------------------------------------------------------
// Disk::Disk()
// Initialize a simulated disk. Open the UNIX file (creating it
// if it doesn't exist), and check the magic number to make sure it's
// ok to treat it as Nachos disk storage.
//
// "toCall" -- object to call when disk read/write request completes
//----------------------------------------------------------------------
Disk::Disk(CallBackObj *toCall)
{
int magicNum;
int tmp = 0;
DEBUG(dbgDisk, "Initializing the disk.");
callWhenDone = toCall;
lastSector = 0;
bufferInit = 0;
sprintf(diskname,"DISK_%d",kernel->hostName);
fileno = OpenForReadWrite(diskname, FALSE);
if (fileno >= 0) { // file exists, check magic number
Read(fileno, (char *) &magicNum, MagicSize);
ASSERT(magicNum == MagicNumber);
} else { // file doesn't exist, create it
fileno = OpenForWrite(diskname);
magicNum = MagicNumber;
WriteFile(fileno, (char *) &magicNum, MagicSize); // write magic number
// need to write at end of file, so that reads will not return EOF
Lseek(fileno, DiskSize - sizeof(int), 0);
WriteFile(fileno, (char *)&tmp, sizeof(int));
}
active = FALSE;
}
//----------------------------------------------------------------------
// Disk::~Disk()
// Clean up disk simulation, by closing the UNIX file representing the
// disk.
//----------------------------------------------------------------------
Disk::~Disk()
{
Close(fileno);
}
//----------------------------------------------------------------------
// Disk::PrintSector()
// Dump the data in a disk read/write request, for debugging.
//----------------------------------------------------------------------
static void
PrintSector (bool writing, int sector, char *data)
{
int *p = (int *) data;
if (writing)
cout << "Writing sector: " << sector << "\n";
else
cout << "Reading sector: " << sector << "\n";
for (unsigned int i = 0; i < (SectorSize/sizeof(int)); i++) {
cout << p[i] << " ";
}
cout << "\n";
}
//----------------------------------------------------------------------
// Disk::ReadRequest/WriteRequest
// Simulate a request to read/write a single disk sector
// Do the read/write immediately to the UNIX file
// Set up an interrupt handler to be called later,
// that will notify the caller when the simulator says
// the operation has completed.
//
// Note that a disk only allows an entire sector to be read/written,
// not part of a sector.
//
// "sectorNumber" -- the disk sector to read/write
// "data" -- the bytes to be written, the buffer to hold the incoming bytes
//----------------------------------------------------------------------
void
Disk::ReadRequest(int sectorNumber, char* data)
{
int ticks = ComputeLatency(sectorNumber, FALSE);
ASSERT(!active); // only one request at a time
ASSERT((sectorNumber >= 0) && (sectorNumber < NumSectors));
DEBUG(dbgDisk, "Reading from sector " << sectorNumber);
Lseek(fileno, SectorSize * sectorNumber + MagicSize, 0);
Read(fileno, data, SectorSize);
if (debug->IsEnabled('d'))
PrintSector(FALSE, sectorNumber, data);
active = TRUE;
UpdateLast(sectorNumber);
kernel->stats->numDiskReads++;
kernel->interrupt->Schedule(this, ticks, DiskInt);
}
void
Disk::WriteRequest(int sectorNumber, char* data)
{
int ticks = ComputeLatency(sectorNumber, TRUE);
ASSERT(!active);
ASSERT((sectorNumber >= 0) && (sectorNumber < NumSectors));
DEBUG(dbgDisk, "Writing to sector " << sectorNumber);
Lseek(fileno, SectorSize * sectorNumber + MagicSize, 0);
WriteFile(fileno, data, SectorSize);
if (debug->IsEnabled('d'))
PrintSector(TRUE, sectorNumber, data);
active = TRUE;
UpdateLast(sectorNumber);
kernel->stats->numDiskWrites++;
kernel->interrupt->Schedule(this, ticks, DiskInt);
}
//----------------------------------------------------------------------
// Disk::CallBack()
// Called by the machine simulation when the disk interrupt occurs.
//----------------------------------------------------------------------
void
Disk::CallBack ()
{
active = FALSE;
callWhenDone->CallBack();
}
//----------------------------------------------------------------------
// Disk::TimeToSeek()
// Returns how long it will take to position the disk head over the correct
// track on the disk. Since when we finish seeking, we are likely
// to be in the middle of a sector that is rotating past the head,
// we also return how long until the head is at the next sector boundary.
//
// Disk seeks at one track per SeekTime ticks (cf. stats.h)
// and rotates at one sector per RotationTime ticks
//----------------------------------------------------------------------
int
Disk::TimeToSeek(int newSector, int *rotation)
{
int newTrack = newSector / SectorsPerTrack;
int oldTrack = lastSector / SectorsPerTrack;
int seek = abs(newTrack - oldTrack) * SeekTime;
// how long will seek take?
int over = (kernel->stats->totalTicks + seek) % RotationTime;
// will we be in the middle of a sector when
// we finish the seek?
*rotation = 0;
if (over > 0) // if so, need to round up to next full sector
*rotation = RotationTime - over;
return seek;
}
//----------------------------------------------------------------------
// Disk::ModuloDiff()
// Return number of sectors of rotational delay between target sector
// "to" and current sector position "from"
//----------------------------------------------------------------------
int
Disk::ModuloDiff(int to, int from)
{
int toOffset = to % SectorsPerTrack;
int fromOffset = from % SectorsPerTrack;
return ((toOffset - fromOffset) + SectorsPerTrack) % SectorsPerTrack;
}
//----------------------------------------------------------------------
// Disk::ComputeLatency()
// Return how long will it take to read/write a disk sector, from
// the current position of the disk head.
//
// Latency = seek time + rotational latency + transfer time
// Disk seeks at one track per SeekTime ticks (cf. stats.h)
// and rotates at one sector per RotationTime ticks
//
// To find the rotational latency, we first must figure out where the
// disk head will be after the seek (if any). We then figure out
// how long it will take to rotate completely past newSector after
// that point.
//
// The disk also has a "track buffer"; the disk continuously reads
// the contents of the current disk track into the buffer. This allows
// read requests to the current track to be satisfied more quickly.
// The contents of the track buffer are discarded after every seek to
// a new track.
//----------------------------------------------------------------------
int
Disk::ComputeLatency(int newSector, bool writing)
{
int rotation;
int seek = TimeToSeek(newSector, &rotation);
int timeAfter = kernel->stats->totalTicks + seek + rotation;
#ifndef NOTRACKBUF // turn this on if you don't want the track buffer stuff
// check if track buffer applies
if ((writing == FALSE) && (seek == 0)
&& (((timeAfter - bufferInit) / RotationTime)
> ModuloDiff(newSector, bufferInit / RotationTime))) {
DEBUG(dbgDisk, "Request latency = " << RotationTime);
return RotationTime; // time to transfer sector from the track buffer
}
#endif
rotation += ModuloDiff(newSector, timeAfter / RotationTime) * RotationTime;
DEBUG(dbgDisk, "Request latency = " << (seek + rotation + RotationTime));
return(seek + rotation + RotationTime);
}
//----------------------------------------------------------------------
// Disk::UpdateLast
// Keep track of the most recently requested sector. So we can know
// what is in the track buffer.
//----------------------------------------------------------------------
void
Disk::UpdateLast(int newSector)
{
int rotate;
int seek = TimeToSeek(newSector, &rotate);
if (seek != 0)
bufferInit = kernel->stats->totalTicks + seek + rotate;
lastSector = newSector;
DEBUG(dbgDisk, "Updating last sector = " << lastSector << " , " << bufferInit);
}

92
code/machine/disk.h Normal file
View File

@@ -0,0 +1,92 @@
// disk.h
// Data structures to emulate a physical disk. A physical disk
// can accept (one at a time) requests to read/write a disk sector;
// when the request is satisfied, the CPU gets an interrupt, and
// the next request can be sent to the disk.
//
// Disk contents are preserved across machine crashes, but if
// a file system operation (eg, create a file) is in progress when the
// system shuts down, the file system may be corrupted.
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef DISK_H
#define DISK_H
#include "copyright.h"
#include "utility.h"
#include "callback.h"
// The following class defines a physical disk I/O device. The disk
// has a single surface, split up into "tracks", and each track split
// up into "sectors" (the same number of sectors on each track, and each
// sector has the same number of bytes of storage).
//
// Addressing is by sector number -- each sector on the disk is given
// a unique number: track * SectorsPerTrack + offset within a track.
//
// As with other I/O devices, the raw physical disk is an asynchronous device --
// requests to read or write portions of the disk return immediately,
// and an interrupt is invoked later to signal that the operation completed.
//
// The physical disk is in fact simulated via operations on a UNIX file.
//
// To make life a little more realistic, the simulated time for
// each operation reflects a "track buffer" -- RAM to store the contents
// of the current track as the disk head passes by. The idea is that the
// disk always transfers to the track buffer, in case that data is requested
// later on. This has the benefit of eliminating the need for
// "skip-sector" scheduling -- a read request which comes in shortly after
// the head has passed the beginning of the sector can be satisfied more
// quickly, because its contents are in the track buffer. Most
// disks these days now come with a track buffer.
//
// The track buffer simulation can be disabled by compiling with -DNOTRACKBUF
const int SectorSize = 128; // number of bytes per disk sector
const int SectorsPerTrack = 32; // number of sectors per disk track
const int NumTracks = 32; // number of tracks per disk
const int NumSectors = (SectorsPerTrack * NumTracks);
// total # of sectors per disk
class Disk : public CallBackObj {
public:
Disk(CallBackObj *toCall); // Create a simulated disk.
// Invoke toCall->CallBack()
// when each request completes.
~Disk(); // Deallocate the disk.
void ReadRequest(int sectorNumber, char* data);
// Read/write an single disk sector.
// These routines send a request to
// the disk and return immediately.
// Only one request allowed at a time!
void WriteRequest(int sectorNumber, char* data);
void CallBack(); // Invoked when disk request
// finishes. In turn calls, callWhenDone.
int ComputeLatency(int newSector, bool writing);
// Return how long a request to
// newSector will take:
// (seek + rotational delay + transfer)
private:
int fileno; // UNIX file number for simulated disk
char diskname[32]; // name of simulated disk's file
CallBackObj *callWhenDone; // Invoke when any disk request finishes
bool active; // Is a disk operation in progress?
int lastSector; // The previous disk request
int bufferInit; // When the track buffer started
// being loaded
int TimeToSeek(int newSector, int *rotate); // time to get to the new track
int ModuloDiff(int to, int from); // # sectors between to and from
void UpdateLast(int newSector);
};
#endif // DISK_H

361
code/machine/interrupt.cc Normal file
View File

@@ -0,0 +1,361 @@
// interrupt.cc
// Routines to simulate hardware interrupts.
//
// The hardware provides a routine (SetLevel) to enable or disable
// interrupts.
//
// In order to emulate the hardware, we need to keep track of all
// interrupts the hardware devices would cause, and when they
// are supposed to occur.
//
// This module also keeps track of simulated time. Time advances
// only when the following occur:
// interrupts are re-enabled
// a user instruction is executed
// there is nothing in the ready queue
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "interrupt.h"
#include "main.h"
// String definitions for debugging messages
static char *intLevelNames[] = { "off", "on"};
static char *intTypeNames[] = { "timer", "disk", "console write",
"console read", "network send",
"network recv"};
//----------------------------------------------------------------------
// PendingInterrupt::PendingInterrupt
// Initialize a hardware device interrupt that is to be scheduled
// to occur in the near future.
//
// "callOnInt" is the object to call when the interrupt occurs
// "time" is when (in simulated time) the interrupt is to occur
// "kind" is the hardware device that generated the interrupt
//----------------------------------------------------------------------
PendingInterrupt::PendingInterrupt(CallBackObj *callOnInt,
int time, IntType kind)
{
callOnInterrupt = callOnInt;
when = time;
type = kind;
}
//----------------------------------------------------------------------
// PendingCompare
// Compare to interrupts based on which should occur first.
//----------------------------------------------------------------------
static int
PendingCompare (PendingInterrupt *x, PendingInterrupt *y)
{
if (x->when < y->when) { return -1; }
else if (x->when > y->when) { return 1; }
else { return 0; }
}
//----------------------------------------------------------------------
// Interrupt::Interrupt
// Initialize the simulation of hardware device interrupts.
//
// Interrupts start disabled, with no interrupts pending, etc.
//----------------------------------------------------------------------
Interrupt::Interrupt()
{
level = IntOff;
pending = new SortedList<PendingInterrupt *>(PendingCompare);
inHandler = FALSE;
yieldOnReturn = FALSE;
status = SystemMode;
}
//----------------------------------------------------------------------
// Interrupt::~Interrupt
// De-allocate the data structures needed by the interrupt simulation.
//----------------------------------------------------------------------
Interrupt::~Interrupt()
{
while (!pending->IsEmpty()) {
delete pending->RemoveFront();
}
delete pending;
}
//----------------------------------------------------------------------
// Interrupt::ChangeLevel
// Change interrupts to be enabled or disabled, without advancing
// the simulated time (normally, enabling interrupts advances the time).
//
// Used internally.
//
// "old" -- the old interrupt status
// "now" -- the new interrupt status
//----------------------------------------------------------------------
void
Interrupt::ChangeLevel(IntStatus old, IntStatus now)
{
level = now;
DEBUG(dbgInt, "\tinterrupts: " << intLevelNames[old] << " -> " << intLevelNames[now]);
}
//----------------------------------------------------------------------
// Interrupt::SetLevel
// Change interrupts to be enabled or disabled, and if interrupts
// are being enabled, advance simulated time by calling OneTick().
//
// Returns:
// The old interrupt status.
// Parameters:
// "now" -- the new interrupt status
//----------------------------------------------------------------------
IntStatus
Interrupt::SetLevel(IntStatus now)
{
IntStatus old = level;
// interrupt handlers are prohibited from enabling interrupts
ASSERT((now == IntOff) || (inHandler == FALSE));
ChangeLevel(old, now); // change to new state
if ((now == IntOn) && (old == IntOff)) {
OneTick(); // advance simulated time
}
return old;
}
//----------------------------------------------------------------------
// Interrupt::OneTick
// Advance simulated time and check if there are any pending
// interrupts to be called.
//
// Two things can cause OneTick to be called:
// interrupts are re-enabled
// a user instruction is executed
//----------------------------------------------------------------------
void
Interrupt::OneTick()
{
MachineStatus oldStatus = status;
Statistics *stats = kernel->stats;
// advance simulated time
if (status == SystemMode) {
stats->totalTicks += SystemTick;
stats->systemTicks += SystemTick;
} else {
stats->totalTicks += UserTick;
stats->userTicks += UserTick;
}
DEBUG(dbgInt, "== Tick " << stats->totalTicks << " ==");
// check any pending interrupts are now ready to fire
ChangeLevel(IntOn, IntOff); // first, turn off interrupts
// (interrupt handlers run with
// interrupts disabled)
CheckIfDue(FALSE); // check for pending interrupts
ChangeLevel(IntOff, IntOn); // re-enable interrupts
if (yieldOnReturn) { // if the timer device handler asked
// for a context switch, ok to do it now
yieldOnReturn = FALSE;
status = SystemMode; // yield is a kernel routine
kernel->currentThread->Yield();
status = oldStatus;
}
}
//----------------------------------------------------------------------
// Interrupt::YieldOnReturn
// Called from within an interrupt handler, to cause a context switch
// (for example, on a time slice) in the interrupted thread,
// when the handler returns.
//
// We can't do the context switch here, because that would switch
// out the interrupt handler, and we want to switch out the
// interrupted thread.
//----------------------------------------------------------------------
void
Interrupt::YieldOnReturn()
{
ASSERT(inHandler == TRUE);
yieldOnReturn = TRUE;
}
//----------------------------------------------------------------------
// Interrupt::Idle
// Routine called when there is nothing in the ready queue.
//
// Since something has to be running in order to put a thread
// on the ready queue, the only thing to do is to advance
// simulated time until the next scheduled hardware interrupt.
//
// If there are no pending interrupts, stop. There's nothing
// more for us to do.
//----------------------------------------------------------------------
void
Interrupt::Idle()
{
DEBUG(dbgInt, "Machine idling; checking for interrupts.");
status = IdleMode;
if (CheckIfDue(TRUE)) { // check for any pending interrupts
status = SystemMode;
return; // return in case there's now
// a runnable thread
}
// if there are no pending interrupts, and nothing is on the ready
// queue, it is time to stop. If the console or the network is
// operating, there are *always* pending interrupts, so this code
// is not reached. Instead, the halt must be invoked by the user program.
DEBUG(dbgInt, "Machine idle. No interrupts to do.");
cout << "No threads ready or runnable, and no pending interrupts.\n";
cout << "Assuming the program completed.\n";
Halt();
}
//----------------------------------------------------------------------
// Interrupt::Halt
// Shut down Nachos cleanly, printing out performance statistics.
//----------------------------------------------------------------------
void
Interrupt::Halt()
{
cout << "Machine halting!\n\n";
cout << "This is halt\n";
kernel->stats->Print();
delete kernel; // Never returns.
}
int
Interrupt::CreateFile(char *filename)
{
return kernel->CreateFile(filename);
}
//----------------------------------------------------------------------
// Interrupt::Schedule
// Arrange for the CPU to be interrupted when simulated time
// reaches "now + when".
//
// Implementation: just put it on a sorted list.
//
// NOTE: the Nachos kernel should not call this routine directly.
// Instead, it is only called by the hardware device simulators.
//
// "toCall" is the object to call when the interrupt occurs
// "fromNow" is how far in the future (in simulated time) the
// interrupt is to occur
// "type" is the hardware device that generated the interrupt
//----------------------------------------------------------------------
void
Interrupt::Schedule(CallBackObj *toCall, int fromNow, IntType type)
{
int when = kernel->stats->totalTicks + fromNow;
PendingInterrupt *toOccur = new PendingInterrupt(toCall, when, type);
DEBUG(dbgInt, "Scheduling interrupt handler the " << intTypeNames[type] << " at time = " << when);
ASSERT(fromNow > 0);
pending->Insert(toOccur);
}
//----------------------------------------------------------------------
// Interrupt::CheckIfDue
// Check if any interrupts are scheduled to occur, and if so,
// fire them off.
//
// Returns:
// TRUE, if we fired off any interrupt handlers
// Params:
// "advanceClock" -- if TRUE, there is nothing in the ready queue,
// so we should simply advance the clock to when the next
// pending interrupt would occur (if any).
//----------------------------------------------------------------------
bool
Interrupt::CheckIfDue(bool advanceClock)
{
PendingInterrupt *next;
Statistics *stats = kernel->stats;
ASSERT(level == IntOff); // interrupts need to be disabled,
// to invoke an interrupt handler
if (debug->IsEnabled(dbgInt)) {
DumpState();
}
if (pending->IsEmpty()) { // no pending interrupts
return FALSE;
}
next = pending->Front();
if (next->when > stats->totalTicks) {
if (!advanceClock) { // not time yet
return FALSE;
}
else { // advance the clock to next interrupt
stats->idleTicks += (next->when - stats->totalTicks);
stats->totalTicks = next->when;
// UDelay(1000L); // rcgood - to stop nachos from spinning.
}
}
DEBUG(dbgInt, "Invoking interrupt handler for the ");
DEBUG(dbgInt, intTypeNames[next->type] << " at time " << next->when);
if (kernel->machine != NULL) {
kernel->machine->DelayedLoad(0, 0);
}
inHandler = TRUE;
do {
next = pending->RemoveFront(); // pull interrupt off list
next->callOnInterrupt->CallBack();// call the interrupt handler
delete next;
} while (!pending->IsEmpty()
&& (pending->Front()->when <= stats->totalTicks));
inHandler = FALSE;
return TRUE;
}
//----------------------------------------------------------------------
// PrintPending
// Print information about an interrupt that is scheduled to occur.
// When, where, why, etc.
//----------------------------------------------------------------------
static void
PrintPending (PendingInterrupt *pending)
{
cout << "Interrupt handler "<< intTypeNames[pending->type];
cout << ", scheduled at " << pending->when;
}
//----------------------------------------------------------------------
// DumpState
// Print the complete interrupt state - the status, and all interrupts
// that are scheduled to occur in the future.
//----------------------------------------------------------------------
void
Interrupt::DumpState()
{
cout << "Time: " << kernel->stats->totalTicks;
cout << ", interrupts " << intLevelNames[level] << "\n";
cout << "Pending interrupts:\n";
pending->Apply(PrintPending);
cout << "\nEnd of pending interrupts\n";
}

145
code/machine/interrupt.h Normal file
View File

@@ -0,0 +1,145 @@
// interrupt.h
// Data structures to emulate low-level interrupt hardware.
//
// The hardware provides a routine (SetLevel) to enable or disable
// interrupts.
//
// In order to emulate the hardware, we need to keep track of all
// interrupts the hardware devices would cause, and when they
// are supposed to occur.
//
// This module also keeps track of simulated time. Time advances
// only when the following occur:
// interrupts are re-enabled
// a user instruction is executed
// there is nothing in the ready queue
//
// As a result, unlike real hardware, interrupts (and thus time-slice
// context switches) cannot occur anywhere in the code where interrupts
// are enabled, but rather only at those places in the code where
// simulated time advances (so that it becomes time to invoke an
// interrupt in the hardware simulation).
//
// NOTE: this means that incorrectly synchronized code may work
// fine on this hardware simulation (even with randomized time slices),
// but it wouldn't work on real hardware.
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef INTERRUPT_H
#define INTERRUPT_H
#include "copyright.h"
#include "list.h"
#include "callback.h"
// Interrupts can be disabled (IntOff) or enabled (IntOn)
enum IntStatus { IntOff, IntOn };
// Nachos can be running kernel code (SystemMode), user code (UserMode),
// or there can be no runnable thread, because the ready list
// is empty (IdleMode).
enum MachineStatus {IdleMode, SystemMode, UserMode};
// IntType records which hardware device generated an interrupt.
// In Nachos, we support a hardware timer device, a disk, a console
// display and keyboard, and a network.
enum IntType { TimerInt, DiskInt, ConsoleWriteInt, ConsoleReadInt,
NetworkSendInt, NetworkRecvInt};
// The following class defines an interrupt that is scheduled
// to occur in the future. The internal data structures are
// left public to make it simpler to manipulate.
class PendingInterrupt {
public:
PendingInterrupt(CallBackObj *callOnInt, int time, IntType kind);
// initialize an interrupt that will
// occur in the future
CallBackObj *callOnInterrupt;// The object (in the hardware device
// emulator) to call when the interrupt occurs
int when; // When the interrupt is supposed to fire
IntType type; // for debugging
};
// The following class defines the data structures for the simulation
// of hardware interrupts. We record whether interrupts are enabled
// or disabled, and any hardware interrupts that are scheduled to occur
// in the future.
class Interrupt {
public:
Interrupt(); // initialize the interrupt simulation
~Interrupt(); // de-allocate data structures
IntStatus SetLevel(IntStatus level);
// Disable or enable interrupts
// and return previous setting.
void Enable() { (void) SetLevel(IntOn); }
// Enable interrupts.
IntStatus getLevel() {return level;}
// Return whether interrupts
// are enabled or disabled
void Idle(); // The ready queue is empty, roll
// simulated time forward until the
// next interrupt
void Halt(); // quit and print out stats
void PrintInt(int number);
int CreateFile(char *filename);
void YieldOnReturn(); // cause a context switch on return
// from an interrupt handler
MachineStatus getStatus() { return status; }
void setStatus(MachineStatus st) { status = st; }
// idle, kernel, user
void DumpState(); // Print interrupt state
// NOTE: the following are internal to the hardware simulation code.
// DO NOT call these directly. I should make them "private",
// but they need to be public since they are called by the
// hardware device simulators.
void Schedule(CallBackObj *callTo, int when, IntType type);
// Schedule an interrupt to occur
// at time "when". This is called
// by the hardware device simulators.
void OneTick(); // Advance simulated time
private:
IntStatus level; // are interrupts enabled or disabled?
SortedList<PendingInterrupt *> *pending;
// the list of interrupts scheduled
// to occur in the future
//int writeFileNo; //UNIX file emulating the display
bool inHandler; // TRUE if we are running an interrupt handler
//bool putBusy; // Is a PrintInt operation in progress
//If so, you cannoot do another one
bool yieldOnReturn; // TRUE if we are to context switch
// on return from the interrupt handler
MachineStatus status; // idle, kernel mode, user mode
// these functions are internal to the interrupt simulation code
bool CheckIfDue(bool advanceClock);
// Check if any interrupts are supposed
// to occur now, and if so, do them
void ChangeLevel(IntStatus old, // SetLevel, without advancing the
IntStatus now); // simulated time
};
#endif // INTERRRUPT_H

224
code/machine/machine.cc Normal file
View File

@@ -0,0 +1,224 @@
// machine.cc
// Routines for simulating the execution of user programs.
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "machine.h"
#include "main.h"
// Textual names of the exceptions that can be generated by user program
// execution, for debugging.
static char* exceptionNames[] = { "no exception", "syscall",
"page fault/no TLB entry", "page read only",
"bus error", "address error", "overflow",
"illegal instruction" };
//----------------------------------------------------------------------
// CheckEndian
// Check to be sure that the host really uses the format it says it
// does, for storing the bytes of an integer. Stop on error.
//----------------------------------------------------------------------
static
void CheckEndian()
{
union checkit {
char charword[4];
unsigned int intword;
} check;
check.charword[0] = 1;
check.charword[1] = 2;
check.charword[2] = 3;
check.charword[3] = 4;
#ifdef HOST_IS_BIG_ENDIAN
ASSERT (check.intword == 0x01020304);
#else
ASSERT (check.intword == 0x04030201);
#endif
}
//----------------------------------------------------------------------
// Machine::Machine
// Initialize the simulation of user program execution.
//
// "debug" -- if TRUE, drop into the debugger after each user instruction
// is executed.
//----------------------------------------------------------------------
Machine::Machine(bool debug)
{
int i;
for (i = 0; i < NumTotalRegs; i++)
registers[i] = 0;
mainMemory = new char[MemorySize];
for (i = 0; i < MemorySize; i++)
mainMemory[i] = 0;
#ifdef USE_TLB
tlb = new TranslationEntry[TLBSize];
for (i = 0; i < TLBSize; i++)
tlb[i].valid = FALSE;
pageTable = NULL;
#else // use linear page table
tlb = NULL;
pageTable = NULL;
#endif
singleStep = debug;
CheckEndian();
}
//----------------------------------------------------------------------
// Machine::~Machine
// De-allocate the data structures used to simulate user program execution.
//----------------------------------------------------------------------
Machine::~Machine()
{
delete [] mainMemory;
if (tlb != NULL)
delete [] tlb;
}
//----------------------------------------------------------------------
// Machine::RaiseException
// Transfer control to the Nachos kernel from user mode, because
// the user program either invoked a system call, or some exception
// occured (such as the address translation failed).
//
// "which" -- the cause of the kernel trap
// "badVaddr" -- the virtual address causing the trap, if appropriate
//----------------------------------------------------------------------
void
Machine::RaiseException(ExceptionType which, int badVAddr)
{
DEBUG(dbgMach, "Exception: " << exceptionNames[which]);
registers[BadVAddrReg] = badVAddr;
DelayedLoad(0, 0); // finish anything in progress
kernel->interrupt->setStatus(SystemMode);
ExceptionHandler(which); // interrupts are enabled at this point
kernel->interrupt->setStatus(UserMode);
}
//----------------------------------------------------------------------
// Machine::Debugger
// Primitive debugger for user programs. Note that we can't use
// gdb to debug user programs, since gdb doesn't run on top of Nachos.
// It could, but you'd have to implement *a lot* more system calls
// to get it to work!
//
// So just allow single-stepping, and printing the contents of memory.
//----------------------------------------------------------------------
void Machine::Debugger()
{
char *buf = new char[80];
int num;
bool done = FALSE;
kernel->interrupt->DumpState();
DumpState();
while (!done) {
// read commands until we should proceed with more execution
// prompt for input, giving current simulation time in the prompt
cout << kernel->stats->totalTicks << ">";
// read one line of input (80 chars max)
cin.get(buf, 80);
if (sscanf(buf, "%d", &num) == 1) {
runUntilTime = num;
done = TRUE;
}
else {
runUntilTime = 0;
switch (*buf) {
case '\0':
done = TRUE;
break;
case 'c':
singleStep = FALSE;
done = TRUE;
break;
case '?':
cout << "Machine commands:\n";
cout << " <return> execute one instruction\n";
cout << " <number> run until the given timer tick\n";
cout << " c run until completion\n";
cout << " ? print help message\n";
break;
default:
cout << "Unknown command: " << buf << "\n";
cout << "Type ? for help.\n";
}
}
// consume the newline delimiter, which does not get
// eaten by cin.get(buf,80) above.
buf[0] = cin.get();
}
delete [] buf;
}
//----------------------------------------------------------------------
// Machine::DumpState
// Print the user program's CPU state. We might print the contents
// of memory, but that seemed like overkill.
//----------------------------------------------------------------------
void
Machine::DumpState()
{
int i;
cout << "Machine registers:\n";
for (i = 0; i < NumGPRegs; i++) {
switch (i) {
case StackReg:
cout << "\tSP(" << i << "):\t" << registers[i];
break;
case RetAddrReg:
cout << "\tRA(" << i << "):\t" << registers[i];
break;
default:
cout << "\t" << i << ":\t" << registers[i];
break;
}
if ((i % 4) == 3) { cout << "\n"; }
}
cout << "\tHi:\t" << registers[HiReg];
cout << "\tLo:\t" << registers[LoReg];
cout << "\tPC:\t" << registers[PCReg];
cout << "\tNextPC:\t" << registers[NextPCReg];
cout << "\tPrevPC:\t" << registers[PrevPCReg];
cout << "\tLoad:\t" << registers[LoadReg];
cout << "\tLoadV:\t" << registers[LoadValueReg] << "\n";
}
//----------------------------------------------------------------------
// Machine::ReadRegister/WriteRegister
// Fetch or write the contents of a user program register.
//----------------------------------------------------------------------
int
Machine::ReadRegister(int num)
{
ASSERT((num >= 0) && (num < NumTotalRegs));
return registers[num];
}
void
Machine::WriteRegister(int num, int value)
{
ASSERT((num >= 0) && (num < NumTotalRegs));
registers[num] = value;
}

206
code/machine/machine.h Normal file
View File

@@ -0,0 +1,206 @@
// machine.h
// Data structures for simulating the execution of user programs
// running on top of Nachos.
//
// User programs are loaded into "mainMemory"; to Nachos,
// this looks just like an array of bytes. Of course, the Nachos
// kernel is in memory too -- but as in most machines these days,
// the kernel is loaded into a separate memory region from user
// programs, and accesses to kernel memory are not translated or paged.
//
// In Nachos, user programs are executed one instruction at a time,
// by the simulator. Each memory reference is translated, checked
// for errors, etc.
//
// DO NOT CHANGE EXCEPT AS NOTED BELOW -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef MACHINE_H
#define MACHINE_H
#include "copyright.h"
#include "utility.h"
#include "translate.h"
// Definitions related to the size, and format of user memory
const int PageSize = 128; // set the page size equal to
// the disk sector size, for simplicity
//
// You are allowed to change this value.
// Doing so will change the number of pages of physical memory
// available on the simulated machine.
//
const int NumPhysPages = 128;
const int MemorySize = (NumPhysPages * PageSize);
const int TLBSize = 4; // if there is a TLB, make it small
enum ExceptionType { NoException, // Everything ok!
SyscallException, // A program executed a system call.
PageFaultException, // No valid translation found
ReadOnlyException, // Write attempted to page marked
// "read-only"
BusErrorException, // Translation resulted in an
// invalid physical address
AddressErrorException, // Unaligned reference or one that
// was beyond the end of the
// address space
OverflowException, // Integer overflow in add or sub.
IllegalInstrException, // Unimplemented or reserved instr.
NumExceptionTypes
};
// User program CPU state. The full set of MIPS registers, plus a few
// more because we need to be able to start/stop a user program between
// any two instructions (thus we need to keep track of things like load
// delay slots, etc.)
#define StackReg 29 // User's stack pointer
#define RetAddrReg 31 // Holds return address for procedure calls
#define NumGPRegs 32 // 32 general purpose registers on MIPS
#define HiReg 32 // Double register to hold multiply result
#define LoReg 33
#define PCReg 34 // Current program counter
#define NextPCReg 35 // Next program counter (for branch delay)
#define PrevPCReg 36 // Previous program counter (for debugging)
#define LoadReg 37 // The register target of a delayed load.
#define LoadValueReg 38 // The value to be loaded by a delayed load.
#define BadVAddrReg 39 // The failing virtual address on an exception
#define NumTotalRegs 40
// The following class defines the simulated host workstation hardware, as
// seen by user programs -- the CPU registers, main memory, etc.
// User programs shouldn't be able to tell that they are running on our
// simulator or on the real hardware, except
// we don't support floating point instructions
// the system call interface to Nachos is not the same as UNIX
// (10 system calls in Nachos vs. 200 in UNIX!)
// If we were to implement more of the UNIX system calls, we ought to be
// able to run Nachos on top of Nachos!
//
// The procedures in this class are defined in machine.cc, mipssim.cc, and
// translate.cc.
class Instruction;
class Interrupt;
class Machine {
public:
Machine(bool debug); // Initialize the simulation of the hardware
// for running user programs
~Machine(); // De-allocate the data structures
// Routines callable by the Nachos kernel
void Run(); // Run a user program
int ReadRegister(int num); // read the contents of a CPU register
void WriteRegister(int num, int value);
// store a value into a CPU register
// Data structures accessible to the Nachos kernel -- main memory and the
// page table/TLB.
//
// Note that *all* communication between the user program and the kernel
// are in terms of these data structures (plus the CPU registers).
char *mainMemory; // physical memory to store user program,
// code and data, while executing
// NOTE: the hardware translation of virtual addresses in the user program
// to physical addresses (relative to the beginning of "mainMemory")
// can be controlled by one of:
// a traditional linear page table
// a software-loaded translation lookaside buffer (tlb) -- a cache of
// mappings of virtual page #'s to physical page #'s
//
// If "tlb" is NULL, the linear page table is used
// If "tlb" is non-NULL, the Nachos kernel is responsible for managing
// the contents of the TLB. But the kernel can use any data structure
// it wants (eg, segmented paging) for handling TLB cache misses.
//
// For simplicity, both the page table pointer and the TLB pointer are
// public. However, while there can be multiple page tables (one per address
// space, stored in memory), there is only one TLB (implemented in hardware).
// Thus the TLB pointer should be considered as *read-only*, although
// the contents of the TLB are free to be modified by the kernel software.
TranslationEntry *tlb; // this pointer should be considered
// "read-only" to Nachos kernel code
TranslationEntry *pageTable;
unsigned int pageTableSize;
bool ReadMem(int addr, int size, int* value);
bool WriteMem(int addr, int size, int value);
// Read or write 1, 2, or 4 bytes of virtual
// memory (at addr). Return FALSE if a
// correct translation couldn't be found.
private:
// Routines internal to the machine simulation -- DO NOT call these directly
void DelayedLoad(int nextReg, int nextVal);
// Do a pending delayed load (modifying a reg)
void OneInstruction(Instruction *instr);
// Run one instruction of a user program.
ExceptionType Translate(int virtAddr, int* physAddr, int size,bool writing);
// Translate an address, and check for
// alignment. Set the use and dirty bits in
// the translation entry appropriately,
// and return an exception code if the
// translation couldn't be completed.
void RaiseException(ExceptionType which, int badVAddr);
// Trap to the Nachos kernel, because of a
// system call or other exception.
void Debugger(); // invoke the user program debugger
void DumpState(); // print the user CPU and memory state
// Internal data structures
int registers[NumTotalRegs]; // CPU registers, for executing user programs
bool singleStep; // drop back into the debugger after each
// simulated instruction
int runUntilTime; // drop back into the debugger when simulated
// time reaches this value
friend class Interrupt; // calls DelayedLoad()
};
extern void ExceptionHandler(ExceptionType which);
// Entry point into Nachos for handling
// user system calls and exceptions
// Defined in exception.cc
// Routines for converting Words and Short Words to and from the
// simulated machine's format of little endian. If the host machine
// is little endian (DEC and Intel), these end up being NOPs.
//
// What is stored in each format:
// host byte ordering:
// kernel data structures
// user registers
// simulated machine byte ordering:
// contents of main memory
unsigned int WordToHost(unsigned int word);
unsigned short ShortToHost(unsigned short shortword);
unsigned int WordToMachine(unsigned int word);
unsigned short ShortToMachine(unsigned short shortword);
#endif // MACHINE_H

828
code/machine/mipssim.cc Normal file
View File

@@ -0,0 +1,828 @@
// mipssim.cc -- simulate a MIPS R2/3000 processor
//
// This code has been adapted from Ousterhout's MIPSSIM package.
// Byte ordering is little-endian, so we can be compatible with
// DEC RISC systems.
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
// Simulation fixes done by Peter E Reissner, class of Winter 1994/95 (York)
// I've not been able to test this extensively.
// Ported to newer version of Nachos at Waterloo by Scott Graham (Mar 99).
#include "copyright.h"
#include "debug.h"
#include "machine.h"
#include "mipssim.h"
#include "main.h"
static void Mult(int a, int b, bool signedArith, int* hiPtr, int* loPtr);
// The following class defines an instruction, represented in both
// undecoded binary form
// decoded to identify
// operation to do
// registers to act on
// any immediate operand value
class Instruction {
public:
void Decode(); // decode the binary representation of the instruction
unsigned int value; // binary representation of the instruction
char opCode; // Type of instruction. This is NOT the same as the
// opcode field from the instruction: see defs in mips.h
char rs, rt, rd; // Three registers from instruction.
int extra; // Immediate or target or shamt field or offset.
// Immediates are sign-extended.
};
//----------------------------------------------------------------------
// Machine::Run
// Simulate the execution of a user-level program on Nachos.
// Called by the kernel when the program starts up; never returns.
//
// This routine is re-entrant, in that it can be called multiple
// times concurrently -- one for each thread executing user code.
//----------------------------------------------------------------------
void
Machine::Run()
{
Instruction *instr = new Instruction; // storage for decoded instruction
if (debug->IsEnabled('m')) {
cout << "Starting program in thread: " << kernel->currentThread->getName();
cout << ", at time: " << kernel->stats->totalTicks << "\n";
}
kernel->interrupt->setStatus(UserMode);
for (;;) {
OneInstruction(instr);
kernel->interrupt->OneTick();
if (singleStep && (runUntilTime <= kernel->stats->totalTicks))
Debugger();
}
}
//----------------------------------------------------------------------
// TypeToReg
// Retrieve the register # referred to in an instruction.
//----------------------------------------------------------------------
static int
TypeToReg(RegType reg, Instruction *instr)
{
switch (reg) {
case RS:
return instr->rs;
case RT:
return instr->rt;
case RD:
return instr->rd;
case EXTRA:
return instr->extra;
default:
return -1;
}
}
//----------------------------------------------------------------------
// Machine::OneInstruction
// Execute one instruction from a user-level program
//
// If there is any kind of exception or interrupt, we invoke the
// exception handler, and when it returns, we return to Run(), which
// will re-invoke us in a loop. This allows us to
// re-start the instruction execution from the beginning, in
// case any of our state has changed. On a syscall,
// the OS software must increment the PC so execution begins
// at the instruction immediately after the syscall.
//
// This routine is re-entrant, in that it can be called multiple
// times concurrently -- one for each thread executing user code.
// We get re-entrancy by never caching any data -- we always re-start the
// simulation from scratch each time we are called (or after trapping
// back to the Nachos kernel on an exception or interrupt), and we always
// store all data back to the machine registers and memory before
// leaving. This allows the Nachos kernel to control our behavior
// by controlling the contents of memory, the translation table,
// and the register set.
//----------------------------------------------------------------------
void
Machine::OneInstruction(Instruction *instr)
{
#ifdef SIM_FIX
int byte; // described in Kane for LWL,LWR,...
#endif
int raw;
int nextLoadReg = 0;
int nextLoadValue = 0; // record delayed load operation, to apply
// in the future
// Fetch instruction
if (!ReadMem(registers[PCReg], 4, &raw))
return; // exception occurred
instr->value = raw;
instr->Decode();
if (debug->IsEnabled('m')) {
struct OpString *str = &opStrings[instr->opCode];
char buf[80];
ASSERT(instr->opCode <= MaxOpcode);
cout << "At PC = " << registers[PCReg];
sprintf(buf, str->format, TypeToReg(str->args[0], instr),
TypeToReg(str->args[1], instr), TypeToReg(str->args[2], instr));
cout << "\t" << buf << "\n";
}
// Compute next pc, but don't install in case there's an error or branch.
int pcAfter = registers[NextPCReg] + 4;
int sum, diff, tmp, value;
unsigned int rs, rt, imm;
// Execute the instruction (cf. Kane's book)
switch (instr->opCode) {
case OP_ADD:
sum = registers[instr->rs] + registers[instr->rt];
if (!((registers[instr->rs] ^ registers[instr->rt]) & SIGN_BIT) &&
((registers[instr->rs] ^ sum) & SIGN_BIT)) {
RaiseException(OverflowException, 0);
return;
}
registers[instr->rd] = sum;
break;
case OP_ADDI:
sum = registers[instr->rs] + instr->extra;
if (!((registers[instr->rs] ^ instr->extra) & SIGN_BIT) &&
((instr->extra ^ sum) & SIGN_BIT)) {
RaiseException(OverflowException, 0);
return;
}
registers[instr->rt] = sum;
break;
case OP_ADDIU:
registers[instr->rt] = registers[instr->rs] + instr->extra;
break;
case OP_ADDU:
registers[instr->rd] = registers[instr->rs] + registers[instr->rt];
break;
case OP_AND:
registers[instr->rd] = registers[instr->rs] & registers[instr->rt];
break;
case OP_ANDI:
registers[instr->rt] = registers[instr->rs] & (instr->extra & 0xffff);
break;
case OP_BEQ:
if (registers[instr->rs] == registers[instr->rt])
pcAfter = registers[NextPCReg] + IndexToAddr(instr->extra);
break;
case OP_BGEZAL:
registers[R31] = registers[NextPCReg] + 4;
case OP_BGEZ:
if (!(registers[instr->rs] & SIGN_BIT))
pcAfter = registers[NextPCReg] + IndexToAddr(instr->extra);
break;
case OP_BGTZ:
if (registers[instr->rs] > 0)
pcAfter = registers[NextPCReg] + IndexToAddr(instr->extra);
break;
case OP_BLEZ:
if (registers[instr->rs] <= 0)
pcAfter = registers[NextPCReg] + IndexToAddr(instr->extra);
break;
case OP_BLTZAL:
registers[R31] = registers[NextPCReg] + 4;
case OP_BLTZ:
if (registers[instr->rs] & SIGN_BIT)
pcAfter = registers[NextPCReg] + IndexToAddr(instr->extra);
break;
case OP_BNE:
if (registers[instr->rs] != registers[instr->rt])
pcAfter = registers[NextPCReg] + IndexToAddr(instr->extra);
break;
case OP_DIV:
if (registers[instr->rt] == 0) {
registers[LoReg] = 0;
registers[HiReg] = 0;
} else {
registers[LoReg] = registers[instr->rs] / registers[instr->rt];
registers[HiReg] = registers[instr->rs] % registers[instr->rt];
}
break;
case OP_DIVU:
rs = (unsigned int) registers[instr->rs];
rt = (unsigned int) registers[instr->rt];
if (rt == 0) {
registers[LoReg] = 0;
registers[HiReg] = 0;
} else {
tmp = rs / rt;
registers[LoReg] = (int) tmp;
tmp = rs % rt;
registers[HiReg] = (int) tmp;
}
break;
case OP_JAL:
registers[R31] = registers[NextPCReg] + 4;
case OP_J:
pcAfter = (pcAfter & 0xf0000000) | IndexToAddr(instr->extra);
break;
case OP_JALR:
registers[instr->rd] = registers[NextPCReg] + 4;
case OP_JR:
pcAfter = registers[instr->rs];
break;
case OP_LB:
case OP_LBU:
tmp = registers[instr->rs] + instr->extra;
if (!ReadMem(tmp, 1, &value))
return;
if ((value & 0x80) && (instr->opCode == OP_LB))
value |= 0xffffff00;
else
value &= 0xff;
nextLoadReg = instr->rt;
nextLoadValue = value;
break;
case OP_LH:
case OP_LHU:
tmp = registers[instr->rs] + instr->extra;
if (tmp & 0x1) {
RaiseException(AddressErrorException, tmp);
return;
}
if (!ReadMem(tmp, 2, &value))
return;
if ((value & 0x8000) && (instr->opCode == OP_LH))
value |= 0xffff0000;
else
value &= 0xffff;
nextLoadReg = instr->rt;
nextLoadValue = value;
break;
case OP_LUI:
DEBUG(dbgMach, "Executing: LUI r" << instr->rt << ", " << instr->extra);
registers[instr->rt] = instr->extra << 16;
break;
case OP_LW:
tmp = registers[instr->rs] + instr->extra;
if (tmp & 0x3) {
RaiseException(AddressErrorException, tmp);
return;
}
if (!ReadMem(tmp, 4, &value))
return;
nextLoadReg = instr->rt;
nextLoadValue = value;
break;
case OP_LWL:
tmp = registers[instr->rs] + instr->extra;
#ifdef SIM_FIX
// The only difference between this code and the BIG ENDIAN code
// is that the ReadMem call is guaranteed an aligned access as it
// should be (Kane's book hides the fact that all memory access
// are done using aligned loads - what the instruction asks for
// is a arbitrary) This is the whole purpose of LWL and LWR etc.
// Then the switch uses 3 - (tmp & 0x3) instead of (tmp & 0x3)
byte = tmp & 0x3;
// DEBUG('P', "Addr 0x%X\n",tmp-byte);
if (!ReadMem(tmp-byte, 4, &value))
return;
#else
// ReadMem assumes all 4 byte requests are aligned on an even
// word boundary. Also, the little endian/big endian swap code would
// fail (I think) if the other cases are ever exercised.
ASSERT((tmp & 0x3) == 0);
if (!ReadMem(tmp, 4, &value))
return;
#endif
if (registers[LoadReg] == instr->rt)
nextLoadValue = registers[LoadValueReg];
else
nextLoadValue = registers[instr->rt];
#ifdef SIM_FIX
switch (3 - byte)
#else
switch (tmp & 0x3)
#endif
{
case 0:
nextLoadValue = value;
break;
case 1:
nextLoadValue = (nextLoadValue & 0xff) | (value << 8);
break;
case 2:
nextLoadValue = (nextLoadValue & 0xffff) | (value << 16);
break;
case 3:
nextLoadValue = (nextLoadValue & 0xffffff) | (value << 24);
break;
}
nextLoadReg = instr->rt;
break;
case OP_LWR:
tmp = registers[instr->rs] + instr->extra;
#ifdef SIM_FIX
// The only difference between this code and the BIG ENDIAN code
// is that the ReadMem call is guaranteed an aligned access as it
// should be (Kane's book hides the fact that all memory access
// are done using aligned loads - what the instruction asks
// for is a arbitrary) This is the whole purpose of LWL and LWR etc.
// Then the switch uses 3 - (tmp & 0x3) instead of (tmp & 0x3)
byte = tmp & 0x3;
// DEBUG('P', "Addr 0x%X\n",tmp-byte);
if (!ReadMem(tmp-byte, 4, &value))
return;
#else
// ReadMem assumes all 4 byte requests are aligned on an even
// word boundary. Also, the little endian/big endian swap code would
// fail (I think) if the other cases are ever exercised.
ASSERT((tmp & 0x3) == 0);
if (!ReadMem(tmp, 4, &value))
return;
#endif
if (registers[LoadReg] == instr->rt)
nextLoadValue = registers[LoadValueReg];
else
nextLoadValue = registers[instr->rt];
#ifdef SIM_FIX
switch (3 - byte)
#else
switch (tmp & 0x3)
#endif
{
case 0:
nextLoadValue = (nextLoadValue & 0xffffff00) |
((value >> 24) & 0xff);
break;
case 1:
nextLoadValue = (nextLoadValue & 0xffff0000) |
((value >> 16) & 0xffff);
break;
case 2:
nextLoadValue = (nextLoadValue & 0xff000000)
| ((value >> 8) & 0xffffff);
break;
case 3:
nextLoadValue = value;
break;
}
nextLoadReg = instr->rt;
break;
case OP_MFHI:
registers[instr->rd] = registers[HiReg];
break;
case OP_MFLO:
registers[instr->rd] = registers[LoReg];
break;
case OP_MTHI:
registers[HiReg] = registers[instr->rs];
break;
case OP_MTLO:
registers[LoReg] = registers[instr->rs];
break;
case OP_MULT:
Mult(registers[instr->rs], registers[instr->rt], TRUE,
&registers[HiReg], &registers[LoReg]);
break;
case OP_MULTU:
Mult(registers[instr->rs], registers[instr->rt], FALSE,
&registers[HiReg], &registers[LoReg]);
break;
case OP_NOR:
registers[instr->rd] = ~(registers[instr->rs] | registers[instr->rt]);
break;
case OP_OR:
registers[instr->rd] = registers[instr->rs] | registers[instr->rt];
break;
case OP_ORI:
registers[instr->rt] = registers[instr->rs] | (instr->extra & 0xffff);
break;
case OP_SB:
if (!WriteMem((unsigned)
(registers[instr->rs] + instr->extra), 1, registers[instr->rt]))
return;
break;
case OP_SH:
if (!WriteMem((unsigned)
(registers[instr->rs] + instr->extra), 2, registers[instr->rt]))
return;
break;
case OP_SLL:
registers[instr->rd] = registers[instr->rt] << instr->extra;
break;
case OP_SLLV:
registers[instr->rd] = registers[instr->rt] <<
(registers[instr->rs] & 0x1f);
break;
case OP_SLT:
if (registers[instr->rs] < registers[instr->rt])
registers[instr->rd] = 1;
else
registers[instr->rd] = 0;
break;
case OP_SLTI:
if (registers[instr->rs] < instr->extra)
registers[instr->rt] = 1;
else
registers[instr->rt] = 0;
break;
case OP_SLTIU:
rs = registers[instr->rs];
imm = instr->extra;
if (rs < imm)
registers[instr->rt] = 1;
else
registers[instr->rt] = 0;
break;
case OP_SLTU:
rs = registers[instr->rs];
rt = registers[instr->rt];
if (rs < rt)
registers[instr->rd] = 1;
else
registers[instr->rd] = 0;
break;
case OP_SRA:
registers[instr->rd] = registers[instr->rt] >> instr->extra;
break;
case OP_SRAV:
registers[instr->rd] = registers[instr->rt] >>
(registers[instr->rs] & 0x1f);
break;
case OP_SRL:
tmp = registers[instr->rt];
tmp >>= instr->extra;
registers[instr->rd] = tmp;
break;
case OP_SRLV:
tmp = registers[instr->rt];
tmp >>= (registers[instr->rs] & 0x1f);
registers[instr->rd] = tmp;
break;
case OP_SUB:
diff = registers[instr->rs] - registers[instr->rt];
if (((registers[instr->rs] ^ registers[instr->rt]) & SIGN_BIT) &&
((registers[instr->rs] ^ diff) & SIGN_BIT)) {
RaiseException(OverflowException, 0);
return;
}
registers[instr->rd] = diff;
break;
case OP_SUBU:
registers[instr->rd] = registers[instr->rs] - registers[instr->rt];
break;
case OP_SW:
if (!WriteMem((unsigned)
(registers[instr->rs] + instr->extra), 4, registers[instr->rt]))
return;
break;
case OP_SWL:
tmp = registers[instr->rs] + instr->extra;
#ifdef SIM_FIX
// The only difference between this code and the BIG ENDIAN code
// is that the ReadMem call is guaranteed an aligned access as it
// should be (Kane's book hides the fact that all memory access
// are done using aligned loads - what the instruction asks for
// is a arbitrary) This is the whole purpose of LWL and LWR etc.
byte = tmp & 0x3;
// DEBUG('P', "Addr 0x%X\n",tmp-byte);
if (!ReadMem(tmp-byte, 4, &value))
return;
// DEBUG('P', "Value 0x%X\n",value);
#else
// The little endian/big endian swap code would
// fail (I think) if the other cases are ever exercised.
ASSERT((tmp & 0x3) == 0);
if (!ReadMem((tmp & ~0x3), 4, &value))
return;
#endif
#ifdef SIM_FIX
switch( 3 - byte )
#else
switch (tmp & 0x3)
#endif // SIM_FIX
{
case 0:
value = registers[instr->rt];
break;
case 1:
value = (value & 0xff000000) | ((registers[instr->rt] >> 8) &
0xffffff);
break;
case 2:
value = (value & 0xffff0000) | ((registers[instr->rt] >> 16) &
0xffff);
break;
case 3:
value = (value & 0xffffff00) | ((registers[instr->rt] >> 24) &
0xff);
break;
}
#ifndef SIM_FIX
if (!WriteMem((tmp & ~0x3), 4, value))
return;
#else
// DEBUG('P', "Value 0x%X\n",value);
if (!WriteMem((tmp - byte), 4, value))
return;
#endif // SIM_FIX
break;
case OP_SWR:
tmp = registers[instr->rs] + instr->extra;
#ifndef SIM_FIX
// The little endian/big endian swap code would
// fail (I think) if the other cases are ever exercised.
ASSERT((tmp & 0x3) == 0);
if (!ReadMem((tmp & ~0x3), 4, &value))
return;
#else
// The only difference between this code and the BIG ENDIAN code
// is that the ReadMem call is guaranteed an aligned access as
// it should be (Kane's book hides the fact that all memory
// access are done using aligned loads - what the instruction
// asks for is a arbitrary) This is the whole purpose of LWL
// and LWR etc.
byte = tmp & 0x3;
// DEBUG('P', "Addr 0x%X\n",tmp-byte);
if (!ReadMem(tmp-byte, 4, &value))
return;
// DEBUG('P', "Value 0x%X\n",value);
#endif // SIM_FIX
#ifndef SIM_FIX
switch (tmp & 0x3)
#else
switch( 3 - byte )
#endif // SIM_FIX
{
case 0:
value = (value & 0xffffff) | (registers[instr->rt] << 24);
break;
case 1:
value = (value & 0xffff) | (registers[instr->rt] << 16);
break;
case 2:
value = (value & 0xff) | (registers[instr->rt] << 8);
break;
case 3:
value = registers[instr->rt];
break;
}
#ifndef SIM_FIX
if (!WriteMem((tmp & ~0x3), 4, value))
return;
#else
// DEBUG('P', "Value 0x%X\n",value);
if (!WriteMem((tmp - byte), 4, value))
return;
#endif // SIM_FIX
break;
case OP_SYSCALL:
RaiseException(SyscallException, 0);
return;
case OP_XOR:
registers[instr->rd] = registers[instr->rs] ^ registers[instr->rt];
break;
case OP_XORI:
registers[instr->rt] = registers[instr->rs] ^ (instr->extra & 0xffff);
break;
case OP_RES:
case OP_UNIMP:
RaiseException(IllegalInstrException, 0);
return;
default:
ASSERT(FALSE);
}
// Now we have successfully executed the instruction.
// Do any delayed load operation
DelayedLoad(nextLoadReg, nextLoadValue);
// Advance program counters.
registers[PrevPCReg] = registers[PCReg]; // for debugging, in case we
// are jumping into lala-land
registers[PCReg] = registers[NextPCReg];
registers[NextPCReg] = pcAfter;
}
//----------------------------------------------------------------------
// Machine::DelayedLoad
// Simulate effects of a delayed load.
//
// NOTE -- RaiseException/CheckInterrupts must also call DelayedLoad,
// since any delayed load must get applied before we trap to the kernel.
//----------------------------------------------------------------------
void
Machine::DelayedLoad(int nextReg, int nextValue)
{
registers[registers[LoadReg]] = registers[LoadValueReg];
registers[LoadReg] = nextReg;
registers[LoadValueReg] = nextValue;
registers[0] = 0; // and always make sure R0 stays zero.
}
//----------------------------------------------------------------------
// Instruction::Decode
// Decode a MIPS instruction
//----------------------------------------------------------------------
void
Instruction::Decode()
{
OpInfo *opPtr;
rs = (value >> 21) & 0x1f;
rt = (value >> 16) & 0x1f;
rd = (value >> 11) & 0x1f;
opPtr = &opTable[(value >> 26) & 0x3f];
opCode = opPtr->opCode;
if (opPtr->format == IFMT) {
extra = value & 0xffff;
if (extra & 0x8000) {
extra |= 0xffff0000;
}
} else if (opPtr->format == RFMT) {
extra = (value >> 6) & 0x1f;
} else {
extra = value & 0x3ffffff;
}
if (opCode == SPECIAL) {
opCode = specialTable[value & 0x3f];
} else if (opCode == BCOND) {
int i = value & 0x1f0000;
if (i == 0) {
opCode = OP_BLTZ;
} else if (i == 0x10000) {
opCode = OP_BGEZ;
} else if (i == 0x100000) {
opCode = OP_BLTZAL;
} else if (i == 0x110000) {
opCode = OP_BGEZAL;
} else {
opCode = OP_UNIMP;
}
}
}
//----------------------------------------------------------------------
// Mult
// Simulate R2000 multiplication.
// The words at *hiPtr and *loPtr are overwritten with the
// double-length result of the multiplication.
//----------------------------------------------------------------------
static void
Mult(int a, int b, bool signedArith, int* hiPtr, int* loPtr)
{
if ((a == 0) || (b == 0)) {
*hiPtr = *loPtr = 0;
return;
}
// Compute the sign of the result, then make everything positive
// so unsigned computation can be done in the main loop.
bool negative = FALSE;
if (signedArith) {
if (a < 0) {
negative = !negative;
a = -a;
}
if (b < 0) {
negative = !negative;
b = -b;
}
}
// Compute the result in unsigned arithmetic (check a's bits one at
// a time, and add in a shifted value of b).
unsigned int bLo = b;
unsigned int bHi = 0;
unsigned int lo = 0;
unsigned int hi = 0;
for (int i = 0; i < 32; i++) {
if (a & 1) {
lo += bLo;
if (lo < bLo) // Carry out of the low bits?
hi += 1;
hi += bHi;
if ((a & 0xfffffffe) == 0)
break;
}
bHi <<= 1;
if (bLo & 0x80000000)
bHi |= 1;
bLo <<= 1;
a >>= 1;
}
// If the result is supposed to be negative, compute the two's
// complement of the double-word result.
if (negative) {
hi = ~hi;
lo = ~lo;
lo++;
if (lo == 0)
hi++;
}
*hiPtr = (int) hi;
*loPtr = (int) lo;
}

229
code/machine/mipssim.h Normal file
View File

@@ -0,0 +1,229 @@
// mipssim.h
// Internal data structures for simulating the MIPS instruction set.
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef MIPSSIM_H
#define MIPSSIM_H
#include "copyright.h"
/*
* OpCode values. The names are straight from the MIPS
* manual except for the following special ones:
*
* OP_UNIMP - means that this instruction is legal, but hasn't
* been implemented in the simulator yet.
* OP_RES - means that this is a reserved opcode (it isn't
* supported by the architecture).
*/
#define OP_ADD 1
#define OP_ADDI 2
#define OP_ADDIU 3
#define OP_ADDU 4
#define OP_AND 5
#define OP_ANDI 6
#define OP_BEQ 7
#define OP_BGEZ 8
#define OP_BGEZAL 9
#define OP_BGTZ 10
#define OP_BLEZ 11
#define OP_BLTZ 12
#define OP_BLTZAL 13
#define OP_BNE 14
#define OP_DIV 16
#define OP_DIVU 17
#define OP_J 18
#define OP_JAL 19
#define OP_JALR 20
#define OP_JR 21
#define OP_LB 22
#define OP_LBU 23
#define OP_LH 24
#define OP_LHU 25
#define OP_LUI 26
#define OP_LW 27
#define OP_LWL 28
#define OP_LWR 29
#define OP_MFHI 31
#define OP_MFLO 32
#define OP_MTHI 34
#define OP_MTLO 35
#define OP_MULT 36
#define OP_MULTU 37
#define OP_NOR 38
#define OP_OR 39
#define OP_ORI 40
#define OP_RFE 41
#define OP_SB 42
#define OP_SH 43
#define OP_SLL 44
#define OP_SLLV 45
#define OP_SLT 46
#define OP_SLTI 47
#define OP_SLTIU 48
#define OP_SLTU 49
#define OP_SRA 50
#define OP_SRAV 51
#define OP_SRL 52
#define OP_SRLV 53
#define OP_SUB 54
#define OP_SUBU 55
#define OP_SW 56
#define OP_SWL 57
#define OP_SWR 58
#define OP_XOR 59
#define OP_XORI 60
#define OP_SYSCALL 61
#define OP_UNIMP 62
#define OP_RES 63
#define MaxOpcode 63
/*
* Miscellaneous definitions:
*/
#define IndexToAddr(x) ((x) << 2)
#define SIGN_BIT 0x80000000
#define R31 31
/*
* The table below is used to translate bits 31:26 of the instruction
* into a value suitable for the "opCode" field of a MemWord structure,
* or into a special value for further decoding.
*/
#define SPECIAL 100
#define BCOND 101
#define IFMT 1
#define JFMT 2
#define RFMT 3
struct OpInfo {
int opCode; /* Translated op code. */
int format; /* Format type (IFMT or JFMT or RFMT) */
};
static OpInfo opTable[] = {
{SPECIAL, RFMT}, {BCOND, IFMT}, {OP_J, JFMT}, {OP_JAL, JFMT},
{OP_BEQ, IFMT}, {OP_BNE, IFMT}, {OP_BLEZ, IFMT}, {OP_BGTZ, IFMT},
{OP_ADDI, IFMT}, {OP_ADDIU, IFMT}, {OP_SLTI, IFMT}, {OP_SLTIU, IFMT},
{OP_ANDI, IFMT}, {OP_ORI, IFMT}, {OP_XORI, IFMT}, {OP_LUI, IFMT},
{OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT},
{OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT},
{OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT},
{OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT},
{OP_LB, IFMT}, {OP_LH, IFMT}, {OP_LWL, IFMT}, {OP_LW, IFMT},
{OP_LBU, IFMT}, {OP_LHU, IFMT}, {OP_LWR, IFMT}, {OP_RES, IFMT},
{OP_SB, IFMT}, {OP_SH, IFMT}, {OP_SWL, IFMT}, {OP_SW, IFMT},
{OP_RES, IFMT}, {OP_RES, IFMT}, {OP_SWR, IFMT}, {OP_RES, IFMT},
{OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT},
{OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT},
{OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT}, {OP_UNIMP, IFMT},
{OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}, {OP_RES, IFMT}
};
/*
* The table below is used to convert the "funct" field of SPECIAL
* instructions into the "opCode" field of a MemWord.
*/
static int specialTable[] = {
OP_SLL, OP_RES, OP_SRL, OP_SRA, OP_SLLV, OP_RES, OP_SRLV, OP_SRAV,
OP_JR, OP_JALR, OP_RES, OP_RES, OP_SYSCALL, OP_UNIMP, OP_RES, OP_RES,
OP_MFHI, OP_MTHI, OP_MFLO, OP_MTLO, OP_RES, OP_RES, OP_RES, OP_RES,
OP_MULT, OP_MULTU, OP_DIV, OP_DIVU, OP_RES, OP_RES, OP_RES, OP_RES,
OP_ADD, OP_ADDU, OP_SUB, OP_SUBU, OP_AND, OP_OR, OP_XOR, OP_NOR,
OP_RES, OP_RES, OP_SLT, OP_SLTU, OP_RES, OP_RES, OP_RES, OP_RES,
OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES,
OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES, OP_RES
};
// Stuff to help print out each instruction, for debugging
enum RegType { NONE, RS, RT, RD, EXTRA };
struct OpString {
char *format; // Printed version of instruction
RegType args[3];
};
static struct OpString opStrings[] = {
{"Shouldn't happen", {NONE, NONE, NONE}},
{"ADD r%d,r%d,r%d", {RD, RS, RT}},
{"ADDI r%d,r%d,%d", {RT, RS, EXTRA}},
{"ADDIU r%d,r%d,%d", {RT, RS, EXTRA}},
{"ADDU r%d,r%d,r%d", {RD, RS, RT}},
{"AND r%d,r%d,r%d", {RD, RS, RT}},
{"ANDI r%d,r%d,%d", {RT, RS, EXTRA}},
{"BEQ r%d,r%d,%d", {RS, RT, EXTRA}},
{"BGEZ r%d,%d", {RS, EXTRA, NONE}},
{"BGEZAL r%d,%d", {RS, EXTRA, NONE}},
{"BGTZ r%d,%d", {RS, EXTRA, NONE}},
{"BLEZ r%d,%d", {RS, EXTRA, NONE}},
{"BLTZ r%d,%d", {RS, EXTRA, NONE}},
{"BLTZAL r%d,%d", {RS, EXTRA, NONE}},
{"BNE r%d,r%d,%d", {RS, RT, EXTRA}},
{"Shouldn't happen", {NONE, NONE, NONE}},
{"DIV r%d,r%d", {RS, RT, NONE}},
{"DIVU r%d,r%d", {RS, RT, NONE}},
{"J %d", {EXTRA, NONE, NONE}},
{"JAL %d", {EXTRA, NONE, NONE}},
{"JALR r%d,r%d", {RD, RS, NONE}},
{"JR r%d,r%d", {RD, RS, NONE}},
{"LB r%d,%d(r%d)", {RT, EXTRA, RS}},
{"LBU r%d,%d(r%d)", {RT, EXTRA, RS}},
{"LH r%d,%d(r%d)", {RT, EXTRA, RS}},
{"LHU r%d,%d(r%d)", {RT, EXTRA, RS}},
{"LUI r%d,%d", {RT, EXTRA, NONE}},
{"LW r%d,%d(r%d)", {RT, EXTRA, RS}},
{"LWL r%d,%d(r%d)", {RT, EXTRA, RS}},
{"LWR r%d,%d(r%d)", {RT, EXTRA, RS}},
{"Shouldn't happen", {NONE, NONE, NONE}},
{"MFHI r%d", {RD, NONE, NONE}},
{"MFLO r%d", {RD, NONE, NONE}},
{"Shouldn't happen", {NONE, NONE, NONE}},
{"MTHI r%d", {RS, NONE, NONE}},
{"MTLO r%d", {RS, NONE, NONE}},
{"MULT r%d,r%d", {RS, RT, NONE}},
{"MULTU r%d,r%d", {RS, RT, NONE}},
{"NOR r%d,r%d,r%d", {RD, RS, RT}},
{"OR r%d,r%d,r%d", {RD, RS, RT}},
{"ORI r%d,r%d,%d", {RT, RS, EXTRA}},
{"RFE", {NONE, NONE, NONE}},
{"SB r%d,%d(r%d)", {RT, EXTRA, RS}},
{"SH r%d,%d(r%d)", {RT, EXTRA, RS}},
{"SLL r%d,r%d,%d", {RD, RT, EXTRA}},
{"SLLV r%d,r%d,r%d", {RD, RT, RS}},
{"SLT r%d,r%d,r%d", {RD, RS, RT}},
{"SLTI r%d,r%d,%d", {RT, RS, EXTRA}},
{"SLTIU r%d,r%d,%d", {RT, RS, EXTRA}},
{"SLTU r%d,r%d,r%d", {RD, RS, RT}},
{"SRA r%d,r%d,%d", {RD, RT, EXTRA}},
{"SRAV r%d,r%d,r%d", {RD, RT, RS}},
{"SRL r%d,r%d,%d", {RD, RT, EXTRA}},
{"SRLV r%d,r%d,r%d", {RD, RT, RS}},
{"SUB r%d,r%d,r%d", {RD, RS, RT}},
{"SUBU r%d,r%d,r%d", {RD, RS, RT}},
{"SW r%d,%d(r%d)", {RT, EXTRA, RS}},
{"SWL r%d,%d(r%d)", {RT, EXTRA, RS}},
{"SWR r%d,%d(r%d)", {RT, EXTRA, RS}},
{"XOR r%d,r%d,r%d", {RD, RS, RT}},
{"XORI r%d,r%d,%d", {RT, RS, EXTRA}},
{"SYSCALL", {NONE, NONE, NONE}},
{"Unimplemented", {NONE, NONE, NONE}},
{"Reserved", {NONE, NONE, NONE}}
};
#endif // MIPSSIM_H

182
code/machine/network.cc Normal file
View File

@@ -0,0 +1,182 @@
// network.cc
// Routines to simulate a network interface, using UNIX sockets
// to deliver packets between multiple invocations of nachos.
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "network.h"
#include "main.h"
//-----------------------------------------------------------------------
// NetworkInput::NetworkInput
// Initialize the simulation for the network input
//
// "toCall" is the interrupt handler to call when packet arrives
//-----------------------------------------------------------------------
NetworkInput::NetworkInput(CallBackObj *toCall)
{
// set up the stuff to emulate asynchronous interrupts
callWhenAvail = toCall;
packetAvail = FALSE;
inHdr.length = 0;
sock = OpenSocket();
sprintf(sockName, "SOCKET_%d", kernel->hostName);
AssignNameToSocket(sockName, sock); // Bind socket to a filename
// in the current directory.
// start polling for incoming packets
kernel->interrupt->Schedule(this, NetworkTime, NetworkRecvInt);
}
//-----------------------------------------------------------------------
// NetworkInput::NetworkInput
// Deallocate the simulation for the network input
// (basically, deallocate the input mailbox)
//-----------------------------------------------------------------------
NetworkInput::~NetworkInput()
{
CloseSocket(sock);
DeAssignNameToSocket(sockName);
}
//-----------------------------------------------------------------------
// NetworkInput::CallBack
// Simulator calls this when a packet may be available to
// be read in from the simulated network.
//
// First check to make sure packet is available & there's space to
// pull it in. Then invoke the "callBack" registered by whoever
// wants the packet.
//-----------------------------------------------------------------------
void
NetworkInput::CallBack()
{
// schedule the next time to poll for a packet
kernel->interrupt->Schedule(this, NetworkTime, NetworkRecvInt);
if (inHdr.length != 0) // do nothing if packet is already buffered
return;
if (!PollSocket(sock)) // do nothing if no packet to be read
return;
// otherwise, read packet in
char *buffer = new char[MaxWireSize];
ReadFromSocket(sock, buffer, MaxWireSize);
// divide packet into header and data
inHdr = *(PacketHeader *)buffer;
ASSERT((inHdr.to == kernel->hostName) && (inHdr.length <= MaxPacketSize));
bcopy(buffer + sizeof(PacketHeader), inbox, inHdr.length);
delete [] buffer ;
DEBUG(dbgNet, "Network received packet from " << inHdr.from << ", length " << inHdr.length);
kernel->stats->numPacketsRecvd++;
// tell post office that the packet has arrived
callWhenAvail->CallBack();
}
//-----------------------------------------------------------------------
// NetworkInput::Receive
// Read a packet, if one is buffered
//-----------------------------------------------------------------------
PacketHeader
NetworkInput::Receive(char* data)
{
PacketHeader hdr = inHdr;
inHdr.length = 0;
if (hdr.length != 0) {
bcopy(inbox, data, hdr.length);
}
return hdr;
}
//-----------------------------------------------------------------------
// NetworkOutput::NetworkOutput
// Initialize the simulation for sending network packets
//
// "reliability" says whether we drop packets to emulate unreliable links
// "toCall" is the interrupt handler to call when next packet can be sent
//-----------------------------------------------------------------------
NetworkOutput::NetworkOutput(double reliability, CallBackObj *toCall)
{
if (reliability < 0) chanceToWork = 0;
else if (reliability > 1) chanceToWork = 1;
else chanceToWork = reliability;
// set up the stuff to emulate asynchronous interrupts
callWhenDone = toCall;
sendBusy = FALSE;
sock = OpenSocket();
}
//-----------------------------------------------------------------------
// NetworkOutput::~NetworkOutput
// Deallocate the simulation for sending network packets
//-----------------------------------------------------------------------
NetworkOutput::~NetworkOutput()
{
CloseSocket(sock);
}
//-----------------------------------------------------------------------
// NetworkOutput::CallBack
// Called by simulator when another packet can be sent.
//-----------------------------------------------------------------------
void
NetworkOutput::CallBack()
{
sendBusy = FALSE;
kernel->stats->numPacketsSent++;
callWhenDone->CallBack();
}
//-----------------------------------------------------------------------
// NetworkOutput::Send
// Send a packet into the simulated network, to the destination in hdr.
// Concatenate hdr and data, and schedule an interrupt to tell the user
// when the next packet can be sent
//
// Note we always pad out a packet to MaxWireSize before putting it into
// the socket, because it's simpler at the receive end.
//-----------------------------------------------------------------------
void
NetworkOutput::Send(PacketHeader hdr, char* data)
{
char toName[32];
sprintf(toName, "SOCKET_%d", (int)hdr.to);
ASSERT((sendBusy == FALSE) && (hdr.length > 0) &&
(hdr.length <= MaxPacketSize) && (hdr.from == kernel->hostName));
DEBUG(dbgNet, "Sending to addr " << hdr.to << ", length " << hdr.length);
kernel->interrupt->Schedule(this, NetworkTime, NetworkSendInt);
if (RandomNumber() % 100 >= chanceToWork * 100) { // emulate a lost packet
DEBUG(dbgNet, "oops, lost it!");
return;
}
// concatenate hdr and data into a single buffer, and send it out
char *buffer = new char[MaxWireSize];
*(PacketHeader *)buffer = hdr;
bcopy(data, buffer + sizeof(PacketHeader), hdr.length);
SendToSocket(sock, buffer, MaxWireSize, toName);
delete [] buffer;
}

110
code/machine/network.h Normal file
View File

@@ -0,0 +1,110 @@
// network.h
// Data structures to emulate a physical network connection.
// The network provides the abstraction of ordered, unreliable,
// fixed-size packet delivery to other machines on the network.
//
// You may note that the interface to the network is similar to
// the console device -- both are full duplex channels.
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef NETWORK_H
#define NETWORK_H
#include "copyright.h"
#include "utility.h"
#include "callback.h"
// Network address -- uniquely identifies a machine. This machine's ID
// is given on the command line.
typedef int NetworkAddress;
// The following class defines the network packet header.
// The packet header is prepended to the data payload by the Network driver,
// before the packet is sent over the wire. The format on the wire is:
// packet header (PacketHeader)
// data (containing MailHeader from the PostOffice!)
class PacketHeader {
public:
NetworkAddress to; // Destination machine ID
NetworkAddress from; // source machine ID
unsigned length; // bytes of packet data, excluding the
// packet header (but including the
// MailHeader prepended by the post office)
};
#define MaxWireSize 64 // largest packet that can go out on the wire
#define MaxPacketSize (MaxWireSize - sizeof(struct PacketHeader))
// data "payload" of the largest packet
// The following two classes defines a physical network device. The network
// is capable of delivering fixed sized packets, in order but unreliably,
// to other machines connected to the network.
//
// The "reliability" of the network can be specified to the constructor.
// This number, between 0 and 1, is the chance that the network will lose
// a packet. Note that you can change the seed for the random number
// generator, by changing the arguments to RandomInit() in Initialize().
// The random number generator is used to choose which packets to drop.
class NetworkInput : public CallBackObj{
public:
NetworkInput(CallBackObj *toCall);
// Allocate and initialize network input driver
~NetworkInput(); // De-allocate the network input driver data
PacketHeader Receive(char* data);
// Poll the network for incoming messages.
// If there is a packet waiting, copy the
// packet into "data" and return the header.
// If no packet is waiting, return a header
// with length 0.
void CallBack(); // A packet may have arrived.
private:
int sock; // UNIX socket number for incoming packets
char sockName[32]; // File name corresponding to UNIX socket
CallBackObj *callWhenAvail; // Interrupt handler, signalling packet has
// arrived.
bool packetAvail; // Packet has arrived, can be pulled off of
// network
PacketHeader inHdr; // Information about arrived packet
char inbox[MaxPacketSize]; // Data for arrived packet
};
class NetworkOutput : public CallBackObj {
public:
NetworkOutput(double reliability, CallBackObj *toCall);
// Allocate and initialize network output driver
~NetworkOutput(); // De-allocate the network input driver data
void Send(PacketHeader hdr, char* data);
// Send the packet data to a remote machine,
// specified by "hdr". Returns immediately.
// "callWhenDone" is invoked once the next
// packet can be sent. Note that callWhenDone
// is called whether or not the packet is
// dropped, and note that the "from" field of
// the PacketHeader is filled in automatically
// by Send().
void CallBack(); // Interrupt handler, called when message is
// sent
private:
int sock; // UNIX socket number for outgoing packets
double chanceToWork; // Likelihood packet will be dropped
CallBackObj *callWhenDone; // Interrupt handler, signalling next packet
// can be sent.
bool sendBusy; // Packet is being sent.
};
#endif // NETWORK_H

45
code/machine/stats.cc Normal file
View File

@@ -0,0 +1,45 @@
// stats.h
// Routines for managing statistics about Nachos performance.
//
// DO NOT CHANGE -- these stats are maintained by the machine emulation.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "debug.h"
#include "stats.h"
//----------------------------------------------------------------------
// Statistics::Statistics
// Initialize performance metrics to zero, at system startup.
//----------------------------------------------------------------------
Statistics::Statistics()
{
totalTicks = idleTicks = systemTicks = userTicks = 0;
numDiskReads = numDiskWrites = 0;
numConsoleCharsRead = numConsoleCharsWritten = 0;
numPageFaults = numPacketsSent = numPacketsRecvd = 0;
}
//----------------------------------------------------------------------
// Statistics::Print
// Print performance metrics, when we've finished everything
// at system shutdown.
//----------------------------------------------------------------------
void
Statistics::Print()
{
cout << "Ticks: total " << totalTicks << ", idle " << idleTicks;
cout << ", system " << systemTicks << ", user " << userTicks <<"\n";
cout << "Disk I/O: reads " << numDiskReads;
cout << ", writes " << numDiskWrites << "\n";
cout << "Console I/O: reads " << numConsoleCharsRead;
cout << ", writes " << numConsoleCharsWritten << "\n";
cout << "Paging: faults " << numPageFaults << "\n";
cout << "Network I/O: packets received " << numPacketsRecvd;
cout << ", sent " << numPacketsSent << "\n";
}

60
code/machine/stats.h Normal file
View File

@@ -0,0 +1,60 @@
// stats.h
// Data structures for gathering statistics about Nachos performance.
//
// DO NOT CHANGE -- these stats are maintained by the machine emulation
//
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef STATS_H
#define STATS_H
#include "copyright.h"
// The following class defines the statistics that are to be kept
// about Nachos behavior -- how much time (ticks) elapsed, how
// many user instructions executed, etc.
//
// The fields in this class are public to make it easier to update.
class Statistics {
public:
int totalTicks; // Total time running Nachos
int idleTicks; // Time spent idle (no threads to run)
int systemTicks; // Time spent executing system code
int userTicks; // Time spent executing user code
// (this is also equal to # of
// user instructions executed)
int numDiskReads; // number of disk read requests
int numDiskWrites; // number of disk write requests
int numConsoleCharsRead; // number of characters read from the keyboard
int numConsoleCharsWritten; // number of characters written to the display
int numPageFaults; // number of virtual memory page faults
int numPacketsSent; // number of packets sent over the network
int numPacketsRecvd; // number of packets received over the network
Statistics(); // initialize everything to zero
void Print(); // print collected statistics
};
// Constants used to reflect the relative time an operation would
// take in a real system. A "tick" is a just a unit of time -- if you
// like, a microsecond.
//
// Since Nachos kernel code is directly executed, and the time spent
// in the kernel measured by the number of calls to enable interrupts,
// these time constants are none too exact.
const int UserTick = 1; // advance for each user-level instruction
const int SystemTick = 10; // advance each time interrupts are enabled
const int RotationTime = 500; // time disk takes to rotate one sector
const int SeekTime = 500; // time disk takes to seek past one track
const int ConsoleTime = 100; // time to read or write one character
const int NetworkTime = 100; // time to send or receive one packet
const int TimerTicks = 100; // (average) time between timer interrupts
#endif // STATS_H

81
code/machine/timer.cc Normal file
View File

@@ -0,0 +1,81 @@
// timer.cc
// Routines to emulate a hardware timer device.
//
// A hardware timer generates a CPU interrupt every X milliseconds.
// This means it can be used for implementing time-slicing.
//
// We emulate a hardware timer by scheduling an interrupt to occur
// every time stats->totalTicks has increased by TimerTicks.
//
// In order to introduce some randomness into time-slicing, if "doRandom"
// is set, then the interrupt is comes after a random number of ticks.
//
// Remember -- nothing in here is part of Nachos. It is just
// an emulation for the hardware that Nachos is running on top of.
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "timer.h"
#include "main.h"
#include "sysdep.h"
//----------------------------------------------------------------------
// Timer::Timer
// Initialize a hardware timer device. Save the place to call
// on each interrupt, and then arrange for the timer to start
// generating interrupts.
//
// "doRandom" -- if true, arrange for the interrupts to occur
// at random, instead of fixed, intervals.
// "toCall" is the interrupt handler to call when the timer expires.
//----------------------------------------------------------------------
Timer::Timer(bool doRandom, CallBackObj *toCall)
{
randomize = doRandom;
callPeriodically = toCall;
disable = FALSE;
SetInterrupt();
}
//----------------------------------------------------------------------
// Timer::CallBack
// Routine called when interrupt is generated by the hardware
// timer device. Schedule the next interrupt, and invoke the
// interrupt handler.
//----------------------------------------------------------------------
void
Timer::CallBack()
{
// invoke the Nachos interrupt handler for this device
callPeriodically->CallBack();
SetInterrupt(); // do last, to let software interrupt handler
// decide if it wants to disable future interrupts
}
//----------------------------------------------------------------------
// Timer::SetInterrupt
// Cause a timer interrupt to occur in the future, unless
// future interrupts have been disabled. The delay is either
// fixed or random.
//----------------------------------------------------------------------
void
Timer::SetInterrupt()
{
if (!disable) {
int delay = TimerTicks;
if (randomize) {
delay = 1 + (RandomNumber() % (TimerTicks * 2));
}
// schedule the next timer device interrupt
kernel->interrupt->Schedule(this, delay, TimerInt);
}
}

53
code/machine/timer.h Normal file
View File

@@ -0,0 +1,53 @@
// timer.h
// Data structures to emulate a hardware timer.
//
// A hardware timer generates a CPU interrupt every X milliseconds.
// This means it can be used for implementing time-slicing, or for
// having a thread go to sleep for a specific period of time.
//
// We emulate a hardware timer by scheduling an interrupt to occur
// every time stats->totalTicks has increased by TimerTicks.
//
// In order to introduce some randomness into time-slicing, if "doRandom"
// is set, then the interrupt comes after a random number of ticks.
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef TIMER_H
#define TIMER_H
#include "copyright.h"
#include "utility.h"
#include "callback.h"
// The following class defines a hardware timer.
class Timer : public CallBackObj {
public:
Timer(bool doRandom, CallBackObj *toCall);
// Initialize the timer, and callback to "toCall"
// every time slice.
virtual ~Timer() {}
void Disable() { disable = TRUE; }
// Turn timer device off, so it doesn't
// generate any more interrupts.
private:
bool randomize; // set if we need to use a random timeout delay
CallBackObj *callPeriodically; // call this every TimerTicks time units
bool disable; // turn off the timer device after next
// interrupt.
void CallBack(); // called internally when the hardware
// timer generates an interrupt
void SetInterrupt(); // cause an interrupt to occur in the
// the future after a fixed or random
// delay
};
#endif // TIMER_H

250
code/machine/translate.cc Normal file
View File

@@ -0,0 +1,250 @@
// translate.cc
// Routines to translate virtual addresses to physical addresses.
// Software sets up a table of legal translations. We look up
// in the table on every memory reference to find the true physical
// memory location.
//
// Two types of translation are supported here.
//
// Linear page table -- the virtual page # is used as an index
// into the table, to find the physical page #.
//
// Translation lookaside buffer -- associative lookup in the table
// to find an entry with the same virtual page #. If found,
// this entry is used for the translation.
// If not, it traps to software with an exception.
//
// In practice, the TLB is much smaller than the amount of physical
// memory (16 entries is common on a machine that has 1000's of
// pages). Thus, there must also be a backup translation scheme
// (such as page tables), but the hardware doesn't need to know
// anything at all about that.
//
// Note that the contents of the TLB are specific to an address space.
// If the address space changes, so does the contents of the TLB!
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "main.h"
// Routines for converting Words and Short Words to and from the
// simulated machine's format of little endian. These end up
// being NOPs when the host machine is also little endian (DEC and Intel).
unsigned int
WordToHost(unsigned int word) {
#ifdef HOST_IS_BIG_ENDIAN
register unsigned long result;
result = (word >> 24) & 0x000000ff;
result |= (word >> 8) & 0x0000ff00;
result |= (word << 8) & 0x00ff0000;
result |= (word << 24) & 0xff000000;
return result;
#else
return word;
#endif /* HOST_IS_BIG_ENDIAN */
}
unsigned short
ShortToHost(unsigned short shortword) {
#ifdef HOST_IS_BIG_ENDIAN
register unsigned short result;
result = (shortword << 8) & 0xff00;
result |= (shortword >> 8) & 0x00ff;
return result;
#else
return shortword;
#endif /* HOST_IS_BIG_ENDIAN */
}
unsigned int
WordToMachine(unsigned int word) { return WordToHost(word); }
unsigned short
ShortToMachine(unsigned short shortword) { return ShortToHost(shortword); }
//----------------------------------------------------------------------
// Machine::ReadMem
// Read "size" (1, 2, or 4) bytes of virtual memory at "addr" into
// the location pointed to by "value".
//
// Returns FALSE if the translation step from virtual to physical memory
// failed.
//
// "addr" -- the virtual address to read from
// "size" -- the number of bytes to read (1, 2, or 4)
// "value" -- the place to write the result
//----------------------------------------------------------------------
bool
Machine::ReadMem(int addr, int size, int *value)
{
int data;
ExceptionType exception;
int physicalAddress;
DEBUG(dbgAddr, "Reading VA " << addr << ", size " << size);
exception = Translate(addr, &physicalAddress, size, FALSE);
if (exception != NoException) {
RaiseException(exception, addr);
return FALSE;
}
switch (size) {
case 1:
data = mainMemory[physicalAddress];
*value = data;
break;
case 2:
data = *(unsigned short *) &mainMemory[physicalAddress];
*value = ShortToHost(data);
break;
case 4:
data = *(unsigned int *) &mainMemory[physicalAddress];
*value = WordToHost(data);
break;
default: ASSERT(FALSE);
}
DEBUG(dbgAddr, "\tvalue read = " << *value);
return (TRUE);
}
//----------------------------------------------------------------------
// Machine::WriteMem
// Write "size" (1, 2, or 4) bytes of the contents of "value" into
// virtual memory at location "addr".
//
// Returns FALSE if the translation step from virtual to physical memory
// failed.
//
// "addr" -- the virtual address to write to
// "size" -- the number of bytes to be written (1, 2, or 4)
// "value" -- the data to be written
//----------------------------------------------------------------------
bool
Machine::WriteMem(int addr, int size, int value)
{
ExceptionType exception;
int physicalAddress;
DEBUG(dbgAddr, "Writing VA " << addr << ", size " << size << ", value " << value);
exception = Translate(addr, &physicalAddress, size, TRUE);
if (exception != NoException) {
RaiseException(exception, addr);
return FALSE;
}
switch (size) {
case 1:
mainMemory[physicalAddress] = (unsigned char) (value & 0xff);
break;
case 2:
*(unsigned short *) &mainMemory[physicalAddress]
= ShortToMachine((unsigned short) (value & 0xffff));
break;
case 4:
*(unsigned int *) &mainMemory[physicalAddress]
= WordToMachine((unsigned int) value);
break;
default: ASSERT(FALSE);
}
return TRUE;
}
//----------------------------------------------------------------------
// Machine::Translate
// Translate a virtual address into a physical address, using
// either a page table or a TLB. Check for alignment and all sorts
// of other errors, and if everything is ok, set the use/dirty bits in
// the translation table entry, and store the translated physical
// address in "physAddr". If there was an error, returns the type
// of the exception.
//
// "virtAddr" -- the virtual address to translate
// "physAddr" -- the place to store the physical address
// "size" -- the amount of memory being read or written
// "writing" -- if TRUE, check the "read-only" bit in the TLB
//----------------------------------------------------------------------
ExceptionType
Machine::Translate(int virtAddr, int* physAddr, int size, bool writing)
{
int i;
unsigned int vpn, offset;
TranslationEntry *entry;
unsigned int pageFrame;
DEBUG(dbgAddr, "\tTranslate " << virtAddr << (writing ? " , write" : " , read"));
// check for alignment errors
if (((size == 4) && (virtAddr & 0x3)) || ((size == 2) && (virtAddr & 0x1))){
DEBUG(dbgAddr, "Alignment problem at " << virtAddr << ", size " << size);
return AddressErrorException;
}
// we must have either a TLB or a page table, but not both!
ASSERT(tlb == NULL || pageTable == NULL);
ASSERT(tlb != NULL || pageTable != NULL);
// calculate the virtual page number, and offset within the page,
// from the virtual address
vpn = (unsigned) virtAddr / PageSize;
offset = (unsigned) virtAddr % PageSize;
if (tlb == NULL) { // => page table => vpn is index into table
if (vpn >= pageTableSize) {
DEBUG(dbgAddr, "Illegal virtual page # " << virtAddr);
return AddressErrorException;
} else if (!pageTable[vpn].valid) {
DEBUG(dbgAddr, "Invalid virtual page # " << virtAddr);
return PageFaultException;
}
entry = &pageTable[vpn];
} else {
for (entry = NULL, i = 0; i < TLBSize; i++)
if (tlb[i].valid && (tlb[i].virtualPage == ((int)vpn))) {
entry = &tlb[i]; // FOUND!
break;
}
if (entry == NULL) { // not found
DEBUG(dbgAddr, "Invalid TLB entry for this virtual page!");
return PageFaultException; // really, this is a TLB fault,
// the page may be in memory,
// but not in the TLB
}
}
if (entry->readOnly && writing) { // trying to write to a read-only page
DEBUG(dbgAddr, "Write to read-only page at " << virtAddr);
return ReadOnlyException;
}
pageFrame = entry->physicalPage;
// if the pageFrame is too big, there is something really wrong!
// An invalid translation was loaded into the page table or TLB.
if (pageFrame >= NumPhysPages) {
DEBUG(dbgAddr, "Illegal pageframe " << pageFrame);
return BusErrorException;
}
entry->use = TRUE; // set the use, dirty bits
if (writing)
entry->dirty = TRUE;
*physAddr = pageFrame * PageSize + offset;
ASSERT((*physAddr >= 0) && ((*physAddr + size) <= MemorySize));
DEBUG(dbgAddr, "phys addr = " << *physAddr);
return NoException;
}

45
code/machine/translate.h Normal file
View File

@@ -0,0 +1,45 @@
// translate.h
// Data structures for managing the translation from
// virtual page # -> physical page #, used for managing
// physical memory on behalf of user programs.
//
// The data structures in this file are "dual-use" - they
// serve both as a page table entry, and as an entry in
// a software-managed translation lookaside buffer (TLB).
// Either way, each entry is of the form:
// <virtual page #, physical page #>.
//
// DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef TLB_H
#define TLB_H
#include "copyright.h"
#include "utility.h"
// The following class defines an entry in a translation table -- either
// in a page table or a TLB. Each entry defines a mapping from one
// virtual page to one physical page.
// In addition, there are some extra bits for access control (valid and
// read-only) and some bits for usage information (use and dirty).
class TranslationEntry {
public:
int virtualPage; // The page number in virtual memory.
int physicalPage; // The page number in real memory (relative to the
// start of "mainMemory"
bool valid; // If this bit is set, the translation is ignored.
// (In other words, the entry hasn't been initialized.)
bool readOnly; // If this bit is set, the user program is not allowed
// to modify the contents of the page.
bool use; // This bit is set by the hardware every time the
// page is referenced or modified.
bool dirty; // This bit is set by the hardware every time the
// page is modified.
};
#endif

344
code/network/post.cc Normal file
View File

@@ -0,0 +1,344 @@
// post.cc
// Routines to deliver incoming network messages to the correct
// "address" -- a mailbox, or a holding area for incoming messages.
// This module operates just like the US postal service (in other
// words, it works, but it's slow, and you can't really be sure if
// your mail really got through!).
//
// Note that once we prepend the MailHdr to the outgoing message data,
// the combination (MailHdr plus data) looks like "data" to the Network
// device.
//
// The implementation synchronizes incoming messages with threads
// waiting for those messages.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#include "copyright.h"
#include "post.h"
//----------------------------------------------------------------------
// Mail::Mail
// Initialize a single mail message, by concatenating the headers to
// the data.
//
// "pktH" -- source, destination machine ID's
// "mailH" -- source, destination mailbox ID's
// "data" -- payload data
//----------------------------------------------------------------------
Mail::Mail(PacketHeader pktH, MailHeader mailH, char *msgData)
{
ASSERT(mailH.length <= MaxMailSize);
pktHdr = pktH;
mailHdr = mailH;
bcopy(msgData, data, mailHdr.length);
}
//----------------------------------------------------------------------
// MailBox::MailBox
// Initialize a single mail box within the post office, so that it
// can receive incoming messages.
//
// Just initialize a list of messages, representing the mailbox.
//----------------------------------------------------------------------
MailBox::MailBox()
{
messages = new SynchList<Mail *>();
}
//----------------------------------------------------------------------
// MailBox::~MailBox
// De-allocate a single mail box within the post office.
//
// Just delete the mailbox, and throw away all the queued messages
// in the mailbox.
//----------------------------------------------------------------------
MailBox::~MailBox()
{
delete messages;
}
//----------------------------------------------------------------------
// PrintHeader
// Print the message header -- the destination machine ID and mailbox
// #, source machine ID and mailbox #, and message length.
//
// "pktHdr" -- source, destination machine ID's
// "mailHdr" -- source, destination mailbox ID's
//----------------------------------------------------------------------
static void
PrintHeader(PacketHeader pktHdr, MailHeader mailHdr)
{
cout << "From (" << pktHdr.from << ", " << mailHdr.from << ") to (" <<
pktHdr.to << ", " << mailHdr.to << ") bytes " << mailHdr.length << "\n";
}
//----------------------------------------------------------------------
// MailBox::Put
// Add a message to the mailbox. If anyone is waiting for message
// arrival, wake them up!
//
// We need to reconstruct the Mail message (by concatenating the headers
// to the data), to simplify queueing the message on the SynchList.
//
// "pktHdr" -- source, destination machine ID's
// "mailHdr" -- source, destination mailbox ID's
// "data" -- payload message data
//----------------------------------------------------------------------
void
MailBox::Put(PacketHeader pktHdr, MailHeader mailHdr, char *data)
{
Mail *mail = new Mail(pktHdr, mailHdr, data);
messages->Append(mail); // put on the end of the list of
// arrived messages, and wake up
// any waiters
}
//----------------------------------------------------------------------
// MailBox::Get
// Get a message from a mailbox, parsing it into the packet header,
// mailbox header, and data.
//
// The calling thread waits if there are no messages in the mailbox.
//
// "pktHdr" -- address to put: source, destination machine ID's
// "mailHdr" -- address to put: source, destination mailbox ID's
// "data" -- address to put: payload message data
//----------------------------------------------------------------------
void
MailBox::Get(PacketHeader *pktHdr, MailHeader *mailHdr, char *data)
{
DEBUG(dbgNet, "Waiting for mail in mailbox");
Mail *mail = messages->RemoveFront(); // remove message from list;
// will wait if list is empty
*pktHdr = mail->pktHdr;
*mailHdr = mail->mailHdr;
if (debug->IsEnabled('n')) {
cout << "Got mail from mailbox: ";
PrintHeader(*pktHdr, *mailHdr);
}
bcopy(mail->data, data, mail->mailHdr.length);
// copy the message data into
// the caller's buffer
delete mail; // we've copied out the stuff we
// need, we can now discard the message
}
//----------------------------------------------------------------------
// PostOfficeInput::PostOfficeInput
// Initialize the post office input queues as a collection of mailboxes.
// Also initialize the network device, to allow post offices
// on different machines to deliver messages to one another.
//
// We use a separate thread "the postal worker" to wait for messages
// to arrive, and deliver them to the correct mailbox. Note that
// delivering messages to the mailboxes can't be done directly
// by the interrupt handlers, because it requires a Lock.
//
// "nBoxes" is the number of mail boxes in this Post Office
//----------------------------------------------------------------------
PostOfficeInput::PostOfficeInput(int nBoxes)
{
messageAvailable = new Semaphore("message available", 0);
numBoxes = nBoxes;
boxes = new MailBox[nBoxes];
network = new NetworkInput(this);
Thread *t = new Thread("postal worker", 1);
t->Fork(PostOfficeInput::PostalDelivery, this);
}
//----------------------------------------------------------------------
// PostOfficeInput::~PostOfficeInput
// De-allocate the post office data structures.
//
// Since the postal helper is waiting on the "messageAvail" semaphore,
// we don't deallocate it! This leaves garbage lying about,
// but the alternative is worse!
//----------------------------------------------------------------------
PostOfficeInput::~PostOfficeInput()
{
delete network;
delete [] boxes;
}
//----------------------------------------------------------------------
// PostOffice::PostalDelivery
// Wait for incoming messages, and put them in the right mailbox.
//
// Incoming messages have had the PacketHeader stripped off,
// but the MailHeader is still tacked on the front of the data.
//----------------------------------------------------------------------
void
PostOfficeInput::PostalDelivery(void* data)
{
PostOfficeInput* _this = (PostOfficeInput*)data;
PacketHeader pktHdr;
MailHeader mailHdr;
char *buffer = new char[MaxPacketSize];
for (;;) {
// first, wait for a message
_this->messageAvailable->P();
pktHdr = _this->network->Receive(buffer);
mailHdr = *(MailHeader *)buffer;
if (debug->IsEnabled('n')) {
cout << "Putting mail into mailbox: ";
PrintHeader(pktHdr, mailHdr);
}
// check that arriving message is legal!
ASSERT(0 <= mailHdr.to && mailHdr.to < _this->numBoxes);
ASSERT(mailHdr.length <= MaxMailSize);
// put into mailbox
_this->boxes[mailHdr.to].Put(pktHdr, mailHdr, buffer + sizeof(MailHeader));
}
}
//----------------------------------------------------------------------
// PostOfficeInput::Receive
// Retrieve a message from a specific box if one is available,
// otherwise wait for a message to arrive in the box.
//
// Note that the MailHeader + data looks just like normal payload
// data to the Network.
//
//
// "box" -- mailbox ID in which to look for message
// "pktHdr" -- address to put: source, destination machine ID's
// "mailHdr" -- address to put: source, destination mailbox ID's
// "data" -- address to put: payload message data
//----------------------------------------------------------------------
void
PostOfficeInput::Receive(int box, PacketHeader *pktHdr,
MailHeader *mailHdr, char* data)
{
ASSERT((box >= 0) && (box < numBoxes));
boxes[box].Get(pktHdr, mailHdr, data);
ASSERT(mailHdr->length <= MaxMailSize);
}
//----------------------------------------------------------------------
// PostOffice::CallBack
// Interrupt handler, called when a packet arrives from the network.
//
// Signal the PostalDelivery routine that it is time to get to work!
//----------------------------------------------------------------------
void
PostOfficeInput::CallBack()
{
messageAvailable->V();
}
//----------------------------------------------------------------------
// PostOfficeOutput::PostOfficeOutput
// Initialize the post office output queue.
//
// "reliability" is the probability that a network packet will
// be delivered (e.g., reliability = 1 means the network never
// drops any packets; reliability = 0 means the network never
// delivers any packets)
//----------------------------------------------------------------------
PostOfficeOutput::PostOfficeOutput(double reliability)
{
messageSent = new Semaphore("message sent", 0);
sendLock = new Lock("message send lock");
network = new NetworkOutput(reliability, this);
}
//----------------------------------------------------------------------
// PostOfficeOutput::~PostOfficeOutput
// De-allocate the post office data structures.
//----------------------------------------------------------------------
PostOfficeOutput::~PostOfficeOutput()
{
delete network;
delete messageSent;
delete sendLock;
}
//----------------------------------------------------------------------
// PostOfficeOutput::Send
// Concatenate the MailHeader to the front of the data, and pass
// the result to the Network for delivery to the destination machine.
//
// Note that the MailHeader + data looks just like normal payload
// data to the Network.
//
// "pktHdr" -- source, destination machine ID's
// "mailHdr" -- source, destination mailbox ID's
// "data" -- payload message data
//----------------------------------------------------------------------
void
PostOfficeOutput::Send(PacketHeader pktHdr, MailHeader mailHdr, char* data)
{
char* buffer = new char[MaxPacketSize]; // space to hold concatenated
// mailHdr + data
if (debug->IsEnabled('n')) {
cout << "Post send: ";
PrintHeader(pktHdr, mailHdr);
}
ASSERT(mailHdr.length <= MaxMailSize);
ASSERT(0 <= mailHdr.to);
// fill in pktHdr, for the Network layer
pktHdr.from = kernel->hostName;
pktHdr.length = mailHdr.length + sizeof(MailHeader);
// concatenate MailHeader and data
bcopy((char *)&mailHdr, buffer, sizeof(MailHeader));
bcopy(data, buffer + sizeof(MailHeader), mailHdr.length);
sendLock->Acquire(); // only one message can be sent
// to the network at any one time
network->Send(pktHdr, buffer);
messageSent->P(); // wait for interrupt to tell us
// ok to send the next message
sendLock->Release();
delete [] buffer; // we've sent the message, so
// we can delete our buffer
}
//----------------------------------------------------------------------
// PostOfficeOutput::CallBack
// Interrupt handler, called when the next packet can be put onto the
// network.
//
// Called even if the previous packet was dropped.
//----------------------------------------------------------------------
void
PostOfficeOutput::CallBack()
{
messageSent->V();
}

151
code/network/post.h Normal file
View File

@@ -0,0 +1,151 @@
// post.h
// Data structures for providing the abstraction of unreliable,
// ordered, fixed-size message delivery to mailboxes on other
// (directly connected) machines. Messages can be dropped by
// the network, but they are never corrupted.
//
// The US Post Office (and Canada Post! -KMS)
// delivers mail to the addressed mailbox.
// By analogy, our post office delivers packets to a specific buffer
// (MailBox), based on the mailbox number stored in the packet header.
// Mail waits in the box until a thread asks for it; if the mailbox
// is empty, threads can wait for mail to arrive in it.
//
// Thus, the service our post office provides is to de-multiplex
// incoming packets, delivering them to the appropriate thread.
//
// With each message, you get a return address, which consists of a "from
// address", which is the id of the machine that sent the message, and
// a "from box", which is the number of a mailbox on the sending machine
// to which you can send an acknowledgement, if your protocol requires
// this.
//
// Copyright (c) 1992-1996 The Regents of the University of California.
// All rights reserved. See copyright.h for copyright notice and limitation
// of liability and disclaimer of warranty provisions.
#ifndef POST_H
#define POST_H
#include "copyright.h"
#include "utility.h"
#include "callback.h"
#include "network.h"
#include "synchlist.h"
#include "synch.h"
// Mailbox address -- uniquely identifies a mailbox on a given machine.
// A mailbox is just a place for temporary storage for messages.
typedef int MailBoxAddress;
// The following class defines part of the message header.
// This is prepended to the message by the PostOffice, before the message
// is sent to the Network.
class MailHeader {
public:
MailBoxAddress to; // Destination mail box
MailBoxAddress from; // Mail box to reply to
unsigned length; // Bytes of message data (excluding the
// mail header)
};
// Maximum "payload" -- real data -- that can included in a single message
// Excluding the MailHeader and the PacketHeader
#define MaxMailSize (MaxPacketSize - sizeof(MailHeader))
// The following class defines the format of an incoming/outgoing
// "Mail" message. The message format is layered:
// network header (PacketHeader)
// post office header (MailHeader)
// data
class Mail {
public:
Mail(PacketHeader pktH, MailHeader mailH, char *msgData);
// Initialize a mail message by
// concatenating the headers to the data
PacketHeader pktHdr; // Header appended by Network
MailHeader mailHdr; // Header appended by PostOffice
char data[MaxMailSize]; // Payload -- message data
};
// The following class defines a single mailbox, or temporary storage
// for messages. Incoming messages are put by the PostOffice into the
// appropriate mailbox, and these messages can then be retrieved by
// threads on this machine.
class MailBox {
public:
MailBox(); // Allocate and initialize mail box
~MailBox(); // De-allocate mail box
void Put(PacketHeader pktHdr, MailHeader mailHdr, char *data);
// Atomically put a message into the mailbox
void Get(PacketHeader *pktHdr, MailHeader *mailHdr, char *data);
// Atomically get a message out of the
// mailbox (and wait if there is no message
// to get!)
private:
SynchList<Mail *> *messages; // A mailbox is just a list of arrived messages
};
// The following two classes defines a "Post Office", or a collection of
// mailboxes. The Post Office provides two main operations:
// Send -- send a message to a mailbox on a remote machine
// Receive -- wait until a message is in the mailbox, then remove and
// return it.
//
// Incoming messages are put by the PostOffice into the
// appropriate mailbox, waking up any threads waiting on Receive.
class PostOfficeInput : public CallBackObj {
public:
PostOfficeInput(int nBoxes); // Allocate and initialize Post Office
~PostOfficeInput(); // De-allocate Post Office data
void Receive(int box, PacketHeader *pktHdr,
MailHeader *mailHdr, char *data);
// Retrieve a message from "box". Wait if
// there is no message in the box.
static void PostalDelivery(void* data);
// Wait for incoming messages,
// and then put them in the correct mailbox
void CallBack(); // Called when incoming packet has arrived
// and can be pulled off of network
// (i.e., time to call PostalDelivery)
private:
NetworkInput *network; // Physical network connection
MailBox *boxes; // Table of mail boxes to hold incoming mail
int numBoxes; // Number of mail boxes
Semaphore *messageAvailable;// V'ed when message has arrived from network
};
class PostOfficeOutput : public CallBackObj {
public:
PostOfficeOutput(double reliability);
// Allocate and initialize output
// "reliability" is how many packets
// get dropped by the underlying network
~PostOfficeOutput(); // De-allocate Post Office data
void Send(PacketHeader pktHdr, MailHeader mailHdr, char *data);
// Send a message to a mailbox on a remote
// machine. The fromBox in the MailHeader is
// the return box for ack's.
void CallBack(); // Called when outgoing packet has been
// put on network; next packet can now be sent
private:
NetworkOutput *network; // Physical network connection
Semaphore *messageSent; // V'ed when next message can be sent to network
Lock *sendLock; // Only one outgoing message at a time
};
#endif

BIN
code/test/DISK_0 Normal file

Binary file not shown.

203
code/test/Makefile Normal file
View File

@@ -0,0 +1,203 @@
#
# Makefile for building user programs to run on top of Nachos
#
# Use "make" to build the test executable(s)
# Use "make clean" to remove .o files and .coff files
# Use "make distclean" to remove all files produced by make, including
# the test executables
#
# This is a GNU Makefile. It must be used with the GNU make program.
# At UW, the GNU make program is /software/gnu/bin/make.
# In many other places it is known as "gmake".
# You may wish to include /software/gnu/bin/ early in your command
# search path, so that you will be using GNU make when you type "make".
#
# Several things to be aware of:
#
# It should not be necessary to build the test executables for
# every type of host machine on which Nachos runs. You should
# be able to build them once, and then use them regardless of
# the host machine type. That is because the test executables
# run on the simulated MIPS machine, and not on the host.
#
# However:
# (1) if you are experiencing problems with the test executables,
# it would be prudent to rebuild them on the host machine
# on which you are currently running Nachos. To do this,
# just type "make distclean", and then "make"
#
# (2) the procedure used to build the test executables does
# depend on the host machine you are on. All of the machine
# dependencies are isolated in the Makefile.dep file.
# It should be possible to build the test executables on
# any MFCF machine. In the MFCF environment, this makefile
# should automatically figure out what type of host you are
# on, and should use the appropriate procedure.
# However, if you are working outside the MFCF environment,
# you will need to build a cross-compiler, build coff2noff,
# and edit Makefile.dep in this directory before you
# can build the test programs.
#
# Nachos assumes that the location of the program startup routine (the
# location the kernel jumps to when the program initially starts up)
# is at location 0. This means: start.o must be the first .o passed
# to ld, in order for the routine "Start" to be loaded at location 0
#
# When you make the test programs, you will see messages like these:
# numsections 3
# Loading 3 sections:
# ".text", filepos 0xd0, mempos 0x0, size 0x440
# ".data", filepos 0x510, mempos 0x440, size 0x0
# ".bss", filepos 0x0, mempos 0x440, size 0x12c0
# These messages are normal. They come from the coff2noff program.
# They are useful in that they tell you how big the various parts of your
# compiled user program are, and where in the address space
# coff2noff is going to place them. This information is also
# recorded in the header of the executable file that coff2noff
# creates. See the method AddrSpace::Load (in userprog/addrspace.cc)
# for an example of how this header is used by the Nachos OS to set up the
# address space for a new process that will run the executable.
#
#
# Adding New Test Programs:
#
# You are free to write new test programs, and to modify the
# existing programs. If you write a new program, you will
# need to modify this makefile so that the new program will
# get built.
# You will need to make the following changes for each program
# you add:
# (1) add the program's name to PROGRAMS variable definition
# (2) add dependencies and build commands for the new
# program. The easiest way to do this is to
# copy the dependencies and commands for an
# existing program, and then change the names.
#
# For example, if you write a test program in foo.c, for which
# the executable is to be called foo, you should do the following:
#
# change the PROGRAMS definition to look like this:
#
# PROGRAMS = halt shell matmult sort foo
#
# add these dependencies/commands:
#
# foo.o: foo.c
# $(CC) $(CFLAGS) -c foo.c
# foo: foo.o start.o
# $(LD) $(LDFLAGS) start.o foo.o -o foo.coff
# $(COFF2NOFF) foo.coff foo
#
# Be careful when you copy the commands! The commands
# must be indented with a *TAB*, not a bunch of spaces.
#
#
#############################################################################
# Makefile.dep contains all machine-dependent definitions
# If you are trying to build coff2noff somewhere outside
# of the MFCF environment, you will almost certainly want
# to visit and edit Makefile.dep before doing so
#############################################################################
include Makefile.dep
CC = $(GCCDIR)gcc
AS = $(GCCDIR)as
LD = $(GCCDIR)ld
INCDIR =-I../userprog -I../lib
CFLAGS = -G 0 -c $(INCDIR) -B../../usr/local/nachos/lib/gcc-lib/decstation-ultrix/2.95.2/ -B../../usr/local/nachos/decstation-ultrix/bin/
ifeq ($(hosttype),unknown)
PROGRAMS = unknownhost
else
# change this if you create a new test program!
# PROGRAMS = add halt consoleIO_test1 consoleIO_test2 fileIO_test1 fileIO_test2
PROGRAMS = halt
endif
all: $(PROGRAMS)
start.o: start.S ../userprog/syscall.h
$(CC) $(CFLAGS) $(ASFLAGS) -c start.S
halt.o: halt.c
$(CC) $(CFLAGS) -c halt.c
halt: halt.o start.o
$(LD) $(LDFLAGS) start.o halt.o -o halt.coff
$(COFF2NOFF) halt.coff halt
add.o: add.c
$(CC) $(CFLAGS) -c add.c
add: add.o start.o
$(LD) $(LDFLAGS) start.o add.o -o add.coff
$(COFF2NOFF) add.coff add
shell.o: shell.c
$(CC) $(CFLAGS) -c shell.c
shell: shell.o start.o
$(LD) $(LDFLAGS) start.o shell.o -o shell.coff
$(COFF2NOFF) shell.coff shell
sort.o: sort.c
$(CC) $(CFLAGS) -c sort.c
sort: sort.o start.o
$(LD) $(LDFLAGS) start.o sort.o -o sort.coff
$(COFF2NOFF) sort.coff sort
segments.o: segments.c
$(CC) $(CFLAGS) -c segments.c
segments: segments.o start.o
$(LD) $(LDFLAGS) start.o segments.o -o segments.coff
$(COFF2NOFF) segments.coff segments
matmult.o: matmult.c
$(CC) $(CFLAGS) -c matmult.c
matmult: matmult.o start.o
$(LD) $(LDFLAGS) start.o matmult.o -o matmult.coff
$(COFF2NOFF) matmult.coff matmult
consoleIO_test1.o: consoleIO_test1.c
$(CC) $(CFLAGS) -c consoleIO_test1.c
consoleIO_test1: consoleIO_test1.o start.o
$(LD) $(LDFLAGS) start.o consoleIO_test1.o -o consoleIO_test1.coff
$(COFF2NOFF) consoleIO_test1.coff consoleIO_test1
consoleIO_test2.o: consoleIO_test2.c
$(CC) $(CFLAGS) -c consoleIO_test2.c
consoleIO_test2: consoleIO_test2.o start.o
$(LD) $(LDFLAGS) start.o consoleIO_test2.o -o consoleIO_test2.coff
$(COFF2NOFF) consoleIO_test2.coff consoleIO_test2
fileIO_test1.o: fileIO_test1.c
$(CC) $(CFLAGS) -c fileIO_test1.c
fileIO_test1: fileIO_test1.o start.o
$(LD) $(LDFLAGS) start.o fileIO_test1.o -o fileIO_test1.coff
$(COFF2NOFF) fileIO_test1.coff fileIO_test1
fileIO_test2.o: fileIO_test2.c
$(CC) $(CFLAGS) -c fileIO_test2.c
fileIO_test2: fileIO_test2.o start.o
$(LD) $(LDFLAGS) start.o fileIO_test2.o -o fileIO_test2.coff
$(COFF2NOFF) fileIO_test2.coff fileIO_test2
fileIO_test3.o: fileIO_test3.c
$(CC) $(CFLAGS) -c fileIO_test3.c
fileIO_test3: fileIO_test3.o start.o
$(LD) $(LDFLAGS) start.o fileIO_test3.o -o fileIO_test3.coff
$(COFF2NOFF) fileIO_test3.coff fileIO_test3
clean:
$(RM) -f *.o *.ii
$(RM) -f *.coff
distclean: clean
$(RM) -f $(PROGRAMS)
unknownhost:
@echo Host type could not be determined.
@echo make is terminating.
@echo If you are on an MFCF machine, contact the instructor to report this problem
@echo Otherwise, edit Makefile.dep and try again.

63
code/test/Makefile.dep Normal file
View File

@@ -0,0 +1,63 @@
#############################################################################
# Machine-specific definitions
#
# If you are not in the MFCF environment, you can either add a new
# automatic test for your machine/OS type, or you should set the
# necessary variables "manually" here
#############################################################################
# unfortunately, command line arguments to uname are not
# very consistent across UNIX flavours. However, the following
# seem to work almost everywhere in MFCF land
osname = $(shell uname -s)
osrelease = $(shell uname -r)
hosttype = unknown
# Test for x86 Linux
# !!! COMMENT THE FOLLOWING LINES OUT IF BUILDING FOR SOLARIS HOST !!!
# !!! ADD PATH TO CPP and CROSS COMPILER
ifeq ($(osname),Linux)
# full path name of your cpp program i.e.:
CPP = ../../usr/local/nachos/lib/gcc-lib/decstation-ultrix/2.95.2/cpp
# directory in which your gcc cross-compiler lives i.e.:
GCCDIR = ../../usr/local/nachos/bin/decstation-ultrix-
LDFLAGS = -T script -N
ASFLAGS = -mips2
CPPFLAGS = $(INCDIR)
COFF2NOFF = ../../coff2noff/coff2noff.x86Linux
hosttype = x86Linux
endif
ifeq ($(osname),Windows)
CPP = /usr/local/nachosxdev/lib/gcc-lib/decstation-ultrix/2.95.3/cpp0
# directory in which your gcc cross-compiler lives i.e.:
GCCDIR = /usr/local/nachosxdev/bin/decstation-ultrix-
LDFLAGS = -T script -N
ASFLAGS = -mips2
CPPFLAGS = $(INCDIR)
COFF2NOFF = ../../coff2noff/coff2noff.Windows
hosttype = Windows
endif
# Note:
# If you are trying to build on MacOS X
# try something like this, substituting whatever
# uname -s returns on your machine for the XXX
#
#ifeq ($(osname),XXX)
#CPP = full path name of your cpp program
#GCCDIR = directory in which your gcc cross-compiler lives
#LDFLAGS = -T script -N
#ASFLAGS = -mips2
#CPPFLAGS = $(INCDIR)
#COFF2NOFF = full pathname of your coff2noff program
# Note: it has been moved to part of the Nachos distribution
# COFF2NOFF = ../../coff2noff.mipsUltrix
#hosttype = MacOS
#endif

BIN
code/test/a Normal file

Binary file not shown.

BIN
code/test/add Normal file

Binary file not shown.

20
code/test/add.c Normal file
View File

@@ -0,0 +1,20 @@
/* add.c
* Simple program to test whether the systemcall interface works.
*
* Just do a add syscall that adds two values and returns the result.
*
*/
#include "syscall.h"
int
main()
{
int result;
result = Add(42, 23);
PrintInt(result);
// printf("result is %d\n", result);
Halt();
/* not reached */
}

BIN
code/test/consoleIO_test1 Normal file

Binary file not shown.

View File

@@ -0,0 +1,12 @@
#include "syscall.h"
int
main()
{
int n;
for (n=9;n>5;n--) {
PrintInt(n);
}
Halt();
}

BIN
code/test/consoleIO_test2 Normal file

Binary file not shown.

View File

@@ -0,0 +1,13 @@
#include "syscall.h"
int
main()
{
int n;
for (n=15;n<=19;n++){
PrintInt(n);
}
Halt();
}

BIN
code/test/fileIO_test1 Normal file

Binary file not shown.

20
code/test/fileIO_test1.c Normal file
View File

@@ -0,0 +1,20 @@
#include "syscall.h"
int main(void)
{
char test[] = "abcdefghijklmnopqrstuvwxyz";
int success = Create("file1.test");
OpenFileId fid;
int i;
if (success != 1) MSG("Failed on creating file");
fid = Open("file1.test");
if (fid == -1) MSG("Failed on opening file");
for (i = 0; i < 26; ++i) {
int count = Write(test + i, 1, fid);
if (count != 1) MSG("Failed on writing file");
}
success = Close(fid);
if (success != 1) MSG("Failed on closing file");
Halt();
}

BIN
code/test/fileIO_test2 Normal file

Binary file not shown.

22
code/test/fileIO_test2.c Normal file
View File

@@ -0,0 +1,22 @@
#include "syscall.h"
int main(void)
{
// you should run fileIO_test1 first before running this one
char test[26];
char check[] = "abcdefghijklmnopqrstuvwxyz";
OpenFileId fid;
int count, success, i;
fid = Open("file1.test");
if (fid == -1) MSG("Failed on opening file");
count = Read(test, 26, fid);
if (count != 26) MSG("Failed on reading file");
success = Close(fid);
if (success != 1) MSG("Failed on closing file");
for (i = 0; i < 26; ++i) {
if (test[i] != check[i]) MSG("Failed: reading wrong result");
}
MSG("Passed! ^_^");
Halt();
}

Some files were not shown because too many files have changed in this diff Show More