End of Lab1
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 23 Jan 2009 20:25:52 +0000 (12:25 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 23 Jan 2009 20:25:52 +0000 (12:25 -0800)
41 files changed:
.bochsrc [new file with mode: 0644]
CODING [new file with mode: 0644]
GNUmakefile [new file with mode: 0644]
boot/Makefrag [new file with mode: 0644]
boot/boot.S [new file with mode: 0644]
boot/main.c [new file with mode: 0644]
boot/sign.pl [new file with mode: 0644]
conf/env.mk [new file with mode: 0644]
conf/lab.mk [new file with mode: 0644]
inc/COPYRIGHT [new file with mode: 0644]
inc/assert.h [new file with mode: 0644]
inc/elf.h [new file with mode: 0644]
inc/error.h [new file with mode: 0644]
inc/kbdreg.h [new file with mode: 0644]
inc/malloc.h [new file with mode: 0644]
inc/memlayout.h [new file with mode: 0644]
inc/mmu.h [new file with mode: 0644]
inc/multiboot.h [new file with mode: 0644]
inc/queue.h [new file with mode: 0644]
inc/stab.h [new file with mode: 0644]
inc/stdarg.h [new file with mode: 0644]
inc/stdio.h [new file with mode: 0644]
inc/string.h [new file with mode: 0644]
inc/types.h [new file with mode: 0644]
inc/x86.h [new file with mode: 0644]
kern/COPYRIGHT [new file with mode: 0644]
kern/Makefrag [new file with mode: 0644]
kern/console.c [new file with mode: 0644]
kern/console.h [new file with mode: 0644]
kern/entry.S [new file with mode: 0644]
kern/init.c [new file with mode: 0644]
kern/kernel.ld [new file with mode: 0644]
kern/monitor.c [new file with mode: 0644]
kern/monitor.h [new file with mode: 0644]
kern/printf.c [new file with mode: 0644]
lib/printfmt.c [new file with mode: 0644]
lib/readline.c [new file with mode: 0644]
lib/string.c [new file with mode: 0644]
mergedep.pl [new file with mode: 0644]
user/testpmap.c [new file with mode: 0644]
user/user.ld [new file with mode: 0644]

diff --git a/.bochsrc b/.bochsrc
new file mode 100644 (file)
index 0000000..e00ba1b
--- /dev/null
+++ b/.bochsrc
@@ -0,0 +1,743 @@
+# You may now use double quotes around pathnames, in case
+# your pathname includes spaces.
+
+#=======================================================================
+# CONFIG_INTERFACE
+#
+# The configuration interface is a series of menus or dialog boxes that
+# allows you to change all the settings that control Bochs's behavior.
+# There are two choices of configuration interface: a text mode version
+# called "textconfig" and a graphical version called "wx".  The text
+# mode version uses stdin/stdout and is always compiled in.  The graphical
+# version is only available when you use "--with-wx" on the configure 
+# command.  If you do not write a config_interface line, Bochs will 
+# choose a default for you.
+#
+# NOTE: if you use the "wx" configuration interface, you must also use
+# the "wx" display library.
+#=======================================================================
+#config_interface: textconfig
+#config_interface: wx
+
+#=======================================================================
+# DISPLAY_LIBRARY
+#
+# The display library is the code that displays the Bochs VGA screen.  Bochs 
+# has a selection of about 10 different display library implementations for 
+# different platforms.  If you run configure with multiple --with-* options, 
+# the display_library command lets you choose which one you want to run with.
+# If you do not write a display_library line, Bochs will choose a default for
+# you.
+#
+# The choices are: 
+#   x              use X windows interface, cross platform
+#   win32          use native win32 libraries
+#   carbon         use Carbon library (for MacOS X)
+#   beos           use native BeOS libraries
+#   macintosh      use MacOS pre-10
+#   amigaos        use native AmigaOS libraries
+#   sdl            use SDL library, cross platform
+#   svga           use SVGALIB library for Linux, allows graphics without X11
+#   term           text only, uses curses/ncurses library, cross platform
+#   rfb            provides an interface to AT&T's VNC viewer, cross platform
+#   wx             use wxWidgets library, cross platform
+#   nogui          no display at all
+#
+# NOTE: if you use the "wx" configuration interface, you must also use
+# the "wx" display library.
+#
+# Specific options:
+# Some display libraries now support specific option to control their
+# behaviour. See the examples below for currently supported options.
+#=======================================================================
+#display_library: amigaos
+#display_library: beos
+#display_library: carbon
+#display_library: macintosh
+#display_library: nogui
+#display_library: rfb, options="timeout=60" # time to wait for client
+#display_library: sdl, options="fullscreen" # startup in fullscreen mode
+#display_library: term
+#display_library: win32, options="legacyF12" # use F12 to toggle mouse
+#display_library: wx
+#display_library: x
+
+#=======================================================================
+# ROMIMAGE:
+# The ROM BIOS controls what the PC does when it first powers on.
+# Normally, you can use a precompiled BIOS in the source or binary
+# distribution called BIOS-bochs-latest. The ROM BIOS is usually loaded
+# starting at address 0xf0000, and it is exactly 64k long.
+# You can also use the environment variable $BXSHARE to specify the
+# location of the BIOS.
+# The usage of external large BIOS images (up to 512k) at memory top is
+# now supported, but we still recommend to use the BIOS distributed with
+# Bochs. Now the start address can be calculated from image size.
+#=======================================================================
+# no longer necessary to specify the address with bochs 2.3.7
+romimage: file=$BXSHARE/BIOS-bochs-latest
+#romimage: file=$BXSHARE/BIOS-bochs-latest, address=0xf0000
+#romimage: file=mybios.bin, address=0xfff80000 # 512k at memory top
+#romimage: file=mybios.bin # calculate start address from image size
+
+#=======================================================================
+# CPU:
+# This defines cpu-related parameters inside Bochs:
+#
+#  COUNT:
+#  Set the number of processors when Bochs is compiled for SMP emulation.
+#  Bochs currently supports up to 8 processors. If Bochs is compiled
+#  without SMP support, it won't accept values different from 1.
+#
+#  IPS:
+#  Emulated Instructions Per Second.  This is the number of IPS that bochs
+#  is capable of running on your machine. You can recompile Bochs with
+#  --enable-show-ips option enabled, to find your workstation's capability.
+#  Measured IPS value will then be logged into your log file or status bar
+#  (if supported by the gui).
+#
+#  IPS is used to calibrate many time-dependent events within the bochs 
+#  simulation.  For example, changing IPS affects the frequency of VGA
+#  updates, the duration of time before a key starts to autorepeat, and
+#  the measurement of BogoMips and other benchmarks.
+#
+#  Examples:
+#  Machine                                         Mips
+# ________________________________________________________________
+#  2.1Ghz Athlon XP with Linux 2.6/g++ 3.4         12 to 15 Mips
+#  1.6Ghz Intel P4 with Win2000/g++ 3.3             5 to  7 Mips
+#  650Mhz Athlon K-7 with Linux 2.4.4/egcs-2.91.66  2 to  2.5 Mips
+#  400Mhz Pentium II with Linux 2.0.36/egcs-1.0.3   1 to  1.8 Mips
+#=======================================================================
+cpu: count=1, ips=10000000
+
+#=======================================================================
+# MEGS
+# Set the number of Megabytes of physical memory you want to emulate. 
+# The default is 32MB, most OS's won't need more than that.
+# The maximum amount of memory supported is 2048Mb.
+#=======================================================================
+#megs: 256
+#megs: 128
+#megs: 64
+megs: 32
+#megs: 16
+#megs: 8
+
+#=======================================================================
+# OPTROMIMAGE[1-4]:
+# You may now load up to 4 optional ROM images. Be sure to use a 
+# read-only area, typically between C8000 and EFFFF. These optional
+# ROM images should not overwrite the rombios (located at
+# F0000-FFFFF) and the videobios (located at C0000-C7FFF).
+# Those ROM images will be initialized by the bios if they contain 
+# the right signature (0x55AA) and a valid checksum.
+# It can also be a convenient way to upload some arbitrary code/data
+# in the simulation, that can be retrieved by the boot loader
+#=======================================================================
+#optromimage1: file=optionalrom.bin, address=0xd0000
+#optromimage2: file=optionalrom.bin, address=0xd1000
+#optromimage3: file=optionalrom.bin, address=0xd2000
+#optromimage4: file=optionalrom.bin, address=0xd3000
+
+#optramimage1: file=/path/file1.img, address=0x0010000
+#optramimage2: file=/path/file2.img, address=0x0020000
+#optramimage3: file=/path/file3.img, address=0x0030000
+#optramimage4: file=/path/file4.img, address=0x0040000
+
+#=======================================================================
+# VGAROMIMAGE
+# You now need to load a VGA ROM BIOS into C0000.
+#=======================================================================
+#vgaromimage: file=bios/VGABIOS-elpin-2.40
+vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest
+#vgaromimage: file=bios/VGABIOS-lgpl-latest-cirrus
+
+#=======================================================================
+# VGA:
+# Here you can specify the display extension to be used. With the value
+# 'none' you can use standard VGA with no extension. Other supported
+# values are 'vbe' for Bochs VBE and 'cirrus' for Cirrus SVGA support.
+#=======================================================================
+#vga: extension=cirrus
+#vga: extension=vbe
+vga: extension=none
+
+#=======================================================================
+# FLOPPYA:
+# Point this to pathname of floppy image file or device
+# This should be of a bootable floppy(image/device) if you're
+# booting from 'a' (or 'floppy').
+#
+# You can set the initial status of the media to 'ejected' or 'inserted'.
+#   floppya: 2_88=path, status=ejected             (2.88M 3.5" floppy)
+#   floppya: 1_44=path, status=inserted            (1.44M 3.5" floppy)
+#   floppya: 1_2=path, status=ejected              (1.2M  5.25" floppy)
+#   floppya: 720k=path, status=inserted            (720K  3.5" floppy)
+#   floppya: 360k=path, status=inserted            (360K  5.25" floppy)
+#   floppya: 320k=path, status=inserted            (320K  5.25" floppy)
+#   floppya: 180k=path, status=inserted            (180K  5.25" floppy)
+#   floppya: 160k=path, status=inserted            (160K  5.25" floppy)
+#   floppya: image=path, status=inserted           (guess type from image size)
+#
+# The path should be the name of a disk image file.  On Unix, you can use a raw
+# device name such as /dev/fd0 on Linux.  On win32 platforms, use drive letters
+# such as a: or b: as the path.  The parameter 'image' works with image files
+# only. In that case the size must match one of the supported types.
+#=======================================================================
+#floppya: 1_44=/dev/fd0, status=inserted
+#floppya: image=../1.44, status=inserted
+#floppya: 1_44=/dev/fd0H1440, status=inserted
+#floppya: 1_2=../1_2, status=inserted
+#floppya: 1_44=a:, status=inserted
+#floppya: 1_44=a.img, status=inserted
+#floppya: 1_44=/dev/rfd0a, status=inserted
+
+#=======================================================================
+# FLOPPYB:
+# See FLOPPYA above for syntax
+#=======================================================================
+#floppyb: 1_44=b:, status=inserted
+#floppyb: 1_44=b.img, status=inserted
+
+#=======================================================================
+# ATA0, ATA1, ATA2, ATA3
+# ATA controller for hard disks and cdroms
+#
+# ata[0-3]: enabled=[0|1], ioaddr1=addr, ioaddr2=addr, irq=number
+# 
+# These options enables up to 4 ata channels. For each channel
+# the two base io addresses and the irq must be specified.
+# 
+# ata0 and ata1 are enabled by default with the values shown below
+#
+# Examples:
+#   ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
+#   ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
+#   ata2: enabled=1, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
+#   ata3: enabled=1, ioaddr1=0x168, ioaddr2=0x360, irq=9
+#=======================================================================
+ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
+#ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
+#ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
+#ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
+
+#=======================================================================
+# ATA[0-3]-MASTER, ATA[0-3]-SLAVE
+#
+# This defines the type and characteristics of all attached ata devices:
+#   type=       type of attached device [disk|cdrom] 
+#   mode=       only valid for disks [flat|concat|external|dll|sparse|vmware3]
+#   mode=       only valid for disks [undoable|growing|volatile]
+#   path=       path of the image
+#   cylinders=  only valid for disks
+#   heads=      only valid for disks
+#   spt=        only valid for disks
+#   status=     only valid for cdroms [inserted|ejected]
+#   biosdetect= type of biosdetection [none|auto], only for disks on ata0 [cmos]
+#   translation=type of translation of the bios, only for disks [none|lba|large|rechs|auto]
+#   model=      string returned by identify device command
+#   journal=    optional filename of the redolog for undoable and volatile disks
+#   
+# Point this at a hard disk image file, cdrom iso file, or physical cdrom
+# device.  To create a hard disk image, try running bximage.  It will help you
+# choose the size and then suggest a line that works with it.
+#
+# In UNIX it may be possible to use a raw device as a Bochs hard disk, 
+# but WE DON'T RECOMMEND IT.  In Windows there is no easy way.
+#
+# In windows, the drive letter + colon notation should be used for cdroms.
+# Depending on versions of windows and drivers, you may only be able to 
+# access the "first" cdrom in the system.  On MacOSX, use path="drive"
+# to access the physical drive.
+#
+# The path is always mandatory. For flat hard disk images created with
+# bximage geometry autodetection can be used (cylinders=0 -> cylinders are
+# calculated using heads=16 and spt=63). For other hard disk images and modes
+# the cylinders, heads, and spt are mandatory.
+#
+# Default values are:
+#   mode=flat, biosdetect=auto, translation=auto, model="Generic 1234"
+#
+# The biosdetect option has currently no effect on the bios
+#
+# Examples:
+#   ata0-master: type=disk, mode=flat, path=10M.sample, cylinders=306, heads=4, spt=17
+#   ata0-slave:  type=disk, mode=flat, path=20M.sample, cylinders=615, heads=4, spt=17
+#   ata1-master: type=disk, mode=flat, path=30M.sample, cylinders=615, heads=6, spt=17
+#   ata1-slave:  type=disk, mode=flat, path=46M.sample, cylinders=940, heads=6, spt=17
+#   ata2-master: type=disk, mode=flat, path=62M.sample, cylinders=940, heads=8, spt=17
+#   ata2-slave:  type=disk, mode=flat, path=112M.sample, cylinders=900, heads=15, spt=17
+#   ata3-master: type=disk, mode=flat, path=483M.sample, cylinders=1024, heads=15, spt=63
+#   ata3-slave:  type=cdrom, path=iso.sample, status=inserted
+#=======================================================================
+#ata0-master: type=disk, mode=flat, path="./obj/kern/bochs.img", cylinders=100, heads=10, spt=10
+ata0-master: type=disk, mode=flat, path="./mnt/hdd.img", cylinders=1, heads=255, spt=63
+
+#=======================================================================
+# BOOT:
+# This defines the boot sequence. Now you can specify up to 3 boot drives.
+# You can either boot from 'floppy', 'disk' or 'cdrom'
+# legacy 'a' and 'c' are also supported
+# Examples:
+#   boot: floppy
+#   boot: disk
+#   boot: cdrom
+#   boot: c
+#   boot: a
+#   boot: cdrom, floppy, disk
+#=======================================================================
+#boot: floppy
+boot: disk
+
+#=======================================================================
+# CLOCK:
+# This defines the parameters of the clock inside Bochs:
+#
+#  SYNC:
+#  TO BE COMPLETED (see Greg explanation in feature request #536329)
+#
+#  TIME0:
+#  Specifies the start (boot) time of the virtual machine. Use a time 
+#  value as returned by the time(2) system call. If no time0 value is 
+#  set or if time0 equal to 1 (special case) or if time0 equal 'local', 
+#  the simulation will be started at the current local host time.
+#  If time0 equal to 2 (special case) or if time0 equal 'utc',
+#  the simulation will be started at the current utc time.
+#
+# Syntax:
+#  clock: sync=[none|slowdown|realtime|both], time0=[timeValue|local|utc]
+#
+# Example:
+#   clock: sync=none,     time0=local       # Now (localtime)
+#   clock: sync=slowdown, time0=315529200   # Tue Jan  1 00:00:00 1980
+#   clock: sync=none,     time0=631148400   # Mon Jan  1 00:00:00 1990
+#   clock: sync=realtime, time0=938581955   # Wed Sep 29 07:12:35 1999
+#   clock: sync=realtime, time0=946681200   # Sat Jan  1 00:00:00 2000
+#   clock: sync=none,     time0=1           # Now (localtime)
+#   clock: sync=none,     time0=utc         # Now (utc/gmt)
+# 
+# Default value are sync=none, time0=local
+#=======================================================================
+#clock: sync=none, time0=local
+clock: sync=realtime, time0=local
+
+
+#=======================================================================
+# FLOPPY_BOOTSIG_CHECK: disabled=[0|1]
+# Enables or disables the 0xaa55 signature check on boot floppies
+# Defaults to disabled=0
+# Examples:
+#   floppy_bootsig_check: disabled=0
+#   floppy_bootsig_check: disabled=1
+#=======================================================================
+#floppy_bootsig_check: disabled=1
+floppy_bootsig_check: disabled=0
+
+#=======================================================================
+# LOG:
+# Give the path of the log file you'd like Bochs debug and misc. verbiage
+# to be written to. If you don't use this option or set the filename to
+# '-' the output is written to the console. If you really don't want it,
+# make it "/dev/null" (Unix) or "nul" (win32). :^(
+#
+# Examples:
+#   log: ./bochs.out
+#   log: /dev/tty
+#=======================================================================
+#log: /dev/null
+log: bochs.log
+
+#=======================================================================
+# LOGPREFIX:
+# This handles the format of the string prepended to each log line.
+# You may use those special tokens :
+#   %t : 11 decimal digits timer tick
+#   %i : 8 hexadecimal digits of cpu current eip (ignored in SMP configuration)
+#   %e : 1 character event type ('i'nfo, 'd'ebug, 'p'anic, 'e'rror)
+#   %d : 5 characters string of the device, between brackets
+# 
+# Default : %t%e%d
+# Examples:
+#   logprefix: %t-%e-@%i-%d
+#   logprefix: %i%e%d
+#=======================================================================
+#logprefix: %t%e%d
+
+#=======================================================================
+# LOG CONTROLS
+#
+# Bochs now has four severity levels for event logging.
+#   panic: cannot proceed.  If you choose to continue after a panic, 
+#          don't be surprised if you get strange behavior or crashes.
+#   error: something went wrong, but it is probably safe to continue the
+#          simulation.
+#   info: interesting or useful messages.
+#   debug: messages useful only when debugging the code.  This may
+#          spit out thousands per second.
+#
+# For events of each level, you can choose to crash, report, or ignore.
+# TODO: allow choice based on the facility: e.g. crash on panics from
+#       everything except the cdrom, and only report those.
+#
+# If you are experiencing many panics, it can be helpful to change
+# the panic action to report instead of fatal.  However, be aware
+# that anything executed after a panic is uncharted territory and can 
+# cause bochs to become unstable.  The panic is a "graceful exit," so
+# if you disable it you may get a spectacular disaster instead.
+#=======================================================================
+panic: action=ask
+error: action=report
+info: action=ignore
+debug: action=ignore
+#pass: action=fatal
+
+#=======================================================================
+# DEBUGGER_LOG:
+# Give the path of the log file you'd like Bochs to log debugger output.
+# If you really don't want it, make it /dev/null or '-'. :^(
+#
+# Examples:
+#   debugger_log: ./debugger.out
+#=======================================================================
+#debugger_log: /dev/null
+#debugger_log: debugger.out
+debugger_log: -
+
+#=======================================================================
+# COM1, COM2, COM3, COM4:
+# This defines a serial port (UART type 16550A). In the 'term' you can specify
+# a device to use as com1. This can be a real serial line, or a pty.  To use
+# a pty (under X/Unix), create two windows (xterms, usually).  One of them will
+# run bochs, and the other will act as com1. Find out the tty the com1
+# window using the `tty' command, and use that as the `dev' parameter.
+# Then do `sleep 1000000' in the com1 window to keep the shell from
+# messing with things, and run bochs in the other window.  Serial I/O to
+# com1 (port 0x3f8) will all go to the other window.
+# Other serial modes are 'null' (no input/output), 'file' (output to a file
+# specified as the 'dev' parameter), 'raw' (use the real serial port - under
+# construction for win32), 'mouse' (standard serial mouse - requires
+# mouse option setting 'type=serial' or 'type=serial_wheel') and 'socket'
+# (connect a networking socket).
+#
+# Examples:
+#   com1: enabled=1, mode=null
+#   com1: enabled=1, mode=mouse
+#   com2: enabled=1, mode=file, dev=serial.out
+#   com3: enabled=1, mode=raw, dev=com1
+#   com3: enabled=1, mode=socket, dev=localhost:8888
+#=======================================================================
+#com1: enabled=1, mode=term, dev=/dev/ttyp9
+
+
+#=======================================================================
+# PARPORT1, PARPORT2:
+# This defines a parallel (printer) port. When turned on and an output file is
+# defined the emulated printer port sends characters printed by the guest OS
+# into the output file. On some platforms a device filename can be used to
+# send the data to the real parallel port (e.g. "/dev/lp0" on Linux, "lpt1" on
+# win32 platforms).
+#
+# Examples:
+#   parport1: enabled=1, file="parport.out"
+#   parport2: enabled=1, file="/dev/lp0"
+#   parport1: enabled=0
+#=======================================================================
+parport1: enabled=1, file="/dev/stdout"
+
+#=======================================================================
+# SB16:
+# This defines the SB16 sound emulation. It can have several of the
+# following properties.
+# All properties are in the format sb16: property=value
+# midi: The filename is where the midi data is sent. This can be a
+#       device or just a file if you want to record the midi data.
+# midimode:
+#      0=no data
+#      1=output to device (system dependent. midi denotes the device driver)
+#      2=SMF file output, including headers
+#      3=output the midi data stream to the file (no midi headers and no
+#        delta times, just command and data bytes)
+# wave: This is the device/file where wave output is stored
+# wavemode:
+#      0=no data
+#      1=output to device (system dependent. wave denotes the device driver)
+#      2=VOC file output, incl. headers
+#      3=output the raw wave stream to the file
+# log:  The file to write the sb16 emulator messages to.
+# loglevel:
+#      0=no log
+#      1=resource changes, midi program and bank changes
+#      2=severe errors
+#      3=all errors
+#      4=all errors plus all port accesses
+#      5=all errors and port accesses plus a lot of extra info
+# dmatimer:
+#      microseconds per second for a DMA cycle.  Make it smaller to fix
+#      non-continuous sound.  750000 is usually a good value.  This needs a
+#      reasonably correct setting for the IPS parameter of the CPU option.
+#
+# For an example look at the next line:
+#=======================================================================
+
+#sb16: midimode=1, midi=/dev/midi00, wavemode=1, wave=/dev/dsp, loglevel=2, log=sb16.log, dmatimer=600000
+
+#=======================================================================
+# VGA_UPDATE_INTERVAL:
+# Video memory is scanned for updates and screen updated every so many
+# virtual seconds.  The default is 40000, about 25Hz. Keep in mind that
+# you must tweak the 'cpu: ips=N' directive to be as close to the number
+# of emulated instructions-per-second your workstation can do, for this
+# to be accurate.
+#
+# Examples:
+#   vga_update_interval: 250000
+#=======================================================================
+vga_update_interval: 300000
+
+# using for Winstone '98 tests
+#vga_update_interval:  100000
+
+#=======================================================================
+# KEYBOARD_SERIAL_DELAY:
+# Approximate time in microseconds that it takes one character to
+# be transfered from the keyboard to controller over the serial path.
+# Examples:
+#   keyboard_serial_delay: 200
+#=======================================================================
+keyboard_serial_delay: 250
+
+#=======================================================================
+# KEYBOARD_PASTE_DELAY:
+# Approximate time in microseconds between attempts to paste
+# characters to the keyboard controller. This leaves time for the
+# guest os to deal with the flow of characters.  The ideal setting
+# depends on how your operating system processes characters.  The
+# default of 100000 usec (.1 seconds) was chosen because it works 
+# consistently in Windows.
+#
+# If your OS is losing characters during a paste, increase the paste
+# delay until it stops losing characters.
+#
+# Examples:
+#   keyboard_paste_delay: 100000
+#=======================================================================
+keyboard_paste_delay: 100000
+
+#=======================================================================
+# MOUSE: 
+# This option prevents Bochs from creating mouse "events" unless a mouse
+# is  enabled. The hardware emulation itself is not disabled by this.
+# You can turn the mouse on by setting enabled to 1, or turn it off by
+# setting enabled to 0. Unless you have a particular reason for enabling
+# the mouse by default, it is recommended that you leave it off.
+# You can also toggle the mouse usage at runtime (control key + middle
+# mouse button on X11, SDL, wxWidgets and Win32).
+# With the mouse type option you can select the type of mouse to emulate.
+# The default value is 'ps2'. The other choices are 'imps2' (wheel mouse
+# on PS/2), 'serial', 'serial_wheel' (one com port requires setting
+# 'mode=mouse') and 'usb' (3-button mouse - one of the USB ports must be
+# connected with the 'mouse' device - requires PCI and USB support).
+#
+# Examples:
+#   mouse: enabled=1
+#   mouse: enabled=1, type=imps2
+#   mouse: enabled=1, type=serial
+#   mouse: enabled=0
+#=======================================================================
+mouse: enabled=0
+
+#=======================================================================
+# private_colormap: Request that the GUI create and use it's own
+#                   non-shared colormap.  This colormap will be used
+#                   when in the bochs window.  If not enabled, a
+#                   shared colormap scheme may be used.  Not implemented
+#                   on all GUI's.
+#
+# Examples:
+#   private_colormap: enabled=1
+#   private_colormap: enabled=0
+#=======================================================================
+private_colormap: enabled=0
+
+#=======================================================================
+# fullscreen: ONLY IMPLEMENTED ON AMIGA
+#             Request that Bochs occupy the entire screen instead of a 
+#             window.
+#
+# Examples:
+#   fullscreen: enabled=0
+#   fullscreen: enabled=1
+#=======================================================================
+#fullscreen: enabled=0
+#screenmode: name="sample"
+
+#=======================================================================
+# ne2k: NE2000 compatible ethernet adapter
+#
+# Examples:
+# ne2k: ioaddr=IOADDR, irq=IRQ, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT
+#
+# ioaddr, irq: You probably won't need to change ioaddr and irq, unless there
+# are IRQ conflicts.
+#
+# mac: The MAC address MUST NOT match the address of any machine on the net.
+# Also, the first byte must be an even number (bit 0 set means a multicast
+# address), and you cannot use ff:ff:ff:ff:ff:ff because that's the broadcast
+# address.  For the ethertap module, you must use fe:fd:00:00:00:01.  There may
+# be other restrictions too.  To be safe, just use the b0:c4... address.
+#
+# ethdev: The ethdev value is the name of the network interface on your host
+# platform.  On UNIX machines, you can get the name by running ifconfig.  On
+# Windows machines, you must run niclist to get the name of the ethdev.
+# Niclist source code is in misc/niclist.c and it is included in Windows 
+# binary releases.
+#
+# script: The script value is optional, and is the name of a script that 
+# is executed after bochs initialize the network interface. You can use 
+# this script to configure this network interface, or enable masquerading.
+# This is mainly useful for the tun/tap devices that only exist during
+# Bochs execution. The network interface name is supplied to the script
+# as first parameter
+#
+# If you don't want to make connections to any physical networks,
+# you can use the following 'ethmod's to simulate a virtual network.
+#   null: All packets are discarded, but logged to a few files.
+#   arpback: ARP is simulated. Disabled by default.
+#   vde:  Virtual Distributed Ethernet
+#   vnet: ARP, ICMP-echo(ping), DHCP and read/write TFTP are simulated.
+#         The virtual host uses 192.168.10.1.
+#         DHCP assigns 192.168.10.2 to the guest.
+#         TFTP uses the ethdev value for the root directory and doesn't
+#         overwrite files.
+#
+#=======================================================================
+# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=fbsd, ethdev=en0 #macosx
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=fbsd, ethdev=xl0
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=win32, ethdev=MYCARD
+# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0
+# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun0, script=./tunconfig
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=null, ethdev=eth0
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=vde, ethdev="/tmp/vde.ctl"
+# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=vnet, ethdev="c:/temp"
+
+#=======================================================================
+# KEYBOARD_MAPPING:
+# This enables a remap of a physical localized keyboard to a 
+# virtualized us keyboard, as the PC architecture expects.
+# If enabled, the keymap file must be specified.
+# 
+# Examples:
+#   keyboard_mapping: enabled=1, map=gui/keymaps/x11-pc-de.map
+#=======================================================================
+keyboard_mapping: enabled=0, map=
+
+#=======================================================================
+# KEYBOARD_TYPE:
+# Type of keyboard return by a "identify keyboard" command to the
+# keyboard controler. It must be one of "xt", "at" or "mf".
+# Defaults to "mf". It should be ok for almost everybody. A known
+# exception is french macs, that do have a "at"-like keyboard.
+#
+# Examples:
+#   keyboard_type: mf
+#=======================================================================
+#keyboard_type: mf
+
+#=======================================================================
+# USER_SHORTCUT:
+# This defines the keyboard shortcut to be sent when you press the "user"
+# button in the headerbar. The shortcut string is a combination of maximum
+# 3 key names (listed below) separated with a '-' character. The old-style
+# syntax (without the '-') still works for the key combinations supported
+# in Bochs 2.2.1.
+# Valid key names:
+# "alt", "bksl", "bksp", "ctrl", "del", "down", "end", "enter", "esc",
+# "f1", ... "f12", "home", "ins", "left", "menu", "minus", "pgdwn", "pgup",
+# "plus", "right", "shift", "space", "tab", "up", and "win".
+#
+# Example:
+#   user_shortcut: keys=ctrl-alt-del
+#=======================================================================
+#user_shortcut: keys=ctrl-alt-del
+
+#=======================================================================
+# I440FXSUPPORT:
+# This option controls the presence of the i440FX PCI chipset. You can
+# also specify the devices connected to PCI slots. Up to 5 slots are
+# available now. These devices are currently supported: ne2k, pcivga,
+# pcidev and pcipnic. If Bochs is compiled with Cirrus SVGA support
+# you'll have the additional choice 'cirrus'.
+#
+# Example:
+#   i440fxsupport: enabled=1, slot1=pcivga, slot2=ne2k
+#=======================================================================
+#i440fxsupport: enabled=1
+
+#=======================================================================
+# USB1:
+# This option controls the presence of the USB root hub which is a part
+# of the i440FX PCI chipset. With the portX option you can connect devices
+# to the hub (currently supported: 'mouse' and 'keypad'). If you connect
+# the mouse to one of the ports and use the mouse option 'type=usb' you'll
+# have a 3-button USB mouse.
+#
+# Example:
+#   usb1: enabled=1, port1=mouse, port2=keypad
+#=======================================================================
+#usb1: enabled=1
+
+#=======================================================================
+# CMOSIMAGE:
+# This defines image file that can be loaded into the CMOS RAM at startup.
+# The rtc_init parameter controls whether initialize the RTC with values stored
+# in the image. By default the time0 argument given to the clock option is used.
+# With 'rtc_init=image' the image is the source for the initial time.
+#
+# Example:
+#   cmosimage: file=cmos.img, rtc_init=image
+#=======================================================================
+#cmosimage: file=cmos.img, rtc_init=time0
+
+#=======================================================================
+# other stuff
+#=======================================================================
+#magic_break: enabled=1
+#load32bitOSImage: os=nullkernel, path=../kernel.img, iolog=../vga_io.log
+#load32bitOSImage: os=linux, path=../linux.img, iolog=../vga_io.log, initrd=../initrd.img
+#text_snapshot_check: enable
+
+#-------------------------
+# PCI host device mapping
+#-------------------------
+#pcidev: vendor=0x1234, device=0x5678
+
+#=======================================================================
+# GDBSTUB:
+# Enable GDB stub. See user documentation for details.
+# Default value is enabled=0.
+#=======================================================================
+#gdbstub: enabled=0, port=1234, text_base=0, data_base=0, bss_base=0
+# and then connect with gdb:
+# $ gdb YOUR-KERNEL
+# .
+# .
+# .
+# (gdb) target remote localhost:1234
+
+#=======================================================================
+# IPS:
+# The IPS directive is DEPRECATED. Use the parameter IPS of the CPU
+# directive instead.
+#=======================================================================
+#ips: 10000000
+
+#=======================================================================
+# for Macintosh, use the style of pathnames in the following
+# examples.
+#
+# vgaromimage: :bios:VGABIOS-elpin-2.40
+# romimage: file=:bios:BIOS-bochs-latest, address=0xf0000
+# floppya: 1_44=[fd:], status=inserted
+#=======================================================================
diff --git a/CODING b/CODING
new file mode 100644 (file)
index 0000000..55d11d7
--- /dev/null
+++ b/CODING
@@ -0,0 +1,35 @@
+JOS CODING STANDARDS
+
+It's easier on everyone if all authors working on a shared
+code base are consistent in the way they write their programs.
+We have the following conventions in our code:
+
+* No space after the name of a function in a call
+  For example, printf("hello") not printf ("hello").
+
+* One space after keywords "if", "for", "while", "switch".
+  For example, if (x) not if(x).
+
+* Space before braces.
+  For example, if (x) { not if (x){.
+
+* Function names are all lower-case separated by underscores.
+
+* Beginning-of-line indentation via tabs, not spaces.
+
+* Preprocessor macros are always UPPERCASE.
+  There are a few grandfathered exceptions: assert, panic,
+  static_assert, offsetof.
+
+* Pointer types have spaces: (uint16_t *) not (uint16_t*).
+
+* Multi-word names are lower_case_with_underscores.
+
+* Comments in imported code are usually C /* ... */ comments.
+  Comments in new code are C++ style //.
+
+* In a function definition, the function name starts a new line.
+  Then you can grep -n '^foo' */*.c to find the definition of foo.
+
+* Functions that take no arguments are declared f(void) not f().
+
diff --git a/GNUmakefile b/GNUmakefile
new file mode 100644 (file)
index 0000000..b223c43
--- /dev/null
@@ -0,0 +1,156 @@
+#
+# This makefile system follows the structuring conventions
+# recommended by Peter Miller in his excellent paper:
+#
+#      Recursive Make Considered Harmful
+#      http://aegis.sourceforge.net/auug97.pdf
+#
+OBJDIR := obj
+
+ifdef LAB
+SETTINGLAB := true
+else
+-include conf/lab.mk
+endif
+
+-include conf/env.mk
+
+ifndef SOL
+SOL := 0
+endif
+ifndef LABADJUST
+LABADJUST := 0
+endif
+
+ifndef LABSETUP
+LABSETUP := ./
+endif
+
+
+TOP = .
+
+# Cross-compiler jos toolchain
+#
+# This Makefile will automatically use the cross-compiler toolchain
+# installed as 'i386-jos-elf-*', if one exists.  If the host tools ('gcc',
+# 'objdump', and so forth) compile for a 32-bit x86 ELF target, that will
+# be detected as well.  If you have the right compiler toolchain installed
+# using a different name, set GCCPREFIX explicitly in conf/env.mk
+
+# try to infer the correct GCCPREFIX
+ifndef GCCPREFIX
+GCCPREFIX := $(shell if i386-jos-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; \
+       then echo 'i386-jos-elf-'; \
+       elif objdump -i 2>&1 | grep 'elf32-i386' >/dev/null 2>&1; \
+       then echo ''; \
+       else echo "***" 1>&2; \
+       echo "*** Error: Couldn't find an i386-*-elf version of GCC/binutils." 1>&2; \
+       echo "*** Is the directory with i386-jos-elf-gcc in your PATH?" 1>&2; \
+       echo "*** If your i386-*-elf toolchain is installed with a command" 1>&2; \
+       echo "*** prefix other than 'i386-jos-elf-', set your GCCPREFIX" 1>&2; \
+       echo "*** environment variable to that prefix and run 'make' again." 1>&2; \
+       echo "*** To turn off this error, run 'gmake GCCPREFIX= ...'." 1>&2; \
+       echo "***" 1>&2; exit 1; fi)
+endif
+
+CC     := $(GCCPREFIX)gcc -pipe
+GCC_LIB := $(shell $(CC) -print-libgcc-file-name)
+AS     := $(GCCPREFIX)as
+AR     := $(GCCPREFIX)ar
+LD     := $(GCCPREFIX)ld
+OBJCOPY        := $(GCCPREFIX)objcopy
+OBJDUMP        := $(GCCPREFIX)objdump
+NM     := $(GCCPREFIX)nm
+
+# Native commands
+NCC    := gcc $(CC_VER) -pipe
+TAR    := gtar
+PERL   := perl
+
+# Compiler flags
+# -fno-builtin is required to avoid refs to undefined functions in the kernel.
+# Only optimize to -O1 to discourage inlining, which complicates backtraces.
+CFLAGS := $(CFLAGS) $(DEFS) $(LABDEFS) -O -fno-builtin -I$(TOP) -MD -Wall -Wno-format -Wno-unused -Werror -gstabs
+
+# Linker flags for JOS user programs
+ULDFLAGS := -T user/user.ld
+
+# Lists that the */Makefrag makefile fragments will add to
+OBJDIRS :=
+
+# Make sure that 'all' is the first target
+all:
+
+# Eliminate default suffix rules
+.SUFFIXES:
+
+# Delete target files if there is an error (or make is interrupted)
+.DELETE_ON_ERROR:
+
+# make it so that no intermediate .o files are ever deleted
+.PRECIOUS: %.o $(OBJDIR)/boot/%.o $(OBJDIR)/kern/%.o \
+       $(OBJDIR)/lib/%.o $(OBJDIR)/fs/%.o $(OBJDIR)/user/%.o
+
+KERN_CFLAGS := $(CFLAGS) -DJOS_KERNEL -gstabs
+USER_CFLAGS := $(CFLAGS) -DJOS_USER -gstabs
+
+
+
+
+# Include Makefrags for subdirectories
+include boot/Makefrag
+include kern/Makefrag
+
+
+IMAGES = $(OBJDIR)/kern/bochs.img
+
+bochs: $(IMAGES)
+       bochs 'display_library: nogui'
+
+# For deleting the build
+clean:
+       rm -rf $(OBJDIR)
+
+realclean: clean
+       rm -rf lab$(LAB).tar.gz bochs.out bochs.log
+
+distclean: realclean
+       rm -rf conf/gcc.mk
+
+grade: $(LABSETUP)grade.sh
+       $(V)$(MAKE) clean >/dev/null 2>/dev/null
+       $(MAKE) all
+       sh $(LABSETUP)grade.sh
+
+handin: tarball
+       turnin --submit porterde cs372h-lab$(LAB) lab$(LAB)-handin.tar.gz
+
+tarball: realclean
+       tar cf - `find . -type f | grep -v '^\.*$$' | grep -v '/CVS/' | grep -v '/\.svn/' | grep -v 'lab[0-9].*\.tar\.gz'` | gzip > lab$(LAB)-handin.tar.gz
+
+# For test runs
+run-%:
+       $(V)rm -f $(OBJDIR)/kern/init.o $(IMAGES)
+       $(V)$(MAKE) "DEFS=-DTEST=_binary_obj_user_$*_start -DTESTSIZE=_binary_obj_user_$*_size" $(IMAGES)
+       bochs -q 'display_library: nogui'
+
+xrun-%:
+       $(V)rm -f $(OBJDIR)/kern/init.o $(IMAGES)
+       $(V)$(MAKE) "DEFS=-DTEST=_binary_obj_user_$*_start -DTESTSIZE=_binary_obj_user_$*_size" $(IMAGES)
+       bochs -q
+
+# This magic automatically generates makefile dependencies
+# for header files included from C source files we compile,
+# and keeps those dependencies up-to-date every time we recompile.
+# See 'mergedep.pl' for more information.
+$(OBJDIR)/.deps: $(foreach dir, $(OBJDIRS), $(wildcard $(OBJDIR)/$(dir)/*.d))
+       @mkdir -p $(@D)
+       @$(PERL) mergedep.pl $@ $^
+
+-include $(OBJDIR)/.deps
+
+always:
+       @:
+
+.PHONY: all always \
+       handin tarball clean realclean clean-labsetup distclean grade labsetup
diff --git a/boot/Makefrag b/boot/Makefrag
new file mode 100644 (file)
index 0000000..843e932
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# Makefile fragment for the JOS kernel.
+# This is NOT a complete makefile;
+# you must run GNU make in the top-level directory
+# where the GNUmakefile is located.
+#
+
+OBJDIRS += boot
+
+BOOT_OBJS := $(OBJDIR)/boot/boot.o $(OBJDIR)/boot/main.o
+
+$(OBJDIR)/boot/%.o: boot/%.c
+       @echo + cc -Os $<
+       @mkdir -p $(@D)
+       $(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $@ $<
+
+$(OBJDIR)/boot/%.o: boot/%.S
+       @echo + as $<
+       @mkdir -p $(@D)
+       $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $<
+
+$(OBJDIR)/boot/main.o: boot/main.c
+       @echo + cc -Os $<
+       $(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $(OBJDIR)/boot/main.o boot/main.c
+
+$(OBJDIR)/boot/boot: $(BOOT_OBJS)
+       @echo + ld boot/boot
+       $(V)$(LD) -N -e start -Ttext 0x7C00 -o $@.out $^
+       $(V)$(OBJDUMP) -S $@.out >$@.asm
+       $(V)$(OBJCOPY) -S -O binary $@.out $@
+       $(V)perl boot/sign.pl $(OBJDIR)/boot/boot
+
diff --git a/boot/boot.S b/boot/boot.S
new file mode 100644 (file)
index 0000000..5ad119d
--- /dev/null
@@ -0,0 +1,98 @@
+#include <inc/mmu.h>
+       
+.set PROT_MODE_CSEG,0x8                # code segment selector
+.set PROT_MODE_DSEG,0x10        # data segment selector
+.set CR0_PE_ON,0x1             # protected mode enable flag
+       
+###############################################################################
+# ENTRY POINT  
+#   This code should be stored in the first sector of the hard disk.
+#   After the BIOS initializes the hardware on startup or system reset,
+#   it loads this code at physical address 0x7c00 - 0x7d00 (512 bytes).
+#   Then the BIOS jumps to the beginning of it, address 0x7c00,
+#   while running in 16-bit real-mode (8086 compatibility mode).
+#   The Code Segment register (CS) is initially zero on entry.
+#      
+# This code switches into 32-bit protected mode so that all of
+# memory can accessed, then calls into C.
+###############################################################################
+       
+.globl start                                   # Entry point   
+start:         .code16                         # This runs in real mode
+               cli                             # Disable interrupts
+               cld                             # String operations increment
+
+               # Set up the important data segment registers (DS, ES, SS).
+               xorw    %ax,%ax                 # Segment number zero
+               movw    %ax,%ds                 # -> Data Segment
+               movw    %ax,%es                 # -> Extra Segment
+               movw    %ax,%ss                 # -> Stack Segment
+
+               # Set up the stack pointer, growing downward from 0x7c00.
+               movw    $start,%sp              # Stack Pointer
+       
+# Enable A20:
+#   For fascinating historical reasons (related to the fact that
+#   the earliest 8086-based PCs could only address 1MB of physical memory
+#   and subsequent 80286-based PCs wanted to retain maximum compatibility),
+#   physical address line 20 is tied to low when the machine boots.
+#   Obviously this a bit of a drag for us, especially when trying to
+#   address memory above 1MB.  This code undoes this.
+       
+seta20.1:      inb     $0x64,%al               # Get status
+               testb   $0x2,%al                # Busy?
+               jnz     seta20.1                # Yes
+               movb    $0xd1,%al               # Command: Write
+               outb    %al,$0x64               #  output port
+seta20.2:      inb     $0x64,%al               # Get status
+               testb   $0x2,%al                # Busy?
+               jnz     seta20.2                # Yes
+               movb    $0xdf,%al               # Enable
+               outb    %al,$0x60               #  A20
+
+# Switch from real to protected mode:
+#   Up until now, there's been no protection, so we've gotten along perfectly
+#   well without explicitly telling the processor how to translate addresses.
+#   When we switch to protected mode, this is no longer true!
+#   We need at least to set up some "segments" that tell the processor it's
+#   OK to run code at any address, or write to any address.
+#   The 'gdt' and 'gdtdesc' tables below define these segments.
+#   This code loads them into the processor.
+#   We need this setup to ensure the transition to protected mode is smooth.
+
+real_to_prot:  cli                     # Don't allow interrupts: mandatory,
+                                       # since we didn't set up an interrupt
+                                       # descriptor table for handling them
+               lgdt    gdtdesc         # load GDT: mandatory in protected mode
+               movl    %cr0, %eax      # Turn on protected mode
+               orl     $CR0_PE_ON, %eax
+               movl    %eax, %cr0
+
+               # CPU magic: jump to relocation, flush prefetch queue, and
+               # reload %cs.  Has the effect of just jmp to the next
+               # instruction, but simultaneously loads CS with
+               # $PROT_MODE_CSEG.
+               ljmp    $PROT_MODE_CSEG, $protcseg
+       
+               # we've switched to 32-bit protected mode; tell the assembler
+               # to generate code for that mode
+protcseg:      .code32
+               # Set up the protected-mode data segment registers
+               movw    $PROT_MODE_DSEG, %ax    # Our data segment selector
+               movw    %ax, %ds                # -> DS: Data Segment
+               movw    %ax, %es                # -> ES: Extra Segment
+               movw    %ax, %fs                # -> FS
+               movw    %ax, %gs                # -> GS
+               movw    %ax, %ss                # -> SS: Stack Segment
+       
+               call cmain                      # finish the boot load from C.
+                                               # cmain() should not return
+spin:          jmp spin                        # ..but in case it does, spin
+       
+               .p2align 2                      # force 4 byte alignment
+gdt:           SEG_NULL                                # null seg
+               SEG(STA_X|STA_R, 0x0, 0xffffffff)       # code seg
+               SEG(STA_W, 0x0, 0xffffffff)             # data seg
+       
+gdtdesc:       .word   0x17                    # sizeof(gdt) - 1
+               .long   gdt                     # address gdt
diff --git a/boot/main.c b/boot/main.c
new file mode 100644 (file)
index 0000000..d828a04
--- /dev/null
@@ -0,0 +1,120 @@
+#include <inc/x86.h>
+#include <inc/elf.h>
+
+/**********************************************************************
+ * This a dirt simple boot loader, whose sole job is to boot
+ * an elf kernel image from the first IDE hard disk.
+ *
+ * DISK LAYOUT
+ *  * This program(boot.S and main.c) is the bootloader.  It should
+ *    be stored in the first sector of the disk.
+ * 
+ *  * The 2nd sector onward holds the kernel image.
+ *     
+ *  * The kernel image must be in ELF format.
+ *
+ * BOOT UP STEPS       
+ *  * when the CPU boots it loads the BIOS into memory and executes it
+ *
+ *  * the BIOS intializes devices, sets of the interrupt routines, and
+ *    reads the first sector of the boot device(e.g., hard-drive) 
+ *    into memory and jumps to it.
+ *
+ *  * Assuming this boot loader is stored in the first sector of the
+ *    hard-drive, this code takes over...
+ *
+ *  * control starts in bootloader.S -- which sets up protected mode,
+ *    and a stack so C code then run, then calls cmain()
+ *
+ *  * cmain() in this file takes over, reads in the kernel and jumps to it.
+ **********************************************************************/
+
+#define SECTSIZE       512
+#define ELFHDR         ((struct Elf *) 0x10000) // scratch space
+
+void readsect(void*, uint32_t);
+void readseg(uint32_t, uint32_t, uint32_t);
+
+void
+cmain(void)
+{
+       struct Proghdr *ph, *eph;
+
+       // read 1st page off disk
+       readseg((uint32_t) ELFHDR, SECTSIZE*8, 0);
+
+       // is this a valid ELF?
+       if (ELFHDR->e_magic != ELF_MAGIC)
+               goto bad;
+
+       // load each program segment (ignores ph flags)
+       ph = (struct Proghdr *) ((uint8_t *) ELFHDR + ELFHDR->e_phoff);
+       eph = ph + ELFHDR->e_phnum;
+       for (; ph < eph; ph++)
+               readseg(ph->p_va, ph->p_memsz, ph->p_offset);
+
+       // call the entry point from the ELF header
+       // note: does not return!
+       ((void (*)(void)) (ELFHDR->e_entry & 0x0FFFFFFF))();
+
+bad:
+       outw(0x8A00, 0x8A00);
+       outw(0x8A00, 0x8E00);
+       while (1)
+               /* do nothing */;
+}
+
+// Read 'count' bytes at 'offset' from kernel into virtual address 'va'.
+// Might copy more than asked
+void
+readseg(uint32_t va, uint32_t count, uint32_t offset)
+{
+       uint32_t end_va;
+
+       va &= 0x0FFFFFFF;
+       end_va = va + count;
+       
+       // round down to sector boundary
+       va &= ~(SECTSIZE - 1);
+
+       // translate from bytes to sectors, and kernel starts at sector 1
+       offset = (offset / SECTSIZE) + 1;
+
+       // If this is too slow, we could read lots of sectors at a time.
+       // We'd write more to memory than asked, but it doesn't matter --
+       // we load in increasing order.
+       while (va < end_va) {
+               readsect((uint8_t*) va, offset);
+               va += SECTSIZE;
+               offset++;
+       }
+}
+
+void
+waitdisk(void)
+{
+       // wait for disk reaady
+       while ((inb(0x1F7) & 0xC0) != 0x40)
+               /* do nothing */;
+}
+
+void
+readsect(void *dst, uint32_t offset)
+{
+       // wait for disk to be ready
+       waitdisk();
+
+       outb(0x1F2, 1);         // count = 1
+       outb(0x1F3, offset);
+       outb(0x1F4, offset >> 8);
+       outb(0x1F5, offset >> 16);
+       outb(0x1F6, (offset >> 24) | 0xE0);
+       outb(0x1F7, 0x20);      // cmd 0x20 - read sectors
+
+       // wait for disk to be ready
+       waitdisk();
+
+       // read a sector
+       insl(0x1F0, dst, SECTSIZE/4);
+}
+
diff --git a/boot/sign.pl b/boot/sign.pl
new file mode 100644 (file)
index 0000000..8a65e9f
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/perl
+
+open(SIG, $ARGV[0]) || die "open $ARGV[0]: $!";
+
+$n = sysread(SIG, $buf, 1000);
+
+if($n > 510){
+       print STDERR "boot block too large: $n bytes (max 510)\n";
+       exit 1;
+}
+
+print STDERR "boot block is $n bytes (max 510)\n";
+
+$buf .= "\0" x (510-$n);
+$buf .= "\x55\xAA";
+
+open(SIG, ">$ARGV[0]") || die "open >$ARGV[0]: $!";
+print SIG $buf;
+close SIG;
diff --git a/conf/env.mk b/conf/env.mk
new file mode 100644 (file)
index 0000000..1518fe9
--- /dev/null
@@ -0,0 +1,23 @@
+# env.mk - configuration variables for the JOS lab
+
+
+# '$(V)' controls whether the lab makefiles print verbose commands (the
+# actual shell commands run by Make), as well as the "overview" commands
+# (such as '+ cc lib/readline.c').
+#
+# For overview commands only, the line should read 'V = @'.
+# For overview and verbose commands, the line should read 'V ='.
+V = @
+
+
+# '$(HANDIN_EMAIL)' is the email address to which lab handins should be
+# sent.
+HANDIN_EMAIL = 6.828-handin@pdos.lcs.mit.edu
+
+
+##
+## If your system-standard GNU toolchain is ELF-compatible, then comment
+## out the following line to use those tools (as opposed to the i386-jos-elf
+## tools that the 6.828 make system looks for by default).
+##
+# GCCPREFIX=''
diff --git a/conf/lab.mk b/conf/lab.mk
new file mode 100644 (file)
index 0000000..ab474ab
--- /dev/null
@@ -0,0 +1,2 @@
+LAB=1
+PACKAGEDATE=Sat Jan 13 22:14:53 CST 2007
diff --git a/inc/COPYRIGHT b/inc/COPYRIGHT
new file mode 100644 (file)
index 0000000..54e7f32
--- /dev/null
@@ -0,0 +1,229 @@
+The files in this directory are:
+
+/*
+ * Copyright (C) 1997 Massachusetts Institute of Technology 
+ *
+ * This software is being provided by the copyright holders under the
+ * following license. By obtaining, using and/or copying this software,
+ * you agree that you have read, understood, and will comply with the
+ * following terms and conditions:
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose and without fee or royalty is
+ * hereby granted, provided that the full text of this NOTICE appears on
+ * ALL copies of the software and documentation or portions thereof,
+ * including modifications, that you make.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
+ * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR
+ * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
+ * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
+ * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT
+ * HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE OR
+ * DOCUMENTATION.
+ *
+ * The name and trademarks of copyright holders may NOT be used in
+ * advertising or publicity pertaining to the software without specific,
+ * written prior permission. Title to copyright in this software and any
+ * associated documentation will at all times remain with copyright
+ * holders. See the file AUTHORS which should have accompanied this software
+ * for a list of all copyright holders.
+ *
+ * This file may be derived from previously copyrighted software. This
+ * copyright applies only to those changes made by the copyright
+ * holders listed in the AUTHORS file. The rest of this file is covered by
+ * the copyright notices, if any, listed below.
+ */
+
+isareg.h is copyright:
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)isa.h       5.7 (Berkeley) 5/9/91
+ */
+
+queue.h is:
+
+/* 
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)queue.h     8.5 (Berkeley) 8/20/94
+ */
+
+stdarg.h is:
+
+/*-
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)stdarg.h    8.1 (Berkeley) 6/10/93
+ */
+
+timerreg.h is:
+
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+types.h is:
+
+/*-
+ * Copyright (c) 1982, 1986, 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)types.h     8.4 (Berkeley) 1/21/94
+ */
+
diff --git a/inc/assert.h b/inc/assert.h
new file mode 100644 (file)
index 0000000..aba04de
--- /dev/null
@@ -0,0 +1,20 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifndef JOS_INC_ASSERT_H
+#define JOS_INC_ASSERT_H
+
+#include <inc/stdio.h>
+
+void _warn(const char*, int, const char*, ...);
+void _panic(const char*, int, const char*, ...) __attribute__((noreturn));
+
+#define warn(...) _warn(__FILE__, __LINE__, __VA_ARGS__)
+#define panic(...) _panic(__FILE__, __LINE__, __VA_ARGS__)
+
+#define assert(x)              \
+       do { if (!(x)) panic("assertion failed: %s", #x); } while (0)
+
+// static_assert(x) will generate a compile-time error if 'x' is false.
+#define static_assert(x)       switch (x) case 0: case (x):
+
+#endif /* !JOS_INC_ASSERT_H */
diff --git a/inc/elf.h b/inc/elf.h
new file mode 100644 (file)
index 0000000..5cdf3fe
--- /dev/null
+++ b/inc/elf.h
@@ -0,0 +1,93 @@
+#ifndef JOS_INC_ELF_H
+#define JOS_INC_ELF_H
+
+#define ELF_MAGIC 0x464C457FU  /* "\x7FELF" in little endian */
+
+#include <inc/types.h>
+
+typedef uint32_t Elf32_Addr;
+typedef uint16_t Elf32_Half;
+typedef uint32_t Elf32_Off;
+typedef int32_t Elf32_Sword;
+typedef uint32_t Elf32_Word;
+
+struct Elf {
+       uint32_t e_magic;       // must equal ELF_MAGIC
+       uint8_t e_elf[12];
+       uint16_t e_type;
+       uint16_t e_machine;
+       uint32_t e_version;
+       uint32_t e_entry;
+       uint32_t e_phoff;
+       uint32_t e_shoff;
+       uint32_t e_flags;
+       uint16_t e_ehsize;
+       uint16_t e_phentsize;
+       uint16_t e_phnum;
+       uint16_t e_shentsize;
+       uint16_t e_shnum;
+       uint16_t e_shstrndx;
+};
+
+struct Proghdr {
+       uint32_t p_type;
+       uint32_t p_offset;
+       uint32_t p_va;
+       uint32_t p_pa;
+       uint32_t p_filesz;
+       uint32_t p_memsz;
+       uint32_t p_flags;
+       uint32_t p_align;
+};
+
+struct Secthdr {
+       uint32_t sh_name;
+       uint32_t sh_type;
+       uint32_t sh_flags;
+       uint32_t sh_addr;
+       uint32_t sh_offset;
+       uint32_t sh_size;
+       uint32_t sh_link;
+       uint32_t sh_info;
+       uint32_t sh_addralign;
+       uint32_t sh_entsize;
+};
+
+typedef struct {
+  unsigned long n_strx;         /* index into string table of name */
+  unsigned char n_type;         /* type of symbol */
+  unsigned char n_other;        /* misc info (usually empty) */
+  unsigned short n_desc;        /* description field */
+  unsigned long n_value;              /* value of symbol */
+} stab_t;
+
+/*
+typedef struct {
+        Elf32_Word      st_name;
+        Elf32_Addr      st_value;
+        Elf32_Word      st_size;
+        unsigned char   st_info;
+        unsigned char   st_other;
+        Elf32_Half      st_shndx;
+} Elf32_Sym;
+*/
+
+
+// Values for Proghdr::p_type
+#define ELF_PROG_LOAD          1
+
+// Flag bits for Proghdr::p_flags
+#define ELF_PROG_FLAG_EXEC     1
+#define ELF_PROG_FLAG_WRITE    2
+#define ELF_PROG_FLAG_READ     4
+
+// Values for Secthdr::sh_type
+#define ELF_SHT_NULL           0
+#define ELF_SHT_PROGBITS       1
+#define ELF_SHT_SYMTAB         2
+#define ELF_SHT_STRTAB         3
+
+// Values for Secthdr::sh_name
+#define ELF_SHN_UNDEF          0
+
+#endif /* !JOS_INC_ELF_H */
diff --git a/inc/error.h b/inc/error.h
new file mode 100644 (file)
index 0000000..6906da5
--- /dev/null
@@ -0,0 +1,18 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifndef JOS_INC_ERROR_H
+#define JOS_INC_ERROR_H
+
+// Kernel error codes -- keep in sync with list in lib/printfmt.c.
+#define E_UNSPECIFIED  1       // Unspecified or unknown problem
+#define E_BAD_ENV      2       // Environment doesn't exist or otherwise
+                               // cannot be used in requested action
+#define E_INVAL                3       // Invalid parameter
+#define E_NO_MEM       4       // Request failed due to memory shortage
+#define E_NO_FREE_ENV  5       // Attempt to create a new environment beyond
+                               // the maximum allowed
+#define E_FAULT                6       // Memory fault
+
+#define        MAXERROR        6
+
+#endif // !JOS_INC_ERROR_H */
diff --git a/inc/kbdreg.h b/inc/kbdreg.h
new file mode 100644 (file)
index 0000000..7c6d740
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef JOS_KBDREG_H
+#define JOS_KBDREG_H
+
+// Special keycodes
+#define KEY_HOME       0xE0
+#define KEY_END                0xE1
+#define KEY_UP         0xE2
+#define KEY_DN         0xE3
+#define KEY_LF         0xE4
+#define KEY_RT         0xE5
+#define KEY_PGUP       0xE6
+#define KEY_PGDN       0xE7
+#define KEY_INS                0xE8
+#define KEY_DEL                0xE9
+
+
+/* This is i8042reg.h + kbdreg.h from NetBSD. */
+
+#define        KBSTATP         0x64    /* kbd controller status port(I) */
+#define         KBS_DIB        0x01    /* kbd data in buffer */
+#define         KBS_IBF        0x02    /* kbd input buffer low */
+#define         KBS_WARM       0x04    /* kbd input buffer low */
+#define         KBS_OCMD       0x08    /* kbd output buffer has command */
+#define         KBS_NOSEC      0x10    /* kbd security lock not engaged */
+#define         KBS_TERR       0x20    /* kbd transmission error */
+#define         KBS_RERR       0x40    /* kbd receive error */
+#define         KBS_PERR       0x80    /* kbd parity error */
+
+#define        KBCMDP          0x64    /* kbd controller port(O) */
+#define         KBC_RAMREAD    0x20    /* read from RAM */
+#define         KBC_RAMWRITE   0x60    /* write to RAM */
+#define         KBC_AUXDISABLE 0xa7    /* disable auxiliary port */
+#define         KBC_AUXENABLE  0xa8    /* enable auxiliary port */
+#define         KBC_AUXTEST    0xa9    /* test auxiliary port */
+#define         KBC_KBDECHO    0xd2    /* echo to keyboard port */
+#define         KBC_AUXECHO    0xd3    /* echo to auxiliary port */
+#define         KBC_AUXWRITE   0xd4    /* write to auxiliary port */
+#define         KBC_SELFTEST   0xaa    /* start self-test */
+#define         KBC_KBDTEST    0xab    /* test keyboard port */
+#define         KBC_KBDDISABLE 0xad    /* disable keyboard port */
+#define         KBC_KBDENABLE  0xae    /* enable keyboard port */
+#define         KBC_PULSE0     0xfe    /* pulse output bit 0 */
+#define         KBC_PULSE1     0xfd    /* pulse output bit 1 */
+#define         KBC_PULSE2     0xfb    /* pulse output bit 2 */
+#define         KBC_PULSE3     0xf7    /* pulse output bit 3 */
+
+#define        KBDATAP         0x60    /* kbd data port(I) */
+#define        KBOUTP          0x60    /* kbd data port(O) */
+
+#define        K_RDCMDBYTE     0x20
+#define        K_LDCMDBYTE     0x60
+
+#define        KC8_TRANS       0x40    /* convert to old scan codes */
+#define        KC8_MDISABLE    0x20    /* disable mouse */
+#define        KC8_KDISABLE    0x10    /* disable keyboard */
+#define        KC8_IGNSEC      0x08    /* ignore security lock */
+#define        KC8_CPU         0x04    /* exit from protected mode reset */
+#define        KC8_MENABLE     0x02    /* enable mouse interrupt */
+#define        KC8_KENABLE     0x01    /* enable keyboard interrupt */
+#define        CMDBYTE         (KC8_TRANS|KC8_CPU|KC8_MENABLE|KC8_KENABLE)
+
+/* keyboard commands */
+#define        KBC_RESET       0xFF    /* reset the keyboard */
+#define        KBC_RESEND      0xFE    /* request the keyboard resend the last byte */
+#define        KBC_SETDEFAULT  0xF6    /* resets keyboard to its power-on defaults */
+#define        KBC_DISABLE     0xF5    /* as per KBC_SETDEFAULT, but also disable key scanning */
+#define        KBC_ENABLE      0xF4    /* enable key scanning */
+#define        KBC_TYPEMATIC   0xF3    /* set typematic rate and delay */
+#define        KBC_SETTABLE    0xF0    /* set scancode translation table */
+#define        KBC_MODEIND     0xED    /* set mode indicators(i.e. LEDs) */
+#define        KBC_ECHO        0xEE    /* request an echo from the keyboard */
+
+/* keyboard responses */
+#define        KBR_EXTENDED    0xE0    /* extended key sequence */
+#define        KBR_RESEND      0xFE    /* needs resend of command */
+#define        KBR_ACK         0xFA    /* received a valid command */
+#define        KBR_OVERRUN     0x00    /* flooded */
+#define        KBR_FAILURE     0xFD    /* diagnosic failure */
+#define        KBR_BREAK       0xF0    /* break code prefix - sent on key release */
+#define        KBR_RSTDONE     0xAA    /* reset complete */
+#define        KBR_ECHO        0xEE    /* echo response */
+
+#endif /* !JOS_KBDREG_H */
diff --git a/inc/malloc.h b/inc/malloc.h
new file mode 100644 (file)
index 0000000..bef7267
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef JOS_INC_MALLOC_H
+#define JOS_INC_MALLOC_H 1
+
+void *malloc(size_t size);
+void free(void *addr);
+
+#endif
diff --git a/inc/memlayout.h b/inc/memlayout.h
new file mode 100644 (file)
index 0000000..fa5d8ef
--- /dev/null
@@ -0,0 +1,181 @@
+#ifndef JOS_INC_MEMLAYOUT_H
+#define JOS_INC_MEMLAYOUT_H
+
+#ifndef __ASSEMBLER__
+#include <inc/types.h>
+#include <inc/queue.h>
+#include <inc/mmu.h>
+#endif /* not __ASSEMBLER__ */
+
+/*
+ * This file contains definitions for memory management in our OS,
+ * which are relevant to both the kernel and user-mode software.
+ */
+
+// Global descriptor numbers
+#define GD_KT     0x08     // kernel text
+#define GD_KD     0x10     // kernel data
+#define GD_UT     0x18     // user text
+#define GD_UD     0x20     // user data
+#define GD_TSS    0x28     // Task segment selector
+
+/*
+ * Virtual memory map:                                Permissions
+ *                                                    kernel/user
+ *
+ *    4 Gig -------->  +------------------------------+
+ *                     |                              | RW/--
+ *                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *                     :              .               :
+ *                     :              .               :
+ *                     :              .               :
+ *                     |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| RW/--
+ *                     |                              | RW/--
+ *                     |   Remapped Physical Memory   | RW/--
+ *                     |                              | RW/--
+ *    KERNBASE ----->  +------------------------------+ 0xf0000000
+ *                     |  Cur. Page Table (Kern. RW)  | RW/--  PTSIZE
+ *    VPT,KSTACKTOP--> +------------------------------+ 0xefc00000      --+
+ *                     |         Kernel Stack         | RW/--  KSTKSIZE   |
+ *                     | - - - - - - - - - - - - - - -|                 PTSIZE
+ *                     |      Invalid Memory (*)      | --/--             |
+ *    ULIM     ------> +------------------------------+ 0xef800000      --+
+ *                     |  Cur. Page Table (User R-)   | R-/R-  PTSIZE
+ *    UVPT      ---->  +------------------------------+ 0xef400000
+ *                     |          RO PAGES            | R-/R-  PTSIZE
+ *    UPAGES    ---->  +------------------------------+ 0xef000000
+ *                     |           RO ENVS            | R-/R-  PTSIZE
+ * UTOP,UENVS ------>  +------------------------------+ 0xeec00000
+ * UXSTACKTOP -/       |     User Exception Stack     | RW/RW  PGSIZE
+ *                     +------------------------------+ 0xeebff000
+ *                     |       Empty Memory (*)       | --/--  PGSIZE
+ *    USTACKTOP  --->  +------------------------------+ 0xeebfe000
+ *                     |      Normal User Stack       | RW/RW  PGSIZE
+ *                     +------------------------------+ 0xeebfd000
+ *                     |                              |
+ *                     |                              |
+ *                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *                     .                              .
+ *                     .                              .
+ *                     .                              .
+ *                     |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
+ *                     |     Program Data & Heap      |
+ *    UTEXT -------->  +------------------------------+ 0x00800000
+ *    PFTEMP ------->  |       Empty Memory (*)       |        PTSIZE
+ *                     |                              |
+ *    UTEMP -------->  +------------------------------+ 0x00400000      --+
+ *                     |       Empty Memory (*)       |                   |
+ *                     | - - - - - - - - - - - - - - -|                   |
+ *                     |  User STAB Data (optional)   |                 PTSIZE
+ *    USTABDATA ---->  +------------------------------+ 0x00200000        |
+ *                     |       Empty Memory (*)       |                   |
+ *    0 ------------>  +------------------------------+                 --+
+ *
+ * (*) Note: The kernel ensures that "Invalid Memory" (ULIM) is *never*
+ *     mapped.  "Empty Memory" is normally unmapped, but user programs may
+ *     map pages there if desired.  JOS user programs map pages temporarily
+ *     at UTEMP.
+ */
+
+
+// All physical memory mapped at this address
+#define        KERNBASE        0xC0000000
+
+// At IOPHYSMEM (640K) there is a 384K hole for I/O.  From the kernel,
+// IOPHYSMEM can be addressed at KERNBASE + IOPHYSMEM.  The hole ends
+// at physical address EXTPHYSMEM.
+#define IOPHYSMEM      0x0A0000
+#define EXTPHYSMEM     0x100000
+
+// Virtual page table.  Entry PDX[VPT] in the PD contains a pointer to
+// the page directory itself, thereby turning the PD into a page table,
+// which maps all the PTEs containing the page mappings for the entire
+// virtual address space into that 4 Meg region starting at VPT.
+#define VPT            (KERNBASE - PTSIZE)
+#define KSTACKTOP      VPT
+#define KSTKSIZE       (8*PGSIZE)              // size of a kernel stack
+#define ULIM           (KSTACKTOP - PTSIZE) 
+
+/*
+ * User read-only mappings! Anything below here til UTOP are readonly to user.
+ * They are global pages mapped in at env allocation time.
+ */
+
+// Same as VPT but read-only for users
+#define UVPT           (ULIM - PTSIZE)
+// Read-only copies of the Page structures
+#define UPAGES         (UVPT - PTSIZE)
+// Read-only copies of the global env structures
+#define UENVS          (UPAGES - PTSIZE)
+
+/*
+ * Top of user VM. User can manipulate VA from UTOP-1 and down!
+ */
+
+// Top of user-accessible VM
+#define UTOP           UENVS
+// Top of one-page user exception stack
+#define UXSTACKTOP     UTOP
+// Next page left invalid to guard against exception stack overflow; then:
+// Top of normal user stack
+#define USTACKTOP      (UTOP - 2*PGSIZE)
+
+// Where user programs generally begin
+#define UTEXT          (2*PTSIZE)
+
+// Used for temporary page mappings.  Typed 'void*' for convenience
+#define UTEMP          ((void*) PTSIZE)
+// Used for temporary page mappings for the user page-fault handler
+// (should not conflict with other temporary page mappings)
+#define PFTEMP         (UTEMP + PTSIZE - PGSIZE)
+// The location of the user-level STABS data structure
+#define USTABDATA      (PTSIZE / 2)    
+
+
+#ifndef __ASSEMBLER__
+
+/*
+ * The page directory entry corresponding to the virtual address range
+ * [VPT, VPT + PTSIZE) points to the page directory itself.  Thus, the page
+ * directory is treated as a page table as well as a page directory.
+ *
+ * One result of treating the page directory as a page table is that all PTEs
+ * can be accessed through a "virtual page table" at virtual address VPT (to
+ * which vpt is set in entry.S).  The PTE for page number N is stored in
+ * vpt[N].  (It's worth drawing a diagram of this!)
+ *
+ * A second consequence is that the contents of the current page directory
+ * will always be available at virtual address (VPT + (VPT >> PGSHIFT)), to
+ * which vpd is set in entry.S.
+ */
+typedef uint32_t pte_t;
+typedef uint32_t pde_t;
+
+extern volatile pte_t vpt[];     // VA of "virtual page table"
+extern volatile pde_t vpd[];     // VA of current page directory
+
+
+/*
+ * Page descriptor structures, mapped at UPAGES.
+ * Read/write to the kernel, read-only to user programs.
+ *
+ * Each Page describes one physical page.
+ * You can map a Page * to the corresponding physical address
+ * with page2pa() in kern/pmap.h.
+ */
+LIST_HEAD(Page_list, Page);
+typedef LIST_ENTRY(Page) Page_LIST_entry_t;
+
+struct Page {
+       Page_LIST_entry_t pp_link;      /* free list link */
+
+       // pp_ref is the count of pointers (usually in page table entries)
+       // to this page, for pages allocated using page_alloc.
+       // Pages allocated at boot time using pmap.c's
+       // boot_alloc do not have valid reference count fields.
+
+       uint16_t pp_ref;
+};
+
+#endif /* !__ASSEMBLER__ */
+#endif /* !JOS_INC_MEMLAYOUT_H */
diff --git a/inc/mmu.h b/inc/mmu.h
new file mode 100644 (file)
index 0000000..29e21a7
--- /dev/null
+++ b/inc/mmu.h
@@ -0,0 +1,312 @@
+#ifndef JOS_INC_MMU_H
+#define JOS_INC_MMU_H
+
+/*
+ * This file contains definitions for the x86 memory management unit (MMU),
+ * including paging- and segmentation-related data structures and constants,
+ * the %cr0, %cr4, and %eflags registers, and traps.
+ */
+
+/*
+ *
+ *     Part 1.  Paging data structures and constants.
+ *
+ */
+
+// A linear address 'la' has a three-part structure as follows:
+//
+// +--------10------+-------10-------+---------12----------+
+// | Page Directory |   Page Table   | Offset within Page  |
+// |      Index     |      Index     |                     |
+// +----------------+----------------+---------------------+
+//  \--- PDX(la) --/ \--- PTX(la) --/ \---- PGOFF(la) ----/
+//  \----------- PPN(la) -----------/
+//
+// The PDX, PTX, PGOFF, and PPN macros decompose linear addresses as shown.
+// To construct a linear address la from PDX(la), PTX(la), and PGOFF(la),
+// use PGADDR(PDX(la), PTX(la), PGOFF(la)).
+
+// page number field of address
+#define PPN(la)                (((uintptr_t) (la)) >> PTXSHIFT)
+#define VPN(la)                PPN(la)         // used to index into vpt[]
+
+// page directory index
+#define PDX(la)                ((((uintptr_t) (la)) >> PDXSHIFT) & 0x3FF)
+#define VPD(la)                PDX(la)         // used to index into vpd[]
+
+// page table index
+#define PTX(la)                ((((uintptr_t) (la)) >> PTXSHIFT) & 0x3FF)
+
+// offset in page
+#define PGOFF(la)      (((uintptr_t) (la)) & 0xFFF)
+
+// construct linear address from indexes and offset
+#define PGADDR(d, t, o)        ((void*) ((d) << PDXSHIFT | (t) << PTXSHIFT | (o)))
+
+// Page directory and page table constants.
+#define NPDENTRIES     1024            // page directory entries per page directory
+#define NPTENTRIES     1024            // page table entries per page table
+
+#define PGSIZE         4096            // bytes mapped by a page
+#define PGSHIFT                12              // log2(PGSIZE)
+
+#define PTSIZE         (PGSIZE*NPTENTRIES) // bytes mapped by a page directory entry
+#define PTSHIFT                22              // log2(PTSIZE)
+
+#define PTXSHIFT       12              // offset of PTX in a linear address
+#define PDXSHIFT       22              // offset of PDX in a linear address
+
+// Page table/directory entry flags.
+#define PTE_P          0x001   // Present
+#define PTE_W          0x002   // Writeable
+#define PTE_U          0x004   // User
+#define PTE_PWT                0x008   // Write-Through
+#define PTE_PCD                0x010   // Cache-Disable
+#define PTE_A          0x020   // Accessed
+#define PTE_D          0x040   // Dirty
+#define PTE_PS         0x080   // Page Size
+#define PTE_MBZ                0x180   // Bits must be zero
+
+// The PTE_AVAIL bits aren't used by the kernel or interpreted by the
+// hardware, so user processes are allowed to set them arbitrarily.
+#define PTE_AVAIL      0xE00   // Available for software use
+
+// Only flags in PTE_USER may be used in system calls.
+#define PTE_USER       (PTE_AVAIL | PTE_P | PTE_W | PTE_U)
+
+// address in page table entry
+#define PTE_ADDR(pte)  ((physaddr_t) (pte) & ~0xFFF)
+
+// Control Register flags
+#define CR0_PE         0x00000001      // Protection Enable
+#define CR0_MP         0x00000002      // Monitor coProcessor
+#define CR0_EM         0x00000004      // Emulation
+#define CR0_TS         0x00000008      // Task Switched
+#define CR0_ET         0x00000010      // Extension Type
+#define CR0_NE         0x00000020      // Numeric Errror
+#define CR0_WP         0x00010000      // Write Protect
+#define CR0_AM         0x00040000      // Alignment Mask
+#define CR0_NW         0x20000000      // Not Writethrough
+#define CR0_CD         0x40000000      // Cache Disable
+#define CR0_PG         0x80000000      // Paging
+
+#define CR4_PCE                0x00000100      // Performance counter enable
+#define CR4_MCE                0x00000040      // Machine Check Enable
+#define CR4_PSE                0x00000010      // Page Size Extensions
+#define CR4_DE         0x00000008      // Debugging Extensions
+#define CR4_TSD                0x00000004      // Time Stamp Disable
+#define CR4_PVI                0x00000002      // Protected-Mode Virtual Interrupts
+#define CR4_VME                0x00000001      // V86 Mode Extensions
+
+// Eflags register
+#define FL_CF          0x00000001      // Carry Flag
+#define FL_PF          0x00000004      // Parity Flag
+#define FL_AF          0x00000010      // Auxiliary carry Flag
+#define FL_ZF          0x00000040      // Zero Flag
+#define FL_SF          0x00000080      // Sign Flag
+#define FL_TF          0x00000100      // Trap Flag
+#define FL_IF          0x00000200      // Interrupt Flag
+#define FL_DF          0x00000400      // Direction Flag
+#define FL_OF          0x00000800      // Overflow Flag
+#define FL_IOPL_MASK   0x00003000      // I/O Privilege Level bitmask
+#define FL_IOPL_0      0x00000000      //   IOPL == 0
+#define FL_IOPL_1      0x00001000      //   IOPL == 1
+#define FL_IOPL_2      0x00002000      //   IOPL == 2
+#define FL_IOPL_3      0x00003000      //   IOPL == 3
+#define FL_NT          0x00004000      // Nested Task
+#define FL_RF          0x00010000      // Resume Flag
+#define FL_VM          0x00020000      // Virtual 8086 mode
+#define FL_AC          0x00040000      // Alignment Check
+#define FL_VIF         0x00080000      // Virtual Interrupt Flag
+#define FL_VIP         0x00100000      // Virtual Interrupt Pending
+#define FL_ID          0x00200000      // ID flag
+
+// Page fault error codes
+#define FEC_PR         0x1     // Page fault caused by protection violation
+#define FEC_WR         0x2     // Page fault caused by a write
+#define FEC_U          0x4     // Page fault occured while in user mode
+
+
+/*
+ *
+ *     Part 2.  Segmentation data structures and constants.
+ *
+ */
+
+#ifdef __ASSEMBLER__
+
+/*
+ * Macros to build GDT entries in assembly.
+ */
+#define SEG_NULL                                               \
+       .word 0, 0;                                             \
+       .byte 0, 0, 0, 0
+#define SEG(type,base,lim)                                     \
+       .word (((lim) >> 12) & 0xffff), ((base) & 0xffff);      \
+       .byte (((base) >> 16) & 0xff), (0x90 | (type)),         \
+               (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff)
+
+#else  // not __ASSEMBLER__
+
+#include <inc/types.h>
+
+// Segment Descriptors
+struct Segdesc {
+       unsigned sd_lim_15_0 : 16;  // Low bits of segment limit
+       unsigned sd_base_15_0 : 16; // Low bits of segment base address
+       unsigned sd_base_23_16 : 8; // Middle bits of segment base address
+       unsigned sd_type : 4;       // Segment type (see STS_ constants)
+       unsigned sd_s : 1;          // 0 = system, 1 = application
+       unsigned sd_dpl : 2;        // Descriptor Privilege Level
+       unsigned sd_p : 1;          // Present
+       unsigned sd_lim_19_16 : 4;  // High bits of segment limit
+       unsigned sd_avl : 1;        // Unused (available for software use)
+       unsigned sd_rsv1 : 1;       // Reserved
+       unsigned sd_db : 1;         // 0 = 16-bit segment, 1 = 32-bit segment
+       unsigned sd_g : 1;          // Granularity: limit scaled by 4K when set
+       unsigned sd_base_31_24 : 8; // High bits of segment base address
+};
+// Null segment
+#define SEG_NULL       (struct Segdesc){ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+// Segment that is loadable but faults when used
+#define SEG_FAULT      (struct Segdesc){ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 }
+// Normal segment
+#define SEG(type, base, lim, dpl) (struct Segdesc)                     \
+{ ((lim) >> 12) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,      \
+    type, 1, dpl, 1, (unsigned) (lim) >> 28, 0, 0, 1, 1,               \
+    (unsigned) (base) >> 24 }
+#define SEG16(type, base, lim, dpl) (struct Segdesc)                   \
+{ (lim) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff,              \
+    type, 1, dpl, 1, (unsigned) (lim) >> 16, 0, 0, 1, 0,               \
+    (unsigned) (base) >> 24 }
+
+#endif /* !__ASSEMBLER__ */
+
+// Application segment type bits
+#define STA_X          0x8         // Executable segment
+#define STA_E          0x4         // Expand down (non-executable segments)
+#define STA_C          0x4         // Conforming code segment (executable only)
+#define STA_W          0x2         // Writeable (non-executable segments)
+#define STA_R          0x2         // Readable (executable segments)
+#define STA_A          0x1         // Accessed
+
+// System segment type bits
+#define STS_T16A       0x1         // Available 16-bit TSS
+#define STS_LDT                0x2         // Local Descriptor Table
+#define STS_T16B       0x3         // Busy 16-bit TSS
+#define STS_CG16       0x4         // 16-bit Call Gate
+#define STS_TG         0x5         // Task Gate / Coum Transmitions
+#define STS_IG16       0x6         // 16-bit Interrupt Gate
+#define STS_TG16       0x7         // 16-bit Trap Gate
+#define STS_T32A       0x9         // Available 32-bit TSS
+#define STS_T32B       0xB         // Busy 32-bit TSS
+#define STS_CG32       0xC         // 32-bit Call Gate
+#define STS_IG32       0xE         // 32-bit Interrupt Gate
+#define STS_TG32       0xF         // 32-bit Trap Gate
+
+
+/*
+ *
+ *     Part 3.  Traps.
+ *
+ */
+
+#ifndef __ASSEMBLER__
+
+// Task state segment format (as described by the Pentium architecture book)
+struct Taskstate {
+       uint32_t ts_link;       // Old ts selector
+       uintptr_t ts_esp0;      // Stack pointers and segment selectors
+       uint16_t ts_ss0;        //   after an increase in privilege level
+       uint16_t ts_padding1;
+       uintptr_t ts_esp1;
+       uint16_t ts_ss1;
+       uint16_t ts_padding2;
+       uintptr_t ts_esp2;
+       uint16_t ts_ss2;
+       uint16_t ts_padding3;
+       physaddr_t ts_cr3;      // Page directory base
+       uintptr_t ts_eip;       // Saved state from last task switch
+       uint32_t ts_eflags;
+       uint32_t ts_eax;        // More saved state (registers)
+       uint32_t ts_ecx;
+       uint32_t ts_edx;
+       uint32_t ts_ebx;
+       uintptr_t ts_esp;
+       uintptr_t ts_ebp;
+       uint32_t ts_esi;
+       uint32_t ts_edi;
+       uint16_t ts_es;         // Even more saved state (segment selectors)
+       uint16_t ts_padding4;
+       uint16_t ts_cs;
+       uint16_t ts_padding5;
+       uint16_t ts_ss;
+       uint16_t ts_padding6;
+       uint16_t ts_ds;
+       uint16_t ts_padding7;
+       uint16_t ts_fs;
+       uint16_t ts_padding8;
+       uint16_t ts_gs;
+       uint16_t ts_padding9;
+       uint16_t ts_ldt;
+       uint16_t ts_padding10;
+       uint16_t ts_t;          // Trap on task switch
+       uint16_t ts_iomb;       // I/O map base address
+};
+
+// Gate descriptors for interrupts and traps
+struct Gatedesc {
+       unsigned gd_off_15_0 : 16;   // low 16 bits of offset in segment
+       unsigned gd_ss : 16;         // segment selector
+       unsigned gd_args : 5;        // # args, 0 for interrupt/trap gates
+       unsigned gd_rsv1 : 3;        // reserved(should be zero I guess)
+       unsigned gd_type : 4;        // type(STS_{TG,IG32,TG32})
+       unsigned gd_s : 1;           // must be 0 (system)
+       unsigned gd_dpl : 2;         // descriptor(meaning new) privilege level
+       unsigned gd_p : 1;           // Present
+       unsigned gd_off_31_16 : 16;  // high bits of offset in segment
+};
+
+// Set up a normal interrupt/trap gate descriptor.
+// - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate.
+// - sel: Code segment selector for interrupt/trap handler
+// - off: Offset in code segment for interrupt/trap handler
+// - dpl: Descriptor Privilege Level -
+//       the privilege level required for software to invoke
+//       this interrupt/trap gate explicitly using an int instruction.
+#define SETGATE(gate, istrap, sel, off, dpl)                   \
+{                                                              \
+       (gate).gd_off_15_0 = (uint32_t) (off) & 0xffff;         \
+       (gate).gd_ss = (sel);                                   \
+       (gate).gd_args = 0;                                     \
+       (gate).gd_rsv1 = 0;                                     \
+       (gate).gd_type = (istrap) ? STS_TG32 : STS_IG32;        \
+       (gate).gd_s = 0;                                        \
+       (gate).gd_dpl = (dpl);                                  \
+       (gate).gd_p = 1;                                        \
+       (gate).gd_off_31_16 = (uint32_t) (off) >> 16;           \
+}
+
+// Set up a call gate descriptor.
+#define SETCALLGATE(gate, ss, off, dpl)                        \
+{                                                              \
+       (gate).gd_off_15_0 = (uint32_t) (off) & 0xffff;         \
+       (gate).gd_ss = (ss);                                    \
+       (gate).gd_args = 0;                                     \
+       (gate).gd_rsv1 = 0;                                     \
+       (gate).gd_type = STS_CG32;                              \
+       (gate).gd_s = 0;                                        \
+       (gate).gd_dpl = (dpl);                                  \
+       (gate).gd_p = 1;                                        \
+       (gate).gd_off_31_16 = (uint32_t) (off) >> 16;           \
+}
+
+// Pseudo-descriptors used for LGDT, LLDT and LIDT instructions.
+struct Pseudodesc {
+       uint16_t pd_lim;                // Limit
+       uint32_t pd_base;               // Base address
+} __attribute__ ((packed));
+
+#endif /* !__ASSEMBLER__ */
+
+#endif /* !JOS_INC_MMU_H */
diff --git a/inc/multiboot.h b/inc/multiboot.h
new file mode 100644 (file)
index 0000000..b32982a
--- /dev/null
@@ -0,0 +1,119 @@
+     /* multiboot.h - the header for Multiboot */
+     /* Copyright (C) 1999, 2001  Free Software Foundation, Inc.
+     
+        This program is free software; you can redistribute it and/or modify
+        it under the terms of the GNU General Public License as published by
+        the Free Software Foundation; either version 2 of the License, or
+        (at your option) any later version.
+     
+        This program is distributed in the hope that it will be useful,
+        but WITHOUT ANY WARRANTY; without even the implied warranty of
+        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+        GNU General Public License for more details.
+     
+        You should have received a copy of the GNU General Public License
+        along with this program; if not, write to the Free Software
+        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+     
+     /* Macros. */
+     
+     /* The magic number for the Multiboot header. */
+     #define MULTIBOOT_HEADER_MAGIC          0x1BADB002
+     
+     /* The flags for the Multiboot header. */
+     #ifdef __ELF__
+     # define MULTIBOOT_HEADER_FLAGS         0x00000003
+     #else
+     # define MULTIBOOT_HEADER_FLAGS         0x00010003
+     #endif
+     
+     /* The magic number passed by a Multiboot-compliant boot loader. */
+     #define MULTIBOOT_BOOTLOADER_MAGIC      0x2BADB002
+     
+     /* The size of our stack (16KB). */
+     #define STACK_SIZE                      0x4000
+     
+     /* C symbol format. HAVE_ASM_USCORE is defined by configure. */
+     #ifdef HAVE_ASM_USCORE
+     # define EXT_C(sym)                     _ ## sym
+     #else
+     # define EXT_C(sym)                     sym
+     #endif
+     
+     #ifndef ASM
+     /* Do not include here in boot.S. */
+     
+     /* Types. */
+     
+     /* The Multiboot header. */
+     typedef struct multiboot_header
+     {
+       unsigned long magic;
+       unsigned long flags;
+       unsigned long checksum;
+       unsigned long header_addr;
+       unsigned long load_addr;
+       unsigned long load_end_addr;
+       unsigned long bss_end_addr;
+       unsigned long entry_addr;
+     } multiboot_header_t;
+     
+     /* The symbol table for a.out. */
+     typedef struct aout_symbol_table
+     {
+       unsigned long tabsize;
+       unsigned long strsize;
+       unsigned long addr;
+       unsigned long reserved;
+     } aout_symbol_table_t;
+     
+     /* The section header table for ELF. */
+     typedef struct elf_section_header_table
+     {
+       unsigned long num;
+       unsigned long size;
+       unsigned long addr;
+       unsigned long shndx;
+     } elf_section_header_table_t;
+     
+     /* The Multiboot information. */
+     typedef struct multiboot_info
+     {
+       unsigned long flags;
+       unsigned long mem_lower;
+       unsigned long mem_upper;
+       unsigned long boot_device;
+       unsigned long cmdline;
+       unsigned long mods_count;
+       unsigned long mods_addr;
+       union
+       {
+         aout_symbol_table_t aout_sym;
+         elf_section_header_table_t elf_sec;
+       } u;
+       unsigned long mmap_length;
+       unsigned long mmap_addr;
+     } multiboot_info_t;
+     
+     /* The module structure. */
+     typedef struct module
+     {
+       unsigned long mod_start;
+       unsigned long mod_end;
+       unsigned long string;
+       unsigned long reserved;
+     } module_t;
+     
+     /* The memory map. Be careful that the offset 0 is base_addr_low
+        but no size. */
+     typedef struct memory_map
+     {
+       unsigned long size;
+       unsigned long base_addr_low;
+       unsigned long base_addr_high;
+       unsigned long length_low;
+       unsigned long length_high;
+       unsigned long type;
+     } memory_map_t;
+     
+     #endif /* ! ASM */
diff --git a/inc/queue.h b/inc/queue.h
new file mode 100644 (file)
index 0000000..7680415
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)queue.h     8.3 (Berkeley) 12/13/93
+ *
+ * For Jos, extra comments have been added to this file, and the original
+ * TAILQ and CIRCLEQ definitions have been removed.   - August 9, 2005
+ */
+
+#ifndef JOS_INC_QUEUE_H
+#define JOS_INC_QUEUE_H
+
+/*
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ */
+
+/*
+ * An example using the below functions.
+ */
+#if 0
+
+struct Frob
+{
+       int frobozz;
+       LIST_ENTRY(Frob) frob_link;     /* this contains the list element pointers */
+};
+
+LIST_HEAD(Frob_list, Frob)             /* defines struct Frob_list as a list of Frob */
+
+struct Frob_list flist;                        /* declare a Frob list */
+
+LIST_INIT(&flist);                     /* clear flist (globals are cleared anyway) */
+flist = LIST_HEAD_INITIALIZER(&flist); /* alternate way to clear flist */
+
+if(LIST_EMPTY(&flist))                 /* check whether list is empty */
+       printf("list is empty\n");
+
+struct Frob *f = LIST_FIRST(&flist);   /* f is first element in list */
+f = LIST_NEXT(f, frob_link);           /* now f is next (second) element in list */
+f = LIST_NEXT(f, frob_link);           /* now f is next (third) element in list */
+
+for(f=LIST_FIRST(&flist); f != 0;      /* iterate over elements in flist */
+    f = LIST_NEXT(f, frob_link))
+       printf("f %d\n", f->frobozz);
+
+LIST_FOREACH(f, &flist, frob_link)     /* alternate way to say that */
+       printf("f %d\n", f->frobozz);
+
+f = LIST_NEXT(LIST_FIRST(&flist));     /* f is second element in list */
+LIST_INSERT_AFTER(f, g, frob_link);    /* add g right after f in list */
+LIST_REMOVE(g, frob_link);             /* remove g from list (can't insert twice!) */
+LIST_INSERT_BEFORE(f, g, frob_link);   /* add g right before f */
+LIST_REMOVE(g, frob_link);             /* remove g again */
+LIST_INSERT_HEAD(&flist, g, frob_link);        /* add g as first element in list */
+
+#endif
+
+/*
+ * List declarations.
+ */
+
+/*
+ * A list is headed by a structure defined by the LIST_HEAD macro.  This structure con‐
+ * tains a single pointer to the first element on the list.  The elements are doubly
+ * linked so that an arbitrary element can be removed without traversing the list.  New
+ * elements can be added to the list after an existing element or at the head of the list.
+ * A LIST_HEAD structure is declared as follows:
+ * 
+ *       LIST_HEAD(HEADNAME, TYPE) head;
+ * 
+ * where HEADNAME is the name of the structure to be defined, and TYPE is the type of the
+ * elements to be linked into the list.  A pointer to the head of the list can later be
+ * declared as:
+ * 
+ *       struct HEADNAME *headp;
+ * 
+ * (The names head and headp are user selectable.)
+ */
+#define        LIST_HEAD(name, type)                                           \
+struct name {                                                          \
+       struct type *lh_first;  /* first element */                     \
+}
+
+/*
+ * Set a list head variable to LIST_HEAD_INITIALIZER(head)
+ * to reset it to the empty list.
+ */
+#define        LIST_HEAD_INITIALIZER(head)                                     \
+       { NULL }
+
+/*
+ * Use this inside a structure "LIST_ENTRY(type) field" to use
+ * x as the list piece.
+ *
+ * The le_prev points at the pointer to the structure containing
+ * this very LIST_ENTRY, so that if we want to remove this list entry,
+ * we can do *le_prev = le_next to update the structure pointing at us.
+ */
+#define        LIST_ENTRY(type)                                                \
+struct {                                                               \
+       struct type *le_next;   /* next element */                      \
+       struct type **le_prev;  /* ptr to ptr to this element */        \
+}
+
+/*
+ * List functions.
+ */
+
+/*
+ * Is the list named "head" empty?
+ */
+#define        LIST_EMPTY(head)        ((head)->lh_first == NULL)
+
+/*
+ * Return the first element in the list named "head".
+ */
+#define        LIST_FIRST(head)        ((head)->lh_first)
+
+/*
+ * Return the element after "elm" in the list.
+ * The "field" name is the link element as above.
+ */
+#define        LIST_NEXT(elm, field)   ((elm)->field.le_next)
+
+/*
+ * Iterate over the elements in the list named "head".
+ * During the loop, assign the list elements to the variable "var"
+ * and use the LIST_ENTRY structure member "field" as the link field.
+ */
+#define        LIST_FOREACH(var, head, field)                                  \
+       for ((var) = LIST_FIRST((head));                                \
+           (var);                                                      \
+           (var) = LIST_NEXT((var), field))
+
+/*
+ * Reset the list named "head" to the empty list.
+ */
+#define        LIST_INIT(head) do {                                            \
+       LIST_FIRST((head)) = NULL;                                      \
+} while (0)
+
+/*
+ * Insert the element "elm" *after* the element "listelm" which is
+ * already in the list.  The "field" name is the link element
+ * as above.
+ */
+#define        LIST_INSERT_AFTER(listelm, elm, field) do {                     \
+       if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
+               LIST_NEXT((listelm), field)->field.le_prev =            \
+                   &LIST_NEXT((elm), field);                           \
+       LIST_NEXT((listelm), field) = (elm);                            \
+       (elm)->field.le_prev = &LIST_NEXT((listelm), field);            \
+} while (0)
+
+/*
+ * Insert the element "elm" *before* the element "listelm" which is
+ * already in the list.  The "field" name is the link element
+ * as above.
+ */
+#define        LIST_INSERT_BEFORE(listelm, elm, field) do {                    \
+       (elm)->field.le_prev = (listelm)->field.le_prev;                \
+       LIST_NEXT((elm), field) = (listelm);                            \
+       *(listelm)->field.le_prev = (elm);                              \
+       (listelm)->field.le_prev = &LIST_NEXT((elm), field);            \
+} while (0)
+
+/*
+ * Insert the element "elm" at the head of the list named "head".
+ * The "field" name is the link element as above.
+ */
+#define        LIST_INSERT_HEAD(head, elm, field) do {                         \
+       if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)     \
+               LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+       LIST_FIRST((head)) = (elm);                                     \
+       (elm)->field.le_prev = &LIST_FIRST((head));                     \
+} while (0)
+
+/*
+ * Remove the element "elm" from the list.
+ * The "field" name is the link element as above.
+ */
+#define        LIST_REMOVE(elm, field) do {                                    \
+       if (LIST_NEXT((elm), field) != NULL)                            \
+               LIST_NEXT((elm), field)->field.le_prev =                \
+                   (elm)->field.le_prev;                               \
+       *(elm)->field.le_prev = LIST_NEXT((elm), field);                \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/inc/stab.h b/inc/stab.h
new file mode 100644 (file)
index 0000000..9b022bb
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef JOS_STAB_H
+#define JOS_STAB_H
+#include <inc/types.h>
+
+// <inc/stab.h>
+// STABS debugging info
+
+// The JOS kernel debugger can understand some debugging information
+// in the STABS format.  For more information on this format, see
+// http://sources.redhat.com/gdb/onlinedocs/stabs_toc.html
+
+// The constants below define some symbol types used by various debuggers
+// and compilers.  JOS uses the N_SO, N_SOL, N_FUN, and N_SLINE types.
+
+#define        N_GSYM          0x20    // global symbol
+#define        N_FNAME         0x22    // F77 function name
+#define        N_FUN           0x24    // procedure name
+#define        N_STSYM         0x26    // data segment variable
+#define        N_LCSYM         0x28    // bss segment variable
+#define        N_MAIN          0x2a    // main function name
+#define        N_PC            0x30    // global Pascal symbol
+#define        N_RSYM          0x40    // register variable
+#define        N_SLINE         0x44    // text segment line number
+#define        N_DSLINE        0x46    // data segment line number
+#define        N_BSLINE        0x48    // bss segment line number
+#define        N_SSYM          0x60    // structure/union element
+#define        N_SO            0x64    // main source file name
+#define        N_LSYM          0x80    // stack variable
+#define        N_BINCL         0x82    // include file beginning
+#define        N_SOL           0x84    // included source file name
+#define        N_PSYM          0xa0    // parameter variable
+#define        N_EINCL         0xa2    // include file end
+#define        N_ENTRY         0xa4    // alternate entry point
+#define        N_LBRAC         0xc0    // left bracket
+#define        N_EXCL          0xc2    // deleted include file
+#define        N_RBRAC         0xe0    // right bracket
+#define        N_BCOMM         0xe2    // begin common
+#define        N_ECOMM         0xe4    // end common
+#define        N_ECOML         0xe8    // end common (local name)
+#define        N_LENG          0xfe    // length of preceding entry
+
+// Entries in the STABS table are formatted as follows.
+struct Stab {
+       uint32_t n_strx;        // index into string table of name
+       uint8_t n_type;         // type of symbol
+       uint8_t n_other;        // misc info (usually empty)
+       uint16_t n_desc;        // description field
+       uintptr_t n_value;      // value of symbol
+};
+
+#endif /* !JOS_STAB_H */
diff --git a/inc/stdarg.h b/inc/stdarg.h
new file mode 100644 (file)
index 0000000..9fc067e
--- /dev/null
@@ -0,0 +1,19 @@
+/*     $NetBSD: stdarg.h,v 1.12 1995/12/25 23:15:31 mycroft Exp $      */
+
+#ifndef JOS_INC_STDARG_H
+#define        JOS_INC_STDARG_H
+
+typedef char *va_list;
+
+#define        __va_size(type) \
+       (((sizeof(type) + sizeof(long) - 1) / sizeof(long)) * sizeof(long))
+
+#define        va_start(ap, last) \
+       ((ap) = (va_list)&(last) + __va_size(last))
+
+#define        va_arg(ap, type) \
+       (*(type *)((ap) += __va_size(type), (ap) - __va_size(type)))
+
+#define        va_end(ap)      ((void)0)
+
+#endif /* !JOS_INC_STDARG_H */
diff --git a/inc/stdio.h b/inc/stdio.h
new file mode 100644 (file)
index 0000000..e7b4a35
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef JOS_INC_STDIO_H
+#define JOS_INC_STDIO_H
+
+#include <inc/stdarg.h>
+
+#ifndef NULL
+#define NULL   ((void *) 0)
+#endif /* !NULL */
+
+// lib/stdio.c
+void   cputchar(int c);
+int    getchar(void);
+int    iscons(int fd);
+
+// lib/printfmt.c
+void   printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...);
+void   vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list);
+
+// lib/printf.c
+int    cprintf(const char *fmt, ...);
+int    vcprintf(const char *fmt, va_list);
+
+// lib/sprintf.c
+int    snprintf(char *str, int size, const char *fmt, ...);
+int    vsnprintf(char *str, int size, const char *fmt, va_list);
+
+// lib/fprintf.c
+int    printf(const char *fmt, ...);
+int    fprintf(int fd, const char *fmt, ...);
+int    vfprintf(int fd, const char *fmt, va_list);
+
+// lib/readline.c
+char*  readline(const char *prompt);
+
+#endif /* !JOS_INC_STDIO_H */
diff --git a/inc/string.h b/inc/string.h
new file mode 100644 (file)
index 0000000..8fe5581
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef JOS_INC_STRING_H
+#define JOS_INC_STRING_H
+
+#include <inc/types.h>
+
+int    strlen(const char *s);
+int    strnlen(const char *s, size_t size);
+char * strcpy(char *dst, const char *src);
+char * strncpy(char *dst, const char *src, size_t size);
+size_t strlcpy(char *dst, const char *src, size_t size);
+int    strcmp(const char *s1, const char *s2);
+int    strncmp(const char *s1, const char *s2, size_t size);
+char * strchr(const char *s, char c);
+char * strfind(const char *s, char c);
+
+void * memset(void *dst, int c, size_t len);
+void * memcpy(void *dst, const void *src, size_t len);
+void * memmove(void *dst, const void *src, size_t len);
+int    memcmp(const void *s1, const void *s2, size_t len);
+void * memfind(const void *s, int c, size_t len);
+
+long   strtol(const char *s, char **endptr, int base);
+
+#endif /* not JOS_INC_STRING_H */
diff --git a/inc/types.h b/inc/types.h
new file mode 100644 (file)
index 0000000..4627178
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef JOS_INC_TYPES_H
+#define JOS_INC_TYPES_H
+
+#ifndef NULL
+#define NULL ((void*) 0)
+#endif
+
+// Represents true-or-false values
+typedef int bool;
+
+// Explicitly-sized versions of integer types
+typedef __signed char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef int int32_t;
+typedef unsigned int uint32_t;
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+
+// Pointers and addresses are 32 bits long.
+// We use pointer types to represent virtual addresses,
+// uintptr_t to represent the numerical values of virtual addresses,
+// and physaddr_t to represent physical addresses.
+typedef int32_t intptr_t;
+typedef uint32_t uintptr_t;
+typedef uint32_t physaddr_t;
+
+// Page numbers are 32 bits long.
+typedef uint32_t ppn_t;
+
+// size_t is used for memory object sizes.
+typedef uint32_t size_t;
+// ssize_t is a signed version of ssize_t, used in case there might be an
+// error return.
+typedef int32_t ssize_t;
+
+// off_t is used for file offsets and lengths.
+typedef int32_t off_t;
+
+// Efficient min and max operations
+#define MIN(_a, _b)                                            \
+({                                                             \
+       typeof(_a) __a = (_a);                                  \
+       typeof(_b) __b = (_b);                                  \
+       __a <= __b ? __a : __b;                                 \
+})
+#define MAX(_a, _b)                                            \
+({                                                             \
+       typeof(_a) __a = (_a);                                  \
+       typeof(_b) __b = (_b);                                  \
+       __a >= __b ? __a : __b;                                 \
+})
+
+// Rounding operations (efficient when n is a power of 2)
+// Round down to the nearest multiple of n
+#define ROUNDDOWN(a, n)                                                \
+({                                                             \
+       uint32_t __a = (uint32_t) (a);                          \
+       (typeof(a)) (__a - __a % (n));                          \
+})
+// Round up to the nearest multiple of n
+#define ROUNDUP(a, n)                                          \
+({                                                             \
+       uint32_t __n = (uint32_t) (n);                          \
+       (typeof(a)) (ROUNDDOWN((uint32_t) (a) + __n - 1, __n)); \
+})
+
+// Return the offset of 'member' relative to the beginning of a struct type
+#define offsetof(type, member)  ((size_t) (&((type*)0)->member))
+
+#endif /* !JOS_INC_TYPES_H */
diff --git a/inc/x86.h b/inc/x86.h
new file mode 100644 (file)
index 0000000..67ad5c9
--- /dev/null
+++ b/inc/x86.h
@@ -0,0 +1,277 @@
+#ifndef JOS_INC_X86_H
+#define JOS_INC_X86_H
+
+#include <inc/types.h>
+
+static __inline void breakpoint(void) __attribute__((always_inline));
+static __inline uint8_t inb(int port) __attribute__((always_inline));
+static __inline void insb(int port, void *addr, int cnt) __attribute__((always_inline));
+static __inline uint16_t inw(int port) __attribute__((always_inline));
+static __inline void insw(int port, void *addr, int cnt) __attribute__((always_inline));
+static __inline uint32_t inl(int port) __attribute__((always_inline));
+static __inline void insl(int port, void *addr, int cnt) __attribute__((always_inline));
+static __inline void outb(int port, uint8_t data) __attribute__((always_inline));
+static __inline void outsb(int port, const void *addr, int cnt) __attribute__((always_inline));
+static __inline void outw(int port, uint16_t data) __attribute__((always_inline));
+static __inline void outsw(int port, const void *addr, int cnt) __attribute__((always_inline));
+static __inline void outsl(int port, const void *addr, int cnt) __attribute__((always_inline));
+static __inline void outl(int port, uint32_t data) __attribute__((always_inline));
+static __inline void invlpg(void *addr) __attribute__((always_inline));
+static __inline void lidt(void *p) __attribute__((always_inline));
+static __inline void lldt(uint16_t sel) __attribute__((always_inline));
+static __inline void ltr(uint16_t sel) __attribute__((always_inline));
+static __inline void lcr0(uint32_t val) __attribute__((always_inline));
+static __inline uint32_t rcr0(void) __attribute__((always_inline));
+static __inline uint32_t rcr2(void) __attribute__((always_inline));
+static __inline void lcr3(uint32_t val) __attribute__((always_inline));
+static __inline uint32_t rcr3(void) __attribute__((always_inline));
+static __inline void lcr4(uint32_t val) __attribute__((always_inline));
+static __inline uint32_t rcr4(void) __attribute__((always_inline));
+static __inline void tlbflush(void) __attribute__((always_inline));
+static __inline uint32_t read_eflags(void) __attribute__((always_inline));
+static __inline void write_eflags(uint32_t eflags) __attribute__((always_inline));
+static __inline uint32_t read_ebp(void) __attribute__((always_inline));
+static __inline uint32_t read_esp(void) __attribute__((always_inline));
+static __inline void cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp);
+static __inline uint64_t read_tsc(void) __attribute__((always_inline));
+
+static __inline void
+breakpoint(void)
+{
+       __asm __volatile("int3");
+}
+
+static __inline uint8_t
+inb(int port)
+{
+       uint8_t data;
+       __asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port));
+       return data;
+}
+
+static __inline void
+insb(int port, void *addr, int cnt)
+{
+       __asm __volatile("cld\n\trepne\n\tinsb"                 :
+                        "=D" (addr), "=c" (cnt)                :
+                        "d" (port), "0" (addr), "1" (cnt)      :
+                        "memory", "cc");
+}
+
+static __inline uint16_t
+inw(int port)
+{
+       uint16_t data;
+       __asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port));
+       return data;
+}
+
+static __inline void
+insw(int port, void *addr, int cnt)
+{
+       __asm __volatile("cld\n\trepne\n\tinsw"                 :
+                        "=D" (addr), "=c" (cnt)                :
+                        "d" (port), "0" (addr), "1" (cnt)      :
+                        "memory", "cc");
+}
+
+static __inline uint32_t
+inl(int port)
+{
+       uint32_t data;
+       __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port));
+       return data;
+}
+
+static __inline void
+insl(int port, void *addr, int cnt)
+{
+       __asm __volatile("cld\n\trepne\n\tinsl"                 :
+                        "=D" (addr), "=c" (cnt)                :
+                        "d" (port), "0" (addr), "1" (cnt)      :
+                        "memory", "cc");
+}
+
+static __inline void
+outb(int port, uint8_t data)
+{
+       __asm __volatile("outb %0,%w1" : : "a" (data), "d" (port));
+}
+
+static __inline void
+outsb(int port, const void *addr, int cnt)
+{
+       __asm __volatile("cld\n\trepne\n\toutsb"                :
+                        "=S" (addr), "=c" (cnt)                :
+                        "d" (port), "0" (addr), "1" (cnt)      :
+                        "cc");
+}
+
+static __inline void
+outw(int port, uint16_t data)
+{
+       __asm __volatile("outw %0,%w1" : : "a" (data), "d" (port));
+}
+
+static __inline void
+outsw(int port, const void *addr, int cnt)
+{
+       __asm __volatile("cld\n\trepne\n\toutsw"                :
+                        "=S" (addr), "=c" (cnt)                :
+                        "d" (port), "0" (addr), "1" (cnt)      :
+                        "cc");
+}
+
+static __inline void
+outsl(int port, const void *addr, int cnt)
+{
+       __asm __volatile("cld\n\trepne\n\toutsl"                :
+                        "=S" (addr), "=c" (cnt)                :
+                        "d" (port), "0" (addr), "1" (cnt)      :
+                        "cc");
+}
+
+static __inline void
+outl(int port, uint32_t data)
+{
+       __asm __volatile("outl %0,%w1" : : "a" (data), "d" (port));
+}
+
+static __inline void 
+invlpg(void *addr)
+{ 
+       __asm __volatile("invlpg (%0)" : : "r" (addr) : "memory");
+}  
+
+static __inline void
+lidt(void *p)
+{
+       __asm __volatile("lidt (%0)" : : "r" (p));
+}
+
+static __inline void
+lldt(uint16_t sel)
+{
+       __asm __volatile("lldt %0" : : "r" (sel));
+}
+
+static __inline void
+ltr(uint16_t sel)
+{
+       __asm __volatile("ltr %0" : : "r" (sel));
+}
+
+static __inline void
+lcr0(uint32_t val)
+{
+       __asm __volatile("movl %0,%%cr0" : : "r" (val));
+}
+
+static __inline uint32_t
+rcr0(void)
+{
+       uint32_t val;
+       __asm __volatile("movl %%cr0,%0" : "=r" (val));
+       return val;
+}
+
+static __inline uint32_t
+rcr2(void)
+{
+       uint32_t val;
+       __asm __volatile("movl %%cr2,%0" : "=r" (val));
+       return val;
+}
+
+static __inline void
+lcr3(uint32_t val)
+{
+       __asm __volatile("movl %0,%%cr3" : : "r" (val));
+}
+
+static __inline uint32_t
+rcr3(void)
+{
+       uint32_t val;
+       __asm __volatile("movl %%cr3,%0" : "=r" (val));
+       return val;
+}
+
+static __inline void
+lcr4(uint32_t val)
+{
+       __asm __volatile("movl %0,%%cr4" : : "r" (val));
+}
+
+static __inline uint32_t
+rcr4(void)
+{
+       uint32_t cr4;
+       __asm __volatile("movl %%cr4,%0" : "=r" (cr4));
+       return cr4;
+}
+
+static __inline void
+tlbflush(void)
+{
+       uint32_t cr3;
+       __asm __volatile("movl %%cr3,%0" : "=r" (cr3));
+       __asm __volatile("movl %0,%%cr3" : : "r" (cr3));
+}
+
+static __inline uint32_t
+read_eflags(void)
+{
+        uint32_t eflags;
+        __asm __volatile("pushfl; popl %0" : "=r" (eflags));
+        return eflags;
+}
+
+static __inline void
+write_eflags(uint32_t eflags)
+{
+        __asm __volatile("pushl %0; popfl" : : "r" (eflags));
+}
+
+static __inline uint32_t
+read_ebp(void)
+{
+        uint32_t ebp;
+        __asm __volatile("movl %%ebp,%0" : "=r" (ebp));
+        return ebp;
+}
+
+static __inline uint32_t
+read_esp(void)
+{
+        uint32_t esp;
+        __asm __volatile("movl %%esp,%0" : "=r" (esp));
+        return esp;
+}
+
+static __inline void
+cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp)
+{
+       uint32_t eax, ebx, ecx, edx;
+       asm volatile("cpuid" 
+               : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+               : "a" (info));
+       if (eaxp)
+               *eaxp = eax;
+       if (ebxp)
+               *ebxp = ebx;
+       if (ecxp)
+               *ecxp = ecx;
+       if (edxp)
+               *edxp = edx;
+}
+
+static __inline uint64_t
+read_tsc(void)
+{
+        uint64_t tsc;
+        __asm __volatile("rdtsc" : "=A" (tsc));
+        return tsc;
+}
+
+#endif /* !JOS_INC_X86_H */
diff --git a/kern/COPYRIGHT b/kern/COPYRIGHT
new file mode 100644 (file)
index 0000000..6a0270c
--- /dev/null
@@ -0,0 +1,155 @@
+Most of the source files in this directory are derived from the Exokernel,
+which is:
+
+/*
+ * Copyright (C) 1997 Massachusetts Institute of Technology 
+ *
+ * This software is being provided by the copyright holders under the
+ * following license. By obtaining, using and/or copying this software,
+ * you agree that you have read, understood, and will comply with the
+ * following terms and conditions:
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose and without fee or royalty is
+ * hereby granted, provided that the full text of this NOTICE appears on
+ * ALL copies of the software and documentation or portions thereof,
+ * including modifications, that you make.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
+ * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR
+ * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
+ * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
+ * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT
+ * HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE OR
+ * DOCUMENTATION.
+ *
+ * The name and trademarks of copyright holders may NOT be used in
+ * advertising or publicity pertaining to the software without specific,
+ * written prior permission. Title to copyright in this software and any
+ * associated documentation will at all times remain with copyright
+ * holders. See the file AUTHORS which should have accompanied this software
+ * for a list of all copyright holders.
+ *
+ * This file may be derived from previously copyrighted software. This
+ * copyright applies only to those changes made by the copyright
+ * holders listed in the AUTHORS file. The rest of this file is covered by
+ * the copyright notices, if any, listed below.
+ */
+
+Console.c was created consulting the NetBSD pccons driver which is:
+
+/*-
+ * Copyright (c) 1993, 1994, 1995 Charles Hannum.  All rights reserved.
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * William Jolitz and Don Ahn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+Kclock.h, sched.h, and printf.h are copyright:
+
+/*
+ * Copyright (C) 1998 Exotec, Inc.
+ *
+ * This software is being provided by the copyright holders under the
+ * following license. By obtaining, using and/or copying this software,
+ * you agree that you have read, understood, and will comply with the
+ * following terms and conditions:
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose and without fee or royalty is
+ * hereby granted, provided that the full text of this NOTICE appears on
+ * ALL copies of the software and documentation or portions thereof,
+ * including modifications, that you make.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO
+ * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
+ * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR
+ * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
+ * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
+ * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT
+ * HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE OR
+ * DOCUMENTATION.
+ *
+ * The name and trademarks of copyright holders may NOT be used in
+ * advertising or publicity pertaining to the software without specific,
+ * written prior permission. Title to copyright in this software and any
+ * associated documentation will at all times remain with Exotec, Inc..
+ *
+ * This file may be derived from previously copyrighted software. This
+ * copyright applies only to those changes made by Exotec, Inc. The rest
+ * of this file is covered by the copyright notices, if any, listed below.
+ */
+
+Printf.c is copyright:
+
+/*-
+ * Copyright (c) 1986, 1988, 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)subr_prf.c  8.3 (Berkeley) 1/21/94
+ */
+
diff --git a/kern/Makefrag b/kern/Makefrag
new file mode 100644 (file)
index 0000000..f0f675d
--- /dev/null
@@ -0,0 +1,84 @@
+#
+# Makefile fragment for JOS kernel.
+# This is NOT a complete makefile;
+# you must run GNU make in the top-level directory
+# where the GNUmakefile is located.
+#
+
+OBJDIRS += kern
+
+KERN_LDFLAGS := $(LDFLAGS) -T kern/kernel.ld -nostdlib
+
+# entry.S must be first, so that it's the first code in the text segment!!!
+#
+# We also snatch the use of a couple handy source files
+# from the lib directory, to avoid gratuitous code duplication.
+KERN_SRCFILES :=       kern/entry.S \
+                       kern/init.c \
+                       kern/console.c \
+                       kern/monitor.c \
+                       kern/pmap.c \
+                       kern/env.c \
+                       kern/kclock.c \
+                       kern/picirq.c \
+                       kern/printf.c \
+                       kern/trap.c \
+                       kern/trapentry.S \
+                       kern/sched.c \
+                       kern/syscall.c \
+                       kern/kdebug.c \
+                       lib/printfmt.c \
+                       lib/readline.c \
+                       lib/string.c
+
+# Only build files if they exist.
+KERN_SRCFILES := $(wildcard $(KERN_SRCFILES))
+
+KERN_BINFILES := 
+
+KERN_OBJFILES := $(patsubst %.c, $(OBJDIR)/%.o, $(KERN_SRCFILES))
+KERN_OBJFILES := $(patsubst %.S, $(OBJDIR)/%.o, $(KERN_OBJFILES))
+KERN_OBJFILES := $(patsubst obj/lib/%, obj/kern/%, $(KERN_OBJFILES))
+
+KERN_BINFILES := $(patsubst %, $(OBJDIR)/%, $(KERN_BINFILES))
+
+# How to build kernel object files
+$(OBJDIR)/kern/%.o: kern/%.c
+       @echo + cc $<
+       @mkdir -p $(@D)
+       $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $<
+
+$(OBJDIR)/kern/%.o: kern/%.S
+       @echo + as $<
+       @mkdir -p $(@D)
+       $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $<
+
+$(OBJDIR)/kern/%.o: lib/%.c
+       @echo + cc $<
+       @mkdir -p $(@D)
+       $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $<
+
+# How to build the kernel itself
+$(OBJDIR)/kern/kernel: $(KERN_OBJFILES) $(KERN_BINFILES) kern/kernel.ld
+       @echo + ld $@
+       $(V)$(LD) -o $@ $(KERN_LDFLAGS) $(KERN_OBJFILES) $(GCC_LIB) -b binary $(KERN_BINFILES)
+       $(V)$(OBJDUMP) -S $@ > $@.asm
+       $(V)$(NM) -n $@ > $@.sym
+
+# How to build the Bochs disk image
+$(OBJDIR)/kern/bochs.img: $(OBJDIR)/kern/kernel $(OBJDIR)/boot/boot
+       @echo + mk $@
+       $(V)dd if=/dev/zero of=$(OBJDIR)/kern/bochs.img~ count=10000 2>/dev/null
+       $(V)dd if=$(OBJDIR)/boot/boot of=$(OBJDIR)/kern/bochs.img~ conv=notrunc 2>/dev/null
+       $(V)dd if=$(OBJDIR)/kern/kernel of=$(OBJDIR)/kern/bochs.img~ seek=1 conv=notrunc 2>/dev/null
+       $(V)mv $(OBJDIR)/kern/bochs.img~ $(OBJDIR)/kern/bochs.img
+       $(V)cp $(OBJDIR)/kern/kernel mnt/hdd/texas
+       $(V)sync
+
+all: $(OBJDIR)/kern/bochs.img
+
+grub: $(OBJDIR)/jos-grub
+
+$(OBJDIR)/jos-grub: $(OBJDIR)/kern/kernel
+       @echo + oc $@
+       $(V)$(OBJCOPY) --adjust-vma=0x10000000 $^ $@
diff --git a/kern/console.c b/kern/console.c
new file mode 100644 (file)
index 0000000..b28ef83
--- /dev/null
@@ -0,0 +1,456 @@
+/* See COPYRIGHT for copyright information. */
+
+#include <inc/x86.h>
+#include <inc/memlayout.h>
+#include <inc/kbdreg.h>
+#include <inc/string.h>
+#include <inc/assert.h>
+
+#include <kern/console.h>
+
+
+void cons_intr(int (*proc)(void));
+
+
+/***** Serial I/O code *****/
+
+#define COM1           0x3F8
+
+#define COM_RX         0       // In:  Receive buffer (DLAB=0)
+#define COM_DLL                0       // Out: Divisor Latch Low (DLAB=1)
+#define COM_DLM                1       // Out: Divisor Latch High (DLAB=1)
+#define COM_IER                1       // Out: Interrupt Enable Register
+#define   COM_IER_RDI  0x01    //   Enable receiver data interrupt
+#define COM_IIR                2       // In:  Interrupt ID Register
+#define COM_FCR                2       // Out: FIFO Control Register
+#define COM_LCR                3       // Out: Line Control Register
+#define          COM_LCR_DLAB  0x80    //   Divisor latch access bit
+#define          COM_LCR_WLEN8 0x03    //   Wordlength: 8 bits
+#define COM_MCR                4       // Out: Modem Control Register
+#define          COM_MCR_RTS   0x02    // RTS complement
+#define          COM_MCR_DTR   0x01    // DTR complement
+#define          COM_MCR_OUT2  0x08    // Out2 complement
+#define COM_LSR                5       // In:  Line Status Register
+#define   COM_LSR_DATA 0x01    //   Data available
+
+static bool serial_exists;
+
+int
+serial_proc_data(void)
+{
+       if (!(inb(COM1+COM_LSR) & COM_LSR_DATA))
+               return -1;
+       return inb(COM1+COM_RX);
+}
+
+void
+serial_intr(void)
+{
+       if (serial_exists)
+               cons_intr(serial_proc_data);
+}
+
+void
+serial_init(void)
+{
+       // Turn off the FIFO
+       outb(COM1+COM_FCR, 0);
+       
+       // Set speed; requires DLAB latch
+       outb(COM1+COM_LCR, COM_LCR_DLAB);
+       outb(COM1+COM_DLL, (uint8_t) (115200 / 9600));
+       outb(COM1+COM_DLM, 0);
+
+       // 8 data bits, 1 stop bit, parity off; turn off DLAB latch
+       outb(COM1+COM_LCR, COM_LCR_WLEN8 & ~COM_LCR_DLAB);
+
+       // No modem controls
+       outb(COM1+COM_MCR, 0);
+       // Enable rcv interrupts
+       outb(COM1+COM_IER, COM_IER_RDI);
+
+       // Clear any preexisting overrun indications and interrupts
+       // Serial port doesn't exist if COM_LSR returns 0xFF
+       serial_exists = (inb(COM1+COM_LSR) != 0xFF);
+       (void) inb(COM1+COM_IIR);
+       (void) inb(COM1+COM_RX);
+
+}
+
+
+
+/***** Parallel port output code *****/
+// For information on PC parallel port programming, see the class References
+// page.
+
+// Stupid I/O delay routine necessitated by historical PC design flaws
+static void
+delay(void)
+{
+       inb(0x84);
+       inb(0x84);
+       inb(0x84);
+       inb(0x84);
+}
+
+static void
+lpt_putc(int c)
+{
+       int i;
+
+       for (i = 0; !(inb(0x378+1) & 0x80) && i < 12800; i++)
+               delay();
+       outb(0x378+0, c);
+       outb(0x378+2, 0x08|0x04|0x01);
+       outb(0x378+2, 0x08);
+}
+
+
+
+
+/***** Text-mode CGA/VGA display output *****/
+
+static unsigned addr_6845;
+static uint16_t *crt_buf;
+static uint16_t crt_pos;
+
+void
+cga_init(void)
+{
+       volatile uint16_t *cp;
+       uint16_t was;
+       unsigned pos;
+
+       cp = (uint16_t*) (KERNBASE + CGA_BUF);
+       was = *cp;
+       *cp = (uint16_t) 0xA55A;
+       if (*cp != 0xA55A) {
+               cp = (uint16_t*) (KERNBASE + MONO_BUF);
+               addr_6845 = MONO_BASE;
+       } else {
+               *cp = was;
+               addr_6845 = CGA_BASE;
+       }
+       
+       /* Extract cursor location */
+       outb(addr_6845, 14);
+       pos = inb(addr_6845 + 1) << 8;
+       outb(addr_6845, 15);
+       pos |= inb(addr_6845 + 1);
+
+       crt_buf = (uint16_t*) cp;
+       crt_pos = pos;
+}
+
+
+
+void
+cga_putc(int c)
+{
+       // if no attribute given, then use black on white
+       if (!(c & ~0xFF))
+               c |= 0x0700;
+
+       switch (c & 0xff) {
+       case '\b':
+               if (crt_pos > 0) {
+                       crt_pos--;
+                       crt_buf[crt_pos] = (c & ~0xff) | ' ';
+               }
+               break;
+       case '\n':
+               crt_pos += CRT_COLS;
+               /* fallthru */
+       case '\r':
+               crt_pos -= (crt_pos % CRT_COLS);
+               break;
+       case '\t':
+               cons_putc(' ');
+               cons_putc(' ');
+               cons_putc(' ');
+               cons_putc(' ');
+               cons_putc(' ');
+               break;
+       default:
+               crt_buf[crt_pos++] = c;         /* write the character */
+               break;
+       }
+
+       // What is the purpose of this?
+       if (crt_pos >= CRT_SIZE) {
+               int i;
+
+               memcpy(crt_buf, crt_buf + CRT_COLS, (CRT_SIZE - CRT_COLS) * sizeof(uint16_t));
+               for (i = CRT_SIZE - CRT_COLS; i < CRT_SIZE; i++)
+                       crt_buf[i] = 0x0700 | ' ';
+               crt_pos -= CRT_COLS;
+       }
+
+       /* move that little blinky thing */
+       outb(addr_6845, 14);
+       outb(addr_6845 + 1, crt_pos >> 8);
+       outb(addr_6845, 15);
+       outb(addr_6845 + 1, crt_pos);
+}
+
+
+/***** Keyboard input code *****/
+
+#define NO             0
+
+#define SHIFT          (1<<0)
+#define CTL            (1<<1)
+#define ALT            (1<<2)
+
+#define CAPSLOCK       (1<<3)
+#define NUMLOCK                (1<<4)
+#define SCROLLLOCK     (1<<5)
+
+#define E0ESC          (1<<6)
+
+static uint8_t shiftcode[256] = 
+{
+       [0x1D] CTL,
+       [0x2A] SHIFT,
+       [0x36] SHIFT,
+       [0x38] ALT,
+       [0x9D] CTL,
+       [0xB8] ALT
+};
+
+static uint8_t togglecode[256] = 
+{
+       [0x3A] CAPSLOCK,
+       [0x45] NUMLOCK,
+       [0x46] SCROLLLOCK
+};
+
+static uint8_t normalmap[256] =
+{
+       NO,   0x1B, '1',  '2',  '3',  '4',  '5',  '6',  // 0x00
+       '7',  '8',  '9',  '0',  '-',  '=',  '\b', '\t',
+       'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',  // 0x10
+       'o',  'p',  '[',  ']',  '\n', NO,   'a',  's',
+       'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';',  // 0x20
+       '\'', '`',  NO,   '\\', 'z',  'x',  'c',  'v',
+       'b',  'n',  'm',  ',',  '.',  '/',  NO,   '*',  // 0x30
+       NO,   ' ',  NO,   NO,   NO,   NO,   NO,   NO,
+       NO,   NO,   NO,   NO,   NO,   NO,   NO,   '7',  // 0x40
+       '8',  '9',  '-',  '4',  '5',  '6',  '+',  '1',
+       '2',  '3',  '0',  '.',  NO,   NO,   NO,   NO,   // 0x50
+       [0xC7] KEY_HOME,        [0x9C] '\n' /*KP_Enter*/,
+       [0xB5] '/' /*KP_Div*/,  [0xC8] KEY_UP,
+       [0xC9] KEY_PGUP,        [0xCB] KEY_LF,
+       [0xCD] KEY_RT,          [0xCF] KEY_END,
+       [0xD0] KEY_DN,          [0xD1] KEY_PGDN,
+       [0xD2] KEY_INS,         [0xD3] KEY_DEL
+};
+
+static uint8_t shiftmap[256] = 
+{
+       NO,   033,  '!',  '@',  '#',  '$',  '%',  '^',  // 0x00
+       '&',  '*',  '(',  ')',  '_',  '+',  '\b', '\t',
+       'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I',  // 0x10
+       'O',  'P',  '{',  '}',  '\n', NO,   'A',  'S',
+       'D',  'F',  'G',  'H',  'J',  'K',  'L',  ':',  // 0x20
+       '"',  '~',  NO,   '|',  'Z',  'X',  'C',  'V',
+       'B',  'N',  'M',  '<',  '>',  '?',  NO,   '*',  // 0x30
+       NO,   ' ',  NO,   NO,   NO,   NO,   NO,   NO,
+       NO,   NO,   NO,   NO,   NO,   NO,   NO,   '7',  // 0x40
+       '8',  '9',  '-',  '4',  '5',  '6',  '+',  '1',
+       '2',  '3',  '0',  '.',  NO,   NO,   NO,   NO,   // 0x50
+       [0xC7] KEY_HOME,        [0x9C] '\n' /*KP_Enter*/,
+       [0xB5] '/' /*KP_Div*/,  [0xC8] KEY_UP,
+       [0xC9] KEY_PGUP,        [0xCB] KEY_LF,
+       [0xCD] KEY_RT,          [0xCF] KEY_END,
+       [0xD0] KEY_DN,          [0xD1] KEY_PGDN,
+       [0xD2] KEY_INS,         [0xD3] KEY_DEL
+};
+
+#define C(x) (x - '@')
+
+static uint8_t ctlmap[256] = 
+{
+       NO,      NO,      NO,      NO,      NO,      NO,      NO,      NO, 
+       NO,      NO,      NO,      NO,      NO,      NO,      NO,      NO, 
+       C('Q'),  C('W'),  C('E'),  C('R'),  C('T'),  C('Y'),  C('U'),  C('I'),
+       C('O'),  C('P'),  NO,      NO,      '\r',    NO,      C('A'),  C('S'),
+       C('D'),  C('F'),  C('G'),  C('H'),  C('J'),  C('K'),  C('L'),  NO, 
+       NO,      NO,      NO,      C('\\'), C('Z'),  C('X'),  C('C'),  C('V'),
+       C('B'),  C('N'),  C('M'),  NO,      NO,      C('/'),  NO,      NO,
+       [0x97] KEY_HOME,
+       [0xB5] C('/'),          [0xC8] KEY_UP,
+       [0xC9] KEY_PGUP,        [0xCB] KEY_LF,
+       [0xCD] KEY_RT,          [0xCF] KEY_END,
+       [0xD0] KEY_DN,          [0xD1] KEY_PGDN,
+       [0xD2] KEY_INS,         [0xD3] KEY_DEL
+};
+
+static uint8_t *charcode[4] = {
+       normalmap,
+       shiftmap,
+       ctlmap,
+       ctlmap
+};
+
+/*
+ * Get data from the keyboard.  If we finish a character, return it.  Else 0.
+ * Return -1 if no data.
+ */
+static int
+kbd_proc_data(void)
+{
+       int c;
+       uint8_t data;
+       static uint32_t shift;
+
+       if ((inb(KBSTATP) & KBS_DIB) == 0)
+               return -1;
+
+       data = inb(KBDATAP);
+
+       if (data == 0xE0) {
+               // E0 escape character
+               shift |= E0ESC;
+               return 0;
+       } else if (data & 0x80) {
+               // Key released
+               data = (shift & E0ESC ? data : data & 0x7F);
+               shift &= ~(shiftcode[data] | E0ESC);
+               return 0;
+       } else if (shift & E0ESC) {
+               // Last character was an E0 escape; or with 0x80
+               data |= 0x80;
+               shift &= ~E0ESC;
+       }
+
+       shift |= shiftcode[data];
+       shift ^= togglecode[data];
+
+       c = charcode[shift & (CTL | SHIFT)][data];
+       if (shift & CAPSLOCK) {
+               if ('a' <= c && c <= 'z')
+                       c += 'A' - 'a';
+               else if ('A' <= c && c <= 'Z')
+                       c += 'a' - 'A';
+       }
+
+       // Process special keys
+       // Ctrl-Alt-Del: reboot
+       if (!(~shift & (CTL | ALT)) && c == KEY_DEL) {
+               cprintf("Rebooting!\n");
+               outb(0x92, 0x3); // courtesy of Chris Frost
+       }
+
+       return c;
+}
+
+void
+kbd_intr(void)
+{
+       cons_intr(kbd_proc_data);
+}
+
+void
+kbd_init(void)
+{
+}
+
+
+
+/***** General device-independent console code *****/
+// Here we manage the console input buffer,
+// where we stash characters received from the keyboard or serial port
+// whenever the corresponding interrupt occurs.
+
+#define CONSBUFSIZE 512
+
+static struct {
+       uint8_t buf[CONSBUFSIZE];
+       uint32_t rpos;
+       uint32_t wpos;
+} cons;
+
+// called by device interrupt routines to feed input characters
+// into the circular console input buffer.
+void
+cons_intr(int (*proc)(void))
+{
+       int c;
+
+       while ((c = (*proc)()) != -1) {
+               if (c == 0)
+                       continue;
+               cons.buf[cons.wpos++] = c;
+               if (cons.wpos == CONSBUFSIZE)
+                       cons.wpos = 0;
+       }
+}
+
+// return the next input character from the console, or 0 if none waiting
+int
+cons_getc(void)
+{
+       int c;
+
+       // poll for any pending input characters,
+       // so that this function works even when interrupts are disabled
+       // (e.g., when called from the kernel monitor).
+       serial_intr();
+       kbd_intr();
+
+       // grab the next character from the input buffer.
+       if (cons.rpos != cons.wpos) {
+               c = cons.buf[cons.rpos++];
+               if (cons.rpos == CONSBUFSIZE)
+                       cons.rpos = 0;
+               return c;
+       }
+       return 0;
+}
+
+// output a character to the console
+void
+cons_putc(int c)
+{
+       lpt_putc(c);
+       cga_putc(c);
+}
+
+// initialize the console devices
+void
+cons_init(void)
+{
+       cga_init();
+       kbd_init();
+       serial_init();
+
+       if (!serial_exists)
+               cprintf("Serial port does not exist!\n");
+}
+
+
+// `High'-level console I/O.  Used by readline and cprintf.
+
+void
+cputchar(int c)
+{
+       cons_putc(c);
+}
+
+int
+getchar(void)
+{
+       int c;
+
+       while ((c = cons_getc()) == 0)
+               /* do nothing */;
+       return c;
+}
+
+int
+iscons(int fdnum)
+{
+       // used by readline
+       return 1;
+}
diff --git a/kern/console.h b/kern/console.h
new file mode 100644 (file)
index 0000000..d78a6e0
--- /dev/null
@@ -0,0 +1,27 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifndef _CONSOLE_H_
+#define _CONSOLE_H_
+#ifndef JOS_KERNEL
+# error "This is a JOS kernel header; user programs should not #include it"
+#endif
+
+#include <inc/types.h>
+
+#define MONO_BASE      0x3B4
+#define MONO_BUF       0xB0000
+#define CGA_BASE       0x3D4
+#define CGA_BUF                0xB8000
+
+#define CRT_ROWS       25
+#define CRT_COLS       80
+#define CRT_SIZE       (CRT_ROWS * CRT_COLS)
+
+void cons_init(void);
+void cons_putc(int c);
+int cons_getc(void);
+
+void kbd_intr(void); // irq 1
+void serial_intr(void); // irq 4
+
+#endif /* _CONSOLE_H_ */
diff --git a/kern/entry.S b/kern/entry.S
new file mode 100644 (file)
index 0000000..27e5e23
--- /dev/null
@@ -0,0 +1,108 @@
+/* See COPYRIGHT for copyright information. */
+
+#include <inc/mmu.h>
+#include <inc/memlayout.h>
+
+# Shift Right Logical 
+#define SRL(val, shamt)                (((val) >> (shamt)) & ~(-1 << (32 - (shamt))))
+
+
+###################################################################
+# The kernel (this code) is linked at address (KERNBASE + 1 Meg), 
+# but the bootloader loads it at address 1 Meg.
+# Kernbase is set for a 3g/1g split
+#      
+# RELOC(x) maps a symbol x from its link address to its actual
+# location in physical memory (its load address).       
+###################################################################
+
+#define        RELOC(x) ((x) - KERNBASE)
+
+
+.set CODE_SEL,0x8              # index of code seg within mygdt
+.set DATA_SEL,0x10             # index of data seg within mygdt
+
+#define MULTIBOOT_PAGE_ALIGN  (1<<0)
+#define MULTIBOOT_MEMORY_INFO (1<<1)
+#define MULTIBOOT_HEADER_MAGIC (0x1BADB002)
+#define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN)
+#define CHECKSUM (-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS))
+
+###################################################################
+# entry point
+###################################################################
+
+.text
+
+# The Multiboot header
+.align 4
+.long MULTIBOOT_HEADER_MAGIC
+.long MULTIBOOT_HEADER_FLAGS
+.long CHECKSUM
+
+.globl         _start
+_start:
+       movw    $0x1234,0x472                   # warm boot
+
+       # Establish our own GDT in place of the boot loader's temporary GDT.
+       lgdt    RELOC(mygdtdesc)                # load descriptor table
+
+       # Immediately reload all segment registers (including CS!)
+       # with segment selectors from the new GDT.
+       movl    $DATA_SEL, %eax                 # Data segment selector
+       movw    %ax,%ds                         # -> DS: Data Segment
+       movw    %ax,%es                         # -> ES: Extra Segment
+       movw    %ax,%ss                         # -> SS: Stack Segment
+       ljmp    $CODE_SEL,$relocated            # reload CS by jumping
+relocated:
+
+       # Clear the frame pointer register (EBP)
+       # so that once we get into debugging C code,
+       # stack backtraces will be terminated properly.
+       movl    $0x0,%ebp                       # nuke frame pointer
+
+    # Set the stack pointer
+       movl    $(bootstacktop),%esp
+
+       # Save multiboot info
+       push    %ebx
+
+       # now to C code
+       call    kernel_init
+
+       # Should never get here, but in case we do, just spin.
+spin:  jmp     spin
+
+
+###################################################################    
+# See <inc/memlayout.h> for a complete description of these two symbols.
+###################################################################
+.data
+       .globl  vpt
+       .set    vpt, VPT
+       .globl  vpd
+       .set    vpd, (VPT + SRL(VPT, 10))
+
+
+###################################################################
+# boot stack
+###################################################################
+       .p2align        PGSHIFT         # force page alignment
+       .globl          bootstack
+bootstack:
+       .space          KSTKSIZE
+       .globl          bootstacktop   
+bootstacktop:
+
+###################################################################
+# setup the GDT        
+###################################################################
+       .p2align        2               # force 4 byte alignment
+mygdt:
+       SEG_NULL                                # null seg
+       SEG(STA_X|STA_R, -KERNBASE, 0xffffffff) # code seg
+       SEG(STA_W, -KERNBASE, 0xffffffff)       # data seg
+mygdtdesc:
+       .word   0x17                    # sizeof(mygdt) - 1
+       .long   RELOC(mygdt)            # address mygdt
+
diff --git a/kern/init.c b/kern/init.c
new file mode 100644 (file)
index 0000000..adb49fd
--- /dev/null
@@ -0,0 +1,136 @@
+/* See COPYRIGHT for copyright information. */
+
+#include <inc/stdio.h>
+#include <inc/string.h>
+#include <inc/assert.h>
+#include <inc/multiboot.h>
+#include <inc/elf.h>
+
+#include <kern/monitor.h>
+#include <kern/console.h>
+
+// Test the stack backtrace function (lab 1 only)
+void
+test_backtrace(int x)
+{
+       cprintf("entering test_backtrace %d\n", x);
+       if (x > 0)
+               test_backtrace(x-1);
+       else
+               mon_backtrace(0, 0, 0);
+       cprintf("leaving test_backtrace %d\n", x);
+}
+
+void
+kernel_init(multiboot_info_t *mboot_info)
+{
+       extern char edata[], end[];
+
+       // Before doing anything else, complete the ELF loading process.
+       // Clear the uninitialized global data (BSS) section of our program.
+       // This ensures that all static/global variables start out zero.
+       memset(edata, 0, end - edata);
+
+       // Initialize the console.
+       // Can't call cprintf until after we do this!
+       cons_init();
+
+       /*
+       extern stab_t stab[], estab[];
+       extern char stabstr[];
+       stab_t* symtab;
+       // Spits out the stabs for functions
+       for (symtab = stab; symtab < estab; symtab++) {
+               // gives us only functions.  not really needed if we scan by address
+               if (symtab->n_type != 36)
+                       continue;
+               cprintf("Symbol name = %s\n", stabstr + symtab->n_strx);
+               cprintf("Symbol type = %d\n", symtab->n_type);
+               cprintf("Symbol value = 0x%x\n", symtab->n_value);
+               cprintf("\n");
+       }
+       */
+
+       // Test the stack backtrace function (lab 1 only)
+       test_backtrace(5);
+
+       // Drop into the kernel monitor.
+       while (1)
+               monitor(NULL);
+}
+
+
+/*
+ * Variable panicstr contains argument to first call to panic; used as flag
+ * to indicate that the kernel has already called panic.
+ */
+static const char *panicstr;
+
+/*
+ * Panic is called on unresolvable fatal errors.
+ * It prints "panic: mesg", and then enters the kernel monitor.
+ */
+void
+_panic(const char *file, int line, const char *fmt,...)
+{
+       va_list ap;
+
+       if (panicstr)
+               goto dead;
+       panicstr = fmt;
+
+       va_start(ap, fmt);
+       cprintf("kernel panic at %s:%d: ", file, line);
+       vcprintf(fmt, ap);
+       cprintf("\n");
+       va_end(ap);
+
+dead:
+       /* break into the kernel monitor */
+       while (1)
+               monitor(NULL);
+}
+
+/* like panic, but don't */
+void
+_warn(const char *file, int line, const char *fmt,...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       cprintf("kernel warning at %s:%d: ", file, line);
+       vcprintf(fmt, ap);
+       cprintf("\n");
+       va_end(ap);
+}
+
+
+       /* Backup of old shit that i hoard for no reason
+        *
+        * all of this was in kernel_init
+       cprintf("6828 decimal is %o octal!\n", 6828);
+       cprintf("Symtab section should begin at: 0x%x \n", stab);
+
+       // double check
+       mboot_info = (multiboot_info_t*)(0xc0000000 + (char*)mboot_info);
+       cprintf("Mboot info address: %p\n", mboot_info);
+       elf_section_header_table_t *elf_head= &(mboot_info->u.elf_sec);
+       cprintf("elf sec info address: %p\n", elf_head);
+    cprintf ("elf_sec: num = %u, size = 0x%x, addr = 0x%x, shndx = 0x%x\n",
+            elf_head->num, elf_head->size,
+            elf_head->addr, elf_head->shndx);
+       
+       struct Secthdr *elf_sym = (struct Secthdr*)(0xc0000000 + elf_head->addr + elf_head->size * 3);
+
+       cprintf("Symtab multiboot struct address: %p\n", elf_sym);
+       cprintf("Symtab multiboot address: %p\n", elf_sym->sh_addr);
+
+       // this walks a symtable, but we don't have one...
+       Elf32_Sym* symtab = (Elf32_Sym*)stab;
+       Elf32_Sym* oldsymtab = symtab;
+       for (; symtab < oldsymtab + 10 ; symtab++) {
+               cprintf("Symbol name index = 0x%x\n", symtab->st_name);
+               //cprintf("Symbol name = %s\n", stabstr + symtab->st_name);
+               cprintf("Symbol vale = 0x%x\n", symtab->st_value);
+       }
+       */
diff --git a/kern/kernel.ld b/kern/kernel.ld
new file mode 100644 (file)
index 0000000..f0b514a
--- /dev/null
@@ -0,0 +1,58 @@
+/* Simple linker script for the JOS kernel.
+   See the GNU ld 'info' manual ("info ld") to learn the syntax. */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+       /* Link the kernel for 0xC01000C0, but load it at 0x001000C0) */
+
+       .text 0xC01000C0 : AT(0x001000C0) {
+               *(.text .stub .text.* .gnu.linkonce.t.*)
+       }
+
+       PROVIDE(etext = .);     /* Define the 'etext' symbol to this value */
+
+       .rodata : {
+               *(.rodata .rodata.* .gnu.linkonce.r.*)
+       }
+
+       /* Include debugging information in kernel memory */
+       .stab : {
+               PROVIDE(stab = .);
+               *(.stab);
+               PROVIDE(estab = .);
+               BYTE(0)         /* Force the linker to allocate space
+                                  for this section */
+       }
+
+       .stabstr : {
+               PROVIDE(stabstr = .);
+               *(.stabstr);
+               PROVIDE(estabstr = .);
+               BYTE(0)         /* Force the linker to allocate space
+                                  for this section */
+       }
+
+       /* Adjust the address for the data segment to the next page */
+       . = ALIGN(0x1000);
+
+       /* The data segment */
+       .data : {
+               *(.data)
+       }
+
+       PROVIDE(edata = .);
+
+       .bss : {
+               *(.bss)
+       }
+
+       PROVIDE(end = .);
+
+       /DISCARD/ : {
+               *(.eh_frame .note.GNU-stack)
+       }
+}
diff --git a/kern/monitor.c b/kern/monitor.c
new file mode 100644 (file)
index 0000000..21ecc4a
--- /dev/null
@@ -0,0 +1,221 @@
+// Simple command-line kernel monitor useful for
+// controlling the kernel and exploring the system interactively.
+
+#include <inc/stdio.h>
+#include <inc/string.h>
+#include <inc/memlayout.h>
+#include <inc/assert.h>
+#include <inc/x86.h>
+#include <inc/elf.h>
+
+#include <kern/console.h>
+#include <kern/monitor.h>
+
+#define CMDBUF_SIZE    80      // enough for one VGA text line
+
+
+struct Command {
+       const char *name;
+       const char *desc;
+       // return -1 to force monitor to exit
+       int (*func)(int argc, char** argv, struct Trapframe* tf);
+};
+
+static struct Command commands[] = {
+       { "help", "Display this list of commands", mon_help },
+       { "kerninfo", "Display information about the kernel", mon_kerninfo },
+       { "backtrace", "Dump a backtrace", mon_backtrace },
+       { "reboot", "Take a ride to the South Bay", mon_reboot },
+};
+#define NCOMMANDS (sizeof(commands)/sizeof(commands[0]))
+
+unsigned read_eip();
+
+/***** Implementations of basic kernel monitor commands *****/
+
+int
+mon_help(int argc, char **argv, struct Trapframe *tf)
+{
+       int i;
+
+       for (i = 0; i < NCOMMANDS; i++)
+               cprintf("%s - %s\n", commands[i].name, commands[i].desc);
+       return 0;
+}
+
+int
+mon_kerninfo(int argc, char **argv, struct Trapframe *tf)
+{
+       extern char _start[], etext[], edata[], end[];
+
+       cprintf("Special kernel symbols:\n");
+       cprintf("  _start %08x (virt)  %08x (phys)\n", _start, _start - KERNBASE);
+       cprintf("  etext  %08x (virt)  %08x (phys)\n", etext, etext - KERNBASE);
+       cprintf("  edata  %08x (virt)  %08x (phys)\n", edata, edata - KERNBASE);
+       cprintf("  end    %08x (virt)  %08x (phys)\n", end, end - KERNBASE);
+       cprintf("Kernel executable memory footprint: %dKB\n",
+               (end-_start+1023)/1024);
+       return 0;
+}
+
+char* function_of(uint32_t address) 
+{
+       extern stab_t stab[], estab[];
+       extern char stabstr[];
+       stab_t* symtab;
+       stab_t* best_symtab = 0;
+       uint32_t best_func = 0;
+       
+       // ugly and unsorted
+       for (symtab = stab; symtab < estab; symtab++) {
+               // only consider functions, type = 36
+               if ((symtab->n_type == 36) && 
+                   (symtab->n_value <= address) && 
+                       (symtab->n_value > best_func)) {
+                       best_func = symtab->n_value;
+                       best_symtab = symtab;
+               }
+       }
+       // maybe the first stab really is the right one...  we'll see.
+       if (best_symtab == 0)
+               return "Function not found!";
+       return stabstr + best_symtab->n_strx;
+}
+
+int
+mon_backtrace(int argc, char **argv, struct Trapframe *tf)
+{
+       uint32_t* ebp, eip;
+       int i = 1;
+       ebp = (uint32_t*)read_ebp();    
+       // this is the retaddr for what called backtrace
+       eip = *(ebp + 1);
+       // jump back a frame (out of mon_backtrace)
+       ebp = (uint32_t*)(*ebp);
+       cprintf("Stack Backtrace:\n");
+       // on each iteration, ebp holds the stack frame and eip is a retaddr in that func
+       while (ebp != 0) {
+               cprintf("%02d EBP: %x EIP: %x Function: %s\n   Args: %08x %08x %08x %08x %08x\n",
+                               i++,
+                       ebp,
+                               eip,
+                               function_of(eip),
+                               *(ebp + 2),
+                               *(ebp + 3),
+                               *(ebp + 4),
+                               *(ebp + 5),
+                               *(ebp + 6)
+                               );
+               eip = *(ebp + 1);
+               ebp = (uint32_t*)(*ebp);
+       }
+
+       return 0;
+}
+
+int
+mon_reboot(int argc, char **argv, struct Trapframe *tf)
+{
+       cprintf("[Irish Accent]: She's goin' down, Cap'n!\n");
+       outb(0x92, 0x3);
+       cprintf("Should have rebooted.  Doesn't work yet in KVM...\n");
+       return 0;
+}
+
+
+
+/***** Kernel monitor command interpreter *****/
+
+#define WHITESPACE "\t\r\n "
+#define MAXARGS 16
+
+static int
+runcmd(char *buf, struct Trapframe *tf)
+{
+       int argc;
+       char *argv[MAXARGS];
+       int i;
+
+       // Parse the command buffer into whitespace-separated arguments
+       argc = 0;
+       argv[argc] = 0;
+       while (1) {
+               // gobble whitespace
+               while (*buf && strchr(WHITESPACE, *buf))
+                       *buf++ = 0;
+               if (*buf == 0)
+                       break;
+
+               // save and scan past next arg
+               if (argc == MAXARGS-1) {
+                       cprintf("Too many arguments (max %d)\n", MAXARGS);
+                       return 0;
+               }
+               argv[argc++] = buf;
+               while (*buf && !strchr(WHITESPACE, *buf))
+                       buf++;
+       }
+       argv[argc] = 0;
+
+       // Lookup and invoke the command
+       if (argc == 0)
+               return 0;
+       for (i = 0; i < NCOMMANDS; i++) {
+               if (strcmp(argv[0], commands[i].name) == 0)
+                       return commands[i].func(argc, argv, tf);
+       }
+       cprintf("Unknown command '%s'\n", argv[0]);
+       return 0;
+}
+
+void
+monitor(struct Trapframe *tf)
+{
+       char *buf;
+
+       cprintf("Welcome to the JOS kernel monitor!\n");
+       cprintf("Type 'help' for a list of commands.\n");
+
+
+       while (1) {
+               buf = readline("K> ");
+               if (buf != NULL)
+                       if (runcmd(buf, tf) < 0)
+                               break;
+       }
+}
+
+/*
+// return EIP of caller.
+// does not work if inlined.
+// putting at the end of the file seems to prevent inlining.
+unsigned
+read_eip()
+{
+       uint32_t callerpc;
+       __asm __volatile("movl 4(%%ebp), %0" : "=r" (callerpc));
+       return callerpc;
+}
+
+char* function_at(uint32_t address) 
+{
+       extern stab_t stab[], estab[];
+       extern char stabstr[];
+       stab_t* symtab;
+       
+       for (symtab = stab; symtab < estab; symtab++) {
+               if (symtab->n_value == address)
+                       return stabstr + symtab->n_strx;
+       }
+       return "Function not found!";
+}
+
+uint32_t called_address(uint32_t retaddr)
+{
+       // retaddr - 4 is the offset to the previous call, which
+       // gets added to the next inst after call when calling
+       return (uint32_t)(retaddr + *(uint32_t*)(retaddr - 4));
+       //used like this:
+       //function_at(called_address(*(ebp + 1))),
+}
+*/
diff --git a/kern/monitor.h b/kern/monitor.h
new file mode 100644 (file)
index 0000000..5dde6ac
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef JOS_KERN_MONITOR_H
+#define JOS_KERN_MONITOR_H
+#ifndef JOS_KERNEL
+# error "This is a JOS kernel header; user programs should not #include it"
+#endif
+
+struct Trapframe;
+
+// Activate the kernel monitor,
+// optionally providing a trap frame indicating the current state
+// (NULL if none).
+void monitor(struct Trapframe *tf);
+
+// Functions implementing monitor commands.
+int mon_help(int argc, char **argv, struct Trapframe *tf);
+int mon_kerninfo(int argc, char **argv, struct Trapframe *tf);
+int mon_backtrace(int argc, char **argv, struct Trapframe *tf);
+int mon_reboot(int argc, char **argv, struct Trapframe *tf);
+
+#endif // !JOS_KERN_MONITOR_H
diff --git a/kern/printf.c b/kern/printf.c
new file mode 100644 (file)
index 0000000..6932ca5
--- /dev/null
@@ -0,0 +1,37 @@
+// Simple implementation of cprintf console output for the kernel,
+// based on printfmt() and the kernel console's cputchar().
+
+#include <inc/types.h>
+#include <inc/stdio.h>
+#include <inc/stdarg.h>
+
+
+static void
+putch(int ch, int *cnt)
+{
+       cputchar(ch);
+       *cnt++;
+}
+
+int
+vcprintf(const char *fmt, va_list ap)
+{
+       int cnt = 0;
+
+       vprintfmt((void*)putch, &cnt, fmt, ap);
+       return cnt;
+}
+
+int
+cprintf(const char *fmt, ...)
+{
+       va_list ap;
+       int cnt;
+
+       va_start(ap, fmt);
+       cnt = vcprintf(fmt, ap);
+       va_end(ap);
+
+       return cnt;
+}
+
diff --git a/lib/printfmt.c b/lib/printfmt.c
new file mode 100644 (file)
index 0000000..d710799
--- /dev/null
@@ -0,0 +1,300 @@
+// Stripped-down primitive printf-style formatting routines,
+// used in common by printf, sprintf, fprintf, etc.
+// This code is also used by both the kernel and user programs.
+
+#include <inc/types.h>
+#include <inc/stdio.h>
+#include <inc/string.h>
+#include <inc/stdarg.h>
+#include <inc/error.h>
+
+/*
+ * Space or zero padding and a field width are supported for the numeric
+ * formats only. 
+ * 
+ * The special format %e takes an integer error code
+ * and prints a string describing the error.
+ * The integer may be positive or negative,
+ * so that -E_NO_MEM and E_NO_MEM are equivalent.
+ */
+
+static const char * const error_string[MAXERROR + 1] =
+{
+       NULL,
+       "unspecified error",
+       "bad environment",
+       "invalid parameter",
+       "out of memory",
+       "out of environments",
+       "segmentation fault",
+};
+
+/*
+ * Print a number (base <= 16) in reverse order,
+ * using specified putch function and associated pointer putdat.
+ */
+static void
+printnum(void (*putch)(int, void*), void *putdat,
+        unsigned long long num, unsigned base, int width, int padc)
+{
+       // first recursively print all preceding (more significant) digits
+       if (num >= base) {
+               printnum(putch, putdat, num / base, base, width - 1, padc);
+       } else {
+               // print any needed pad characters before first digit
+               while (--width > 0)
+                       putch(padc, putdat);
+       }
+
+       // then print this (the least significant) digit
+       putch("0123456789abcdef"[num % base], putdat);
+}
+
+// Get an unsigned int of various possible sizes from a varargs list,
+// depending on the lflag parameter.
+static unsigned long long
+getuint(va_list *ap, int lflag)
+{
+       if (lflag >= 2)
+               return va_arg(*ap, unsigned long long);
+       else if (lflag)
+               return va_arg(*ap, unsigned long);
+       else
+               return va_arg(*ap, unsigned int);
+}
+
+// Same as getuint but signed - can't use getuint
+// because of sign extension
+static long long
+getint(va_list *ap, int lflag)
+{
+       if (lflag >= 2)
+               return va_arg(*ap, long long);
+       else if (lflag)
+               return va_arg(*ap, long);
+       else
+               return va_arg(*ap, int);
+}
+
+
+// Main function to format and print a string.
+void printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...);
+
+void
+vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list ap)
+{
+       register const char *p;
+       register int ch, err;
+       unsigned long long num;
+       int base, lflag, width, precision, altflag;
+       char padc;
+
+       while (1) {
+               while ((ch = *(unsigned char *) fmt++) != '%') {
+                       if (ch == '\0')
+                               return;
+                       putch(ch, putdat);
+               }
+
+               // Process a %-escape sequence
+               padc = ' ';
+               width = -1;
+               precision = -1;
+               lflag = 0;
+               altflag = 0;
+       reswitch:
+               switch (ch = *(unsigned char *) fmt++) {
+
+               // flag to pad on the right
+               case '-':
+                       padc = '-';
+                       goto reswitch;
+                       
+               // flag to pad with 0's instead of spaces
+               case '0':
+                       padc = '0';
+                       goto reswitch;
+
+               // width field
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+                       for (precision = 0; ; ++fmt) {
+                               precision = precision * 10 + ch - '0';
+                               ch = *fmt;
+                               if (ch < '0' || ch > '9')
+                                       break;
+                       }
+                       goto process_precision;
+
+               case '*':
+                       precision = va_arg(ap, int);
+                       goto process_precision;
+
+               case '.':
+                       if (width < 0)
+                               width = 0;
+                       goto reswitch;
+
+               case '#':
+                       altflag = 1;
+                       goto reswitch;
+
+               process_precision:
+                       if (width < 0)
+                               width = precision, precision = -1;
+                       goto reswitch;
+
+               // long flag (doubled for long long)
+               case 'l':
+                       lflag++;
+                       goto reswitch;
+
+               // character
+               case 'c':
+                       putch(va_arg(ap, int), putdat);
+                       break;
+
+               // error message
+               case 'e':
+                       err = va_arg(ap, int);
+                       if (err < 0)
+                               err = -err;
+                       if (err > MAXERROR || (p = error_string[err]) == NULL)
+                               printfmt(putch, putdat, "error %d", err);
+                       else
+                               printfmt(putch, putdat, "%s", p);
+                       break;
+
+               // string
+               case 's':
+                       if ((p = va_arg(ap, char *)) == NULL)
+                               p = "(null)";
+                       if (width > 0 && padc != '-')
+                               for (width -= strnlen(p, precision); width > 0; width--)
+                                       putch(padc, putdat);
+                       for (; (ch = *p++) != '\0' && (precision < 0 || --precision >= 0); width--)
+                               if (altflag && (ch < ' ' || ch > '~'))
+                                       putch('?', putdat);
+                               else
+                                       putch(ch, putdat);
+                       for (; width > 0; width--)
+                               putch(' ', putdat);
+                       break;
+
+               // (signed) decimal
+               case 'd':
+                       num = getint(&ap, lflag);
+                       if ((long long) num < 0) {
+                               putch('-', putdat);
+                               num = -(long long) num;
+                       }
+                       base = 10;
+                       goto number;
+
+               // unsigned decimal
+               case 'u':
+                       num = getuint(&ap, lflag);
+                       base = 10;
+                       goto number;
+
+               // (unsigned) octal
+               case 'o':
+                       // should do something with padding so it's always 3 octits
+                       num = getuint(&ap, lflag);
+                       base = 8;
+                       goto number;
+
+               // pointer
+               case 'p':
+                       putch('0', putdat);
+                       putch('x', putdat);
+                       num = (unsigned long long)
+                               (uintptr_t) va_arg(ap, void *);
+                       base = 16;
+                       goto number;
+
+               // (unsigned) hexadecimal
+               case 'x':
+                       num = getuint(&ap, lflag);
+                       base = 16;
+               number:
+                       printnum(putch, putdat, num, base, width, padc);
+                       break;
+
+               // escaped '%' character
+               case '%':
+                       putch(ch, putdat);
+                       break;
+                       
+               // unrecognized escape sequence - just print it literally
+               default:
+                       putch('%', putdat);
+                       for (fmt--; fmt[-1] != '%'; fmt--)
+                               /* do nothing */;
+                       break;
+               }
+       }
+}
+
+void
+printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       vprintfmt(putch, putdat, fmt, ap);
+       va_end(ap);
+}
+
+struct sprintbuf {
+       char *buf;
+       char *ebuf;
+       int cnt;
+};
+
+static void
+sprintputch(int ch, struct sprintbuf *b)
+{
+       b->cnt++;
+       if (b->buf < b->ebuf)
+               *b->buf++ = ch;
+}
+
+int
+vsnprintf(char *buf, int n, const char *fmt, va_list ap)
+{
+       struct sprintbuf b = {buf, buf+n-1, 0};
+
+       if (buf == NULL || n < 1)
+               return -E_INVAL;
+
+       // print the string to the buffer
+       vprintfmt((void*)sprintputch, &b, fmt, ap);
+
+       // null terminate the buffer
+       *b.buf = '\0';
+
+       return b.cnt;
+}
+
+int
+snprintf(char *buf, int n, const char *fmt, ...)
+{
+       va_list ap;
+       int rc;
+
+       va_start(ap, fmt);
+       rc = vsnprintf(buf, n, fmt, ap);
+       va_end(ap);
+
+       return rc;
+}
+
+
diff --git a/lib/readline.c b/lib/readline.c
new file mode 100644 (file)
index 0000000..7c631bd
--- /dev/null
@@ -0,0 +1,38 @@
+#include <inc/stdio.h>
+#include <inc/error.h>
+
+#define BUFLEN 1024
+static char buf[BUFLEN];
+
+char *
+readline(const char *prompt)
+{
+       int i, c, echoing;
+
+       if (prompt != NULL)
+               cprintf("%s", prompt);
+
+       i = 0;
+       echoing = iscons(0);
+       while (1) {
+               c = getchar();
+               if (c < 0) {
+                       cprintf("read error: %e\n", c);
+                       return NULL;
+               } else if (c >= ' ' && i < BUFLEN-1) {
+                       if (echoing)
+                               cputchar(c);
+                       buf[i++] = c;
+               } else if (c == '\b' && i > 0) {
+                       if (echoing)
+                               cputchar(c);
+                       i--;
+               } else if (c == '\n' || c == '\r') {
+                       if (echoing)
+                               cputchar(c);
+                       buf[i] = 0;
+                       return buf;
+               }
+       }
+}
+
diff --git a/lib/string.c b/lib/string.c
new file mode 100644 (file)
index 0000000..d3818c8
--- /dev/null
@@ -0,0 +1,226 @@
+// Basic string routines.  Not hardware optimized, but not shabby.
+
+#include <inc/string.h>
+
+int
+strlen(const char *s)
+{
+       int n;
+
+       for (n = 0; *s != '\0'; s++)
+               n++;
+       return n;
+}
+
+int
+strnlen(const char *s, size_t size)
+{
+       int n;
+
+       for (n = 0; size > 0 && *s != '\0'; s++, size--)
+               n++;
+       return n;
+}
+
+char *
+strcpy(char *dst, const char *src)
+{
+       char *ret;
+
+       ret = dst;
+       while ((*dst++ = *src++) != '\0')
+               /* do nothing */;
+       return ret;
+}
+
+char *
+strncpy(char *dst, const char *src, size_t size) {
+       size_t i;
+       char *ret;
+
+       ret = dst;
+       for (i = 0; i < size; i++) {
+               *dst++ = *src;
+               // If strlen(src) < size, null-pad 'dst' out to 'size' chars
+               if (*src != '\0')
+                       src++;
+       }
+       return ret;
+}
+
+size_t
+strlcpy(char *dst, const char *src, size_t size)
+{
+       char *dst_in;
+
+       dst_in = dst;
+       if (size > 0) {
+               while (--size > 0 && *src != '\0')
+                       *dst++ = *src++;
+               *dst = '\0';
+       }
+       return dst - dst_in;
+}
+
+int
+strcmp(const char *p, const char *q)
+{
+       while (*p && *p == *q)
+               p++, q++;
+       return (int) ((unsigned char) *p - (unsigned char) *q);
+}
+
+int
+strncmp(const char *p, const char *q, size_t n)
+{
+       while (n > 0 && *p && *p == *q)
+               n--, p++, q++;
+       if (n == 0)
+               return 0;
+       else
+               return (int) ((unsigned char) *p - (unsigned char) *q);
+}
+
+// Return a pointer to the first occurrence of 'c' in 's',
+// or a null pointer if the string has no 'c'.
+char *
+strchr(const char *s, char c)
+{
+       for (; *s; s++)
+               if (*s == c)
+                       return (char *) s;
+       return 0;
+}
+
+// Return a pointer to the first occurrence of 'c' in 's',
+// or a pointer to the string-ending null character if the string has no 'c'.
+char *
+strfind(const char *s, char c)
+{
+       for (; *s; s++)
+               if (*s == c)
+                       break;
+       return (char *) s;
+}
+
+
+void *
+memset(void *v, int c, size_t n)
+{
+       char *p;
+       int m;
+
+       p = v;
+       m = n;
+       while (--m >= 0)
+               *p++ = c;
+
+       return v;
+}
+
+void *
+memcpy(void *dst, const void *src, size_t n)
+{
+       const char *s;
+       char *d;
+
+       s = src;
+       d = dst;
+       while (n-- > 0)
+               *d++ = *s++;
+
+       return dst;
+}
+
+void *
+memmove(void *dst, const void *src, size_t n)
+{
+       const char *s;
+       char *d;
+       
+       s = src;
+       d = dst;
+       if (s < d && s + n > d) {
+               s += n;
+               d += n;
+               while (n-- > 0)
+                       *--d = *--s;
+       } else
+               while (n-- > 0)
+                       *d++ = *s++;
+
+       return dst;
+}
+
+int
+memcmp(const void *v1, const void *v2, size_t n)
+{
+       const uint8_t *s1 = (const uint8_t *) v1;
+       const uint8_t *s2 = (const uint8_t *) v2;
+
+       while (n-- > 0) {
+               if (*s1 != *s2)
+                       return (int) *s1 - (int) *s2;
+               s1++, s2++;
+       }
+
+       return 0;
+}
+
+void *
+memfind(const void *s, int c, size_t n)
+{
+       const void *ends = (const char *) s + n;
+       for (; s < ends; s++)
+               if (*(const unsigned char *) s == (unsigned char) c)
+                       break;
+       return (void *) s;
+}
+
+long
+strtol(const char *s, char **endptr, int base)
+{
+       int neg = 0;
+       long val = 0;
+
+       // gobble initial whitespace
+       while (*s == ' ' || *s == '\t')
+               s++;
+
+       // plus/minus sign
+       if (*s == '+')
+               s++;
+       else if (*s == '-')
+               s++, neg = 1;
+
+       // hex or octal base prefix
+       if ((base == 0 || base == 16) && (s[0] == '0' && s[1] == 'x'))
+               s += 2, base = 16;
+       else if (base == 0 && s[0] == '0')
+               s++, base = 8;
+       else if (base == 0)
+               base = 10;
+
+       // digits
+       while (1) {
+               int dig;
+
+               if (*s >= '0' && *s <= '9')
+                       dig = *s - '0';
+               else if (*s >= 'a' && *s <= 'z')
+                       dig = *s - 'a' + 10;
+               else if (*s >= 'A' && *s <= 'Z')
+                       dig = *s - 'A' + 10;
+               else
+                       break;
+               if (dig >= base)
+                       break;
+               s++, val = (val * base) + dig;
+               // we don't properly detect overflow!
+       }
+
+       if (endptr)
+               *endptr = (char *) s;
+       return (neg ? -val : val);
+}
+
diff --git a/mergedep.pl b/mergedep.pl
new file mode 100644 (file)
index 0000000..1730d53
--- /dev/null
@@ -0,0 +1,86 @@
+#!/usr/bin/perl
+# Copyright 2003 Bryan Ford
+# Distributed under the GNU General Public License.
+#
+# Usage: mergedep <main-depfile> [<new-depfiles> ...]
+#
+# This script merges the contents of all <new-depfiles> specified
+# on the command line into the single file <main-depfile>,
+# which may or may not previously exist.
+# Dependencies in the <new-depfiles> will override
+# any existing dependencies for the same targets in <main-depfile>.
+# The <new-depfiles> are deleted after <main-depfile> is updated.
+#
+# The <new-depfiles> are typically generated by GCC with the -MD option,
+# and the <main-depfile> is typically included from a Makefile,
+# as shown here for GNU 'make':
+#
+#      .deps: $(wildcard *.d)
+#              perl mergedep $@ $^
+#      -include .deps
+#
+# This script properly handles multiple dependencies per <new-depfile>,
+# including dependencies having no target,
+# so it is compatible with GCC3's -MP option.
+#
+
+sub readdeps {
+       my $filename = shift;
+
+       open(DEPFILE, $filename) or return 0;
+       while (<DEPFILE>) {
+               if (/([^:]*):([^\\:]*)([\\]?)$/) {
+                       my $target = $1;
+                       my $deplines = $2;
+                       my $slash = $3;
+                       while ($slash ne '') {
+                               $_ = <DEPFILE>;
+                               defined($_) or die
+                                       "Unterminated dependency in $filename";
+                               /(^[ \t][^\\]*)([\\]?)$/ or die
+                                       "Bad continuation line in $filename";
+                               $deplines = "$deplines\\\n$1";
+                               $slash = $2;
+                       }
+                       #print "DEPENDENCY [[$target]]: [[$deplines]]\n";
+                       $dephash{$target} = $deplines;
+               } elsif (/^[#]?[ \t]*$/) {
+                       # ignore blank lines and comments
+               } else {
+                       die "Bad dependency line in $filename: $_";
+               }
+       }
+       close DEPFILE;
+       return 1;
+}
+
+
+if ($#ARGV < 0) {
+       print "Usage: mergedep <main-depfile> [<new-depfiles> ..]\n";
+       exit(1);
+}
+
+%dephash = ();
+
+# Read the main dependency file
+$maindeps = $ARGV[0];
+readdeps($maindeps);
+
+# Read and merge in the new dependency files
+foreach $i (1 .. $#ARGV) {
+       readdeps($ARGV[$i]) or die "Can't open $ARGV[$i]";
+}
+
+# Update the main dependency file
+open(DEPFILE, ">$maindeps.tmp") or die "Can't open output file $maindeps.tmp";
+foreach $target (keys %dephash) {
+       print DEPFILE "$target:$dephash{$target}";
+}
+close DEPFILE;
+rename("$maindeps.tmp", "$maindeps") or die "Can't overwrite $maindeps";
+
+# Finally, delete the new dependency files
+foreach $i (1 .. $#ARGV) {
+       unlink($ARGV[$i]) or print "Error removing $ARGV[$i]\n";
+}
+
diff --git a/user/testpmap.c b/user/testpmap.c
new file mode 100644 (file)
index 0000000..f38cff5
--- /dev/null
@@ -0,0 +1,215 @@
+//#ifdef LAB >= 4
+
+#include <inc/lib.h>
+
+int sequence_length = 16;
+int sequence[] = { 0,  1,   1,   2,   3, 
+                  5,  8,  13,  21,  34, 
+                 55, 89, 144, 233, 377, 610};
+
+void
+mark_page(int* pg, int i) {
+  memset(pg, 0, PGSIZE);
+
+  // now dump a non-random sequence into the page
+  // offset by i
+  int j;
+  for (j = 0; j < sequence_length; j++)
+    pg[j] = i + sequence[j];
+}
+
+int
+test_page(int* pg, int i) {
+  int j;
+  for (j = 0; j < sequence_length; j++)
+    if (pg[j] != i + sequence[j])
+      return 1;
+
+  return 0;
+}
+
+void
+print_marked_page(int* pg) {
+  int j;
+  for (j = 0; j < (sequence_length-1); j++)
+    cprintf("%d, ", pg[j]);
+
+  cprintf("%d", pg[j]);
+}
+
+void
+print_expected_mark(int i) {
+  int j;
+  for (j = 0; j < (sequence_length-1); j++)
+    cprintf("%d, ", sequence[j]+i);
+  
+  cprintf("%d", sequence[j]+i);
+}
+
+int n, va, r, initva, maxpa, maxva, maxnum, failures;
+int *page_id;
+
+int
+alloc_range(int initaddr, int maxpa, int startn) {
+  n = startn;
+  maxnum = maxpa / PGSIZE;
+  initva = initaddr;
+  maxva = initva + maxpa;
+  
+  cprintf ("[%08x] trying to alloc pages in range [%08x, %08x]\n", env->env_id, initva, maxva);
+
+  // how many pages can I alloc? 
+  // - limit to 256 M worth of pages
+  for (va = initva; va < maxva; va += PGSIZE, n++) { 
+    // alloc a page 
+    if ((r = sys_mem_alloc(0, va, PTE_P | PTE_U | PTE_W | PTE_AVAIL)) < 0) { 
+      //cprintf("\nsys_mem_alloc failed: %e", r);
+      break;
+    }
+
+    //page_id = (int*)va;
+    //*page_id = n;              // mark this page...
+    //memset((int*)va, n, PGSIZE / sizeof(int));
+    mark_page((int*)va, n);
+
+    if ( (((va - initva) / PGSIZE) % 128) == 0) cprintf(".");
+  }
+  cprintf("\n");
+
+  cprintf("[%08x] able to allocate [%d] pages of requested [%d] pages\n", env->env_id, n, maxnum);
+
+  maxva = va;
+  return n;
+}
+
+int
+test_range(int startva, int endva, int startn) {
+  int c;
+  cprintf("[%08x] testing pages in [%08x, %08x] to see if they look okay\n", env->env_id, startva, endva);
+  n = startn;
+  failures = 0;  
+  for (va = startva, c = 0; va < endva; va += PGSIZE, n++, c++) { 
+    page_id = (int*)va;
+
+    if (test_page((int*)va, n)) {
+      cprintf("\n[%08x] unexpected value at [%08x]:\n  {", env->env_id, va);
+      print_marked_page((int*)va);
+      cprintf("} should be\n  {");
+      print_expected_mark(n);
+      cprintf("}");
+      
+      failures++;
+    } else {
+      Pte pte = vpt[VPN(va)];
+      int perm = (PTE_U | PTE_P | PTE_W | PTE_AVAIL);
+
+      if ((pte & perm) != perm) {
+       cprintf("\n[%08x] unexpected PTE permissions [04x] for address [%08x]\n {", env->env_id, pte & perm, va);
+       failures++;
+      }
+
+      //      cprintf("\n value at [%08x]: {", va);
+      //print_marked_page((int*)va);
+      //cprintf("} should be {");
+      //print_expected_mark(n);
+      //cprintf("}");
+    }
+
+    if ( (((va - startva) / PGSIZE) % 128) == 0) cprintf(".");
+    //if ((va % PDMAP) == 0) cprintf(".");
+  }
+  cprintf("\n");
+
+  cprintf("[%08x] tested %d pages: %d failed assertions.\n", env->env_id, c, failures);
+
+  return failures;
+}
+
+void
+unmap_range(int startva, int endva) {
+  cprintf("[%08x] unmapping range [%08x, %08x].\n", env->env_id, startva, endva);
+  int xva, z;
+  for (z=0, xva = startva; xva < endva; xva += PGSIZE, z++) { 
+    sys_mem_unmap(0, xva);
+  }
+  cprintf("[%08x] unmapped %d pages.\n", env->env_id, z);
+}
+
+int
+duplicate_range(int startva, int dupeva, int nbytes) {
+  cprintf("[%08x] duplicating range [%08x, %08x] at [%08x, %08x]\n", 
+        env->env_id, startva, startva+nbytes, dupeva, dupeva+nbytes);
+  int xva, r, k;
+  for (xva = 0, k = 0; xva < nbytes; xva += PGSIZE, k+=PGSIZE) { 
+    if ((r = sys_mem_map(0, startva+xva, 0, dupeva+xva, PTE_P | PTE_U | PTE_W | PTE_USER)) < 0) {
+      cprintf ("[%08x] duplicate_range FAILURE: %e\n", env->env_id, r);
+      return r;
+    }
+  }
+
+  return k;
+}
+
+// This tries to stress test the pmap code...
+// Not the most intelligent testing strategy, 
+// just hammer at it and see if it breaks.
+void
+umain(int argc, char **argv)
+{  
+  int max, max2, k, j, i, dupesize, dupen;
+
+  for (i = 0; i < 2; i++) { // might as well do this multiple times to stress the system...
+    cprintf("PMAPTEST[%08x] starting ROUND %d.\n", env->env_id, i);
+
+    // Try to allocate as many pages as possible...
+    k = alloc_range(UTEXT+PDMAP, (256 * 1024 * 1024), 0);       // alloc as many as possible
+    max = maxva;                                                // save maximum memory size
+    test_range(UTEXT+PDMAP, max, 0);                            // test if all are unique pages
+
+    // If we've corrupted kernel memory, a yield might expose a problem.
+    cprintf("PMAPTEST[%08x] yielding...\n", env->env_id);
+    sys_yield();
+    cprintf("PMAPTEST[%08x] back.\n", env->env_id);
+
+    // Free a couple of pages for use by page tables and other envs...
+    unmap_range(max-16 * PGSIZE, max);                           // free some pages so we have wiggle room, if extra
+    max -= 16 * PGSIZE;                                          // pages are needed for page tables...
+    
+    // Unmap last 1024 pages and then try to reallocate them in the same place
+    unmap_range(max - PDMAP, max);                              // unmap last 1024 pages
+    j = alloc_range(max - PDMAP, PDMAP, 0);                     // try to realloc them (<1024 if other envs alloc'd)
+    max2 = maxva; // max2 <= max && max2 >= (max - PDMAP)
+    test_range(max - PDMAP, max2, 0);                           // test if new pages are unique
+  
+    // Create duplicate mappings of the last 1024
+    dupesize = duplicate_range(max2-PDMAP, max+PDMAP, j*PGSIZE); // create duplicate mappings
+    test_range(max2-PDMAP, max2-PDMAP+dupesize, 0);             // test lower mapping
+    test_range(max+PDMAP, max + PDMAP + dupesize, 0);           // test upper mapping
+    dupen = *((int*)(max+PDMAP));
+  
+    // Remove one of the duplicate mappings and then unmap and realloc the last 1024 pages
+    unmap_range(max2-PDMAP, max2-PDMAP+dupesize);           // unmap lower mapping
+    j = alloc_range(max2-PDMAP, PDMAP, 0);                  // try to alloc something, should be below 1024 (really? other envs?)
+    unmap_range(max2-2*PDMAP, max2 - PDMAP);                // free 1024 pages
+    j = alloc_range(max2-2*PDMAP, PDMAP, 0);                // alloc new pages for free'd 1024
+    //max2 = maxva; // max2 <= old_max2 - PDMAP
+    
+    // Test ranges...
+    test_range(UTEXT+PDMAP, max2-2*PDMAP, 0);              // test entire lower range of pages
+    test_range(max2-2*PDMAP, maxva, 0);                    // test entire lower range of pages
+    test_range(max+PDMAP, max + PDMAP + dupesize, dupen);  // test upper range
+
+    // Free everything
+    unmap_range(UTEXT+PDMAP, maxva);                        
+    unmap_range(max+PDMAP, max+PDMAP+dupesize);    
+    
+    //unmap_range(UTEXT+PDMAP, max);
+  }
+
+}
+
+//#endif
+
+
+
+
diff --git a/user/user.ld b/user/user.ld
new file mode 100644 (file)
index 0000000..18d949c
--- /dev/null
@@ -0,0 +1,72 @@
+/* Simple linker script for JOS user-level programs.
+   See the GNU ld 'info' manual ("info ld") to learn the syntax. */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+       /* Load programs at this address: "." means the current address */
+       . = 0x800020;
+
+       .text : {
+               *(.text .stub .text.* .gnu.linkonce.t.*)
+       }
+
+       PROVIDE(etext = .);     /* Define the 'etext' symbol to this value */
+
+       .rodata : {
+               *(.rodata .rodata.* .gnu.linkonce.r.*)
+       }
+
+       /* Adjust the address for the data segment to the next page */
+       . = ALIGN(0x1000);
+
+       .data : {
+               *(.data)
+       }
+
+       PROVIDE(edata = .);
+
+       .bss : {
+               *(.bss)
+       }
+
+       PROVIDE(end = .);
+
+
+       /* Place debugging symbols so that they can be found by
+        * the kernel debugger.
+        * Specifically, the four words at 0x200000 mark the beginning of
+        * the stabs, the end of the stabs, the beginning of the stabs
+        * string table, and the end of the stabs string table, respectively.
+        */
+
+       .stab_info 0x200000 : {
+               LONG(__STAB_BEGIN__);
+               LONG(__STAB_END__);
+               LONG(__STABSTR_BEGIN__);
+               LONG(__STABSTR_END__);
+       }
+
+       .stab : {
+               __STAB_BEGIN__ = DEFINED(__STAB_BEGIN__) ? __STAB_BEGIN__ : .;
+               *(.stab);
+               __STAB_END__ = DEFINED(__STAB_END__) ? __STAB_END__ : .;
+               BYTE(0)         /* Force the linker to allocate space
+                                  for this section */
+       }
+
+       .stabstr : {
+               __STABSTR_BEGIN__ = DEFINED(__STABSTR_BEGIN__) ? __STABSTR_BEGIN__ : .;
+               *(.stabstr);
+               __STABSTR_END__ = DEFINED(__STABSTR_END__) ? __STABSTR_END__ : .;
+               BYTE(0)         /* Force the linker to allocate space
+                                  for this section */
+       }
+
+       /DISCARD/ : {
+               *(.eh_frame .note.GNU-stack)
+       }
+}