diff --git a/.bochsrc b/.bochsrc
new file mode 100644
index 0000000..8e91da8
--- /dev/null
+++ b/.bochsrc
@@ -0,0 +1,749 @@
+# 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
+#display_library: sdl
+
+#=======================================================================
+# 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.
+#=======================================================================
+#romimage: file=$BXSHARE/BIOS-bochs-latest
+#romimage: file=./BIOS-bochs-latest
+romimage: file=./BIOS-bochs-latest_2-3
+#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=./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
+#vga: extension=cirrus, update_freq=10, realtime=1
+
+#=======================================================================
+# 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"
+
+#=======================================================================
+# 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
+#=======================================================================
+#VERY IMPORTANT: If you are running Autograde script on Windows, DON'T forget to
+# change the .bochsrc parport1 option of students folders to:
+# parport1: enabled=1, file="student_stdout"
+# instead of file="CON", to allow the script to read the Bochs output correctly
+
+# parport1: enabled=1, file="/dev/stdout"
+# parport1: enabled=1, file="stdout"
+# parport1: enabled=1, file="console.out"
+parport1: enabled=1, file="CON" # or "CON:"
+
+#=======================================================================
+# 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
+
+#=======================================================================
+# 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/.bochsrc-debug b/.bochsrc-debug
new file mode 100644
index 0000000..110ed97
--- /dev/null
+++ b/.bochsrc-debug
@@ -0,0 +1,755 @@
+# 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.
+#=======================================================================
+#romimage: file=$BXSHARE/BIOS-bochs-latest
+#romimage: file=./BIOS-bochs-latest
+romimage: file=./BIOS-bochs-latest_2-3
+#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
+#megs: 7
+
+#=======================================================================
+# 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=./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"
+
+#=======================================================================
+# 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"
+# parport1: enabled=1, file="stdout"
+# parport1: enabled=1, file="console.out"
+
+# WARNING: never use CON workaround with bochs-debug-gdb, it creates an
+# invalid file on the hard disk that connot be removed easily
+# (only with cmd: https://bytes.com/topic/windows/insights/929114-how-create-delete-folders-like-con-com1-prn-aux-clock-nul-windows-xp)
+# (https://support.microsoft.com/en-us/kb/120716)
+# parport1: enabled=1, file="CON" # or "CON:"
+
+#VERY IMPORTANT: If you are running Autograde script on Windows, DON'T forget to
+# change the .bochsrc parport1 option of students folders to:
+# parport1: enabled=1, file="student_stdout"
+# instead of file="CON", to allow the script to read the Bochs output correctly
+
+
+#=======================================================================
+# 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=1, port=1234, text_base=0, data_base=0, bss_base=0
+#com3: enabled=1, mode=socket-client, dev=localhost:1234
+#com3: enabled=1, mode=socket-server, dev=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/.cproject b/.cproject
new file mode 100644
index 0000000..ede02e4
--- /dev/null
+++ b/.cproject
@@ -0,0 +1,216 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.gdbinit b/.gdbinit
new file mode 100644
index 0000000..04f77a7
--- /dev/null
+++ b/.gdbinit
@@ -0,0 +1,3 @@
+set remotetimeout 120
+set tcp auto-retry on
+target remote localhost:1234
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a8b7ec5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+# Build Files
+obj/
+
+# Log Files
+*.log
diff --git a/.project b/.project
new file mode 100644
index 0000000..fb6f87a
--- /dev/null
+++ b/.project
@@ -0,0 +1,77 @@
+
+
+ FOS_Labs_Template
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+ ?name?
+
+
+
+ org.eclipse.cdt.make.core.append_environment
+ true
+
+
+ org.eclipse.cdt.make.core.autoBuildTarget
+ all
+
+
+ org.eclipse.cdt.make.core.buildArguments
+
+
+
+ org.eclipse.cdt.make.core.buildCommand
+ make
+
+
+ org.eclipse.cdt.make.core.cleanBuildTarget
+ clean
+
+
+ org.eclipse.cdt.make.core.contents
+ org.eclipse.cdt.make.core.activeConfigSettings
+
+
+ org.eclipse.cdt.make.core.enableAutoBuild
+ false
+
+
+ org.eclipse.cdt.make.core.enableCleanBuild
+ true
+
+
+ org.eclipse.cdt.make.core.enableFullBuild
+ true
+
+
+ org.eclipse.cdt.make.core.fullBuildTarget
+ all
+
+
+ org.eclipse.cdt.make.core.stopOnError
+ true
+
+
+ org.eclipse.cdt.make.core.useDefaultBuildCmd
+ true
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/.settings/de.loskutov.anyedit.AnyEditTools.prefs b/.settings/de.loskutov.anyedit.AnyEditTools.prefs
new file mode 100644
index 0000000..c9ca2a9
--- /dev/null
+++ b/.settings/de.loskutov.anyedit.AnyEditTools.prefs
@@ -0,0 +1,18 @@
+activeContentFilterList=*.makefile,makefile,*.Makefile,Makefile,Makefile.*,*.mk,MANIFEST.MF,.project
+addNewLine=true
+convertActionOnSaave=AnyEdit.CnvrtTabToSpaces
+eclipse.preferences.version=1
+fixLineDelimiters=false
+ignoreBlankLinesWhenTrimming=false
+inActiveContentFilterList=
+javaTabWidthForJava=true
+org.eclipse.jdt.ui.editor.tab.width=2
+projectPropsEnabled=false
+removeTrailingSpaces=true
+replaceAllSpaces=false
+replaceAllTabs=false
+saveAndAddLine=false
+saveAndConvert=false
+saveAndFixLineDelimiters=false
+saveAndTrim=true
+useModulo4Tabs=false
diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml
new file mode 100644
index 0000000..ba7455c
--- /dev/null
+++ b/.settings/language.settings.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.cdt.codan.core.prefs b/.settings/org.eclipse.cdt.codan.core.prefs
new file mode 100644
index 0000000..ff135cf
--- /dev/null
+++ b/.settings/org.eclipse.cdt.codan.core.prefs
@@ -0,0 +1,71 @@
+eclipse.preferences.version=1
+org.eclipse.cdt.codan.checkers.errnoreturn=Warning
+org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false}
+org.eclipse.cdt.codan.checkers.errreturnvalue=Error
+org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.checkers.nocommentinside=-Error
+org.eclipse.cdt.codan.checkers.nocommentinside.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.checkers.nolinecomment=-Error
+org.eclipse.cdt.codan.checkers.nolinecomment.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.checkers.noreturn=Error
+org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false}
+org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error
+org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error
+org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error
+org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false}
+org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning
+org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()}
+org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error
+org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning
+org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true}
+org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error
+org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error
+org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error
+org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error
+org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info
+org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},pattern\=>"^[a-z]",macro\=>true,exceptions\=>()}
+org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error
+org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error
+org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning
+org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning
+org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>()}
+org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},paramNot\=>false}
+org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},else\=>false,afterelse\=>false}
+org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
+org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true}
+org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true}
+org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning
+org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")}
+org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error
+org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}}
diff --git a/.settings/org.eclipse.cdt.core.prefs b/.settings/org.eclipse.cdt.core.prefs
new file mode 100644
index 0000000..09f0071
--- /dev/null
+++ b/.settings/org.eclipse.cdt.core.prefs
@@ -0,0 +1,6 @@
+eclipse.preferences.version=1
+environment/project/cdt.managedbuild.toolchain.gnu.base.1882392411/PATH/delimiter=;
+environment/project/cdt.managedbuild.toolchain.gnu.base.1882392411/PATH/operation=replace
+environment/project/cdt.managedbuild.toolchain.gnu.base.1882392411/PATH/value=${PWD}\\..\\..\\bin;${PWD}\\..\\..\\opt\\cross\\bin;C\:/Program Files (x86)/Java/jre1.8.0_73/bin/client;C\:/Program Files (x86)/Java/jre1.8.0_73/bin;C\:/Program Files (x86)/Java/jre1.8.0_73/lib/i386;C\:\\ProgramData\\Oracle\\Java\\javapath;C\:\\WINDOWS\\system32;C\:\\WINDOWS;C\:\\WINDOWS\\System32\\Wbem;C\:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;%USERPROFILE%\\.dnx\\bin;C\:\\Program Files\\Microsoft DNX\\Dnvm\\;C\:\\Program Files (x86)\\nodejs\\;C\:\\Program Files (x86)\\Skype\\Phone\\;C\:\\Program Files\\MATLAB\\MATLAB Production Server\\R2015a\\runtime\\win64;C\:\\Program Files\\MATLAB\\MATLAB Production Server\\R2015a\\bin;C\:\\Program Files\\MATLAB\\MATLAB Production Server\\R2015a\\polyspace\\bin;C\:\\Program Files (x86)\\EaseUS\\Todo Backup\\bin;C\:\\Program Files (x86)\\Windows Kits\\10\\Windows Performance Toolkit\\;C\:\\Program Files\\Git\\cmd;C\:\\Users\\mahmo\\AppData\\Roaming\\npm;C\:\\Program Files (x86)\\EaseUS\\Todo Backup\\bin\\x64\\;
+environment/project/cdt.managedbuild.toolchain.gnu.base.1882392411/append=true
+environment/project/cdt.managedbuild.toolchain.gnu.base.1882392411/appendContributed=true
diff --git a/.settings/org.eclipse.ltk.core.refactoring.prefs b/.settings/org.eclipse.ltk.core.refactoring.prefs
new file mode 100644
index 0000000..b196c64
--- /dev/null
+++ b/.settings/org.eclipse.ltk.core.refactoring.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
diff --git a/BIOS-bochs-latest b/BIOS-bochs-latest
new file mode 100644
index 0000000..742c322
Binary files /dev/null and b/BIOS-bochs-latest differ
diff --git a/BIOS-bochs-latest_2-3 b/BIOS-bochs-latest_2-3
new file mode 100644
index 0000000..5fcdfa3
Binary files /dev/null and b/BIOS-bochs-latest_2-3 differ
diff --git a/Credits_and_Thanks.txt b/Credits_and_Thanks.txt
new file mode 100644
index 0000000..35edf48
--- /dev/null
+++ b/Credits_and_Thanks.txt
@@ -0,0 +1,5 @@
+Thanks to student Adham Zahran (Ain Shams University, FCIS, 3rd year) for solving a serious problem with boot Makefrag that prevented the course from running correclty with modern GCC.
+
+His effort along with the work of FOS TAs team led to the migration of the FOS course and development tools to modern Linux and Windows
+
+FOS Team 2016
\ No newline at end of file
diff --git a/Debug_Readme.txt b/Debug_Readme.txt
new file mode 100644
index 0000000..f4e3fb3
--- /dev/null
+++ b/Debug_Readme.txt
@@ -0,0 +1 @@
+At first time to try debugging, Eclipse may ask you about the location of source files, just click the "Edit Source Lookup Path" button and change the existing "Path Mapping" to your correct location
\ No newline at end of file
diff --git a/FOS_Developer_Console.bat b/FOS_Developer_Console.bat
new file mode 100644
index 0000000..c421b5f
--- /dev/null
+++ b/FOS_Developer_Console.bat
@@ -0,0 +1,8 @@
+@ECHO off
+set "local_directory=%cd%"
+set PATH=%local_directory%\..\..\bin;%local_directory%\..\..\opt\cross\bin;
+
+start
+
+
+
diff --git a/GNUmakefile b/GNUmakefile
new file mode 100644
index 0000000..bd169b7
--- /dev/null
+++ b/GNUmakefile
@@ -0,0 +1,174 @@
+#
+# 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 fos toolchain
+#
+# This Makefile will automatically use the cross-compiler toolchain
+# installed as 'i386-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-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; \
+ then echo 'i386-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-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-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
+
+# Note for migration to new build systems, if this doesn't work with 64 compiler try
+# to add specific 32bit options like: -m32, --32 and -m elf_i386 to CC, AS, AR and LD
+#CC := $(GCCPREFIX)gcc -m32 -pipe
+#GCC_LIB := $(shell $(CC) -print-libgcc-file-name)
+#AS := $(GCCPREFIX)as --32
+#AR := $(GCCPREFIX)ar
+#LD := $(GCCPREFIX)ld -m elf_i386
+#OBJCOPY := $(GCCPREFIX)objcopy
+#OBJDUMP := $(GCCPREFIX)objdump
+#NM := $(GCCPREFIX)nm
+
+CC := i386-elf-gcc -m32 -pipe
+GCC_LIB := $(shell $(CC) -print-libgcc-file-name)
+AS := i386-elf-as --32
+AR := i386-elf-ar
+LD := i386-elf-ld -m elf_i386
+OBJCOPY := i386-elf-objcopy
+OBJDUMP := i386-elf-objdump
+NM := i386-elf-nm
+
+
+# Note for migration to new build systems, if this doesn't work with 64 compilers, try adding -m32 to NCC flags
+# Native commands
+NCC := gcc $(CC_VER) -m32 -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
+CFLAGS := $(CFLAGS) $(DEFS) $(LABDEFS) -O0 -fno-builtin -I$(TOP) -MD -Wall -Wno-format -Wno-unused -Werror -fno-stack-protector -ggdb -g3
+
+# Linker flags for FOS 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) -DFOS_KERNEL -gstabs
+USER_CFLAGS := $(CFLAGS) -DJOS_USER -gstabs
+
+
+
+
+# Include Makefrags for subdirectories
+include boot/Makefrag
+include kern/Makefrag
+include lib/Makefrag
+include user/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
+ @echo Please visit http://pdos.csail.mit.edu/cgi-bin/828handin
+ @echo and upload lab$(LAB)-handin.tar.gz. Thanks!
+
+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/VGABIOS-lgpl-latest b/VGABIOS-lgpl-latest
new file mode 100644
index 0000000..1756065
Binary files /dev/null and b/VGABIOS-lgpl-latest differ
diff --git a/bochscon.bat b/bochscon.bat
new file mode 100644
index 0000000..4274a6d
--- /dev/null
+++ b/bochscon.bat
@@ -0,0 +1,5 @@
+@ECHO off
+set "local_directory=%cd%"
+set PATH=%local_directory%\..\..\bin;%local_directory%\..\..\opt\cross\bin;
+
+start cmd.exe /k ^"bochs.exe -q"
\ No newline at end of file
diff --git a/boot/Makefrag b/boot/Makefrag
new file mode 100644
index 0000000..c130c0a
--- /dev/null
+++ b/boot/Makefrag
@@ -0,0 +1,32 @@
+#
+# Makefile fragment for the FOS 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 -m elf_i386 boot/boot
+ $(V)$(LD) --oformat=elf32-i386 -melf_i386 -N -e start -Ttext 0x7C00 -o $@.out $^
+ $(V)$(OBJDUMP) -S $@.out >$@.asm
+ $(V)$(OBJCOPY) -S -R ".eh_frame" -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
index 0000000..5ad119d
--- /dev/null
+++ b/boot/boot.S
@@ -0,0 +1,98 @@
+#include
+
+.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
index 0000000..8f3f463
--- /dev/null
+++ b/boot/main.c
@@ -0,0 +1,120 @@
+#include
+#include
+
+/**********************************************************************
+ * 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);
+void readseg(uint32, uint32, uint32);
+
+void
+cmain(void)
+{
+ struct Proghdr *ph, *eph;
+
+ // read 1st page off disk
+ readseg((uint32) 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 *) 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 & 0xFFFFFF))();
+
+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 va, uint32 count, uint32 offset)
+{
+ uint32 end_va;
+
+ va &= 0xFFFFFF;
+ 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*) va, offset);
+ va += SECTSIZE;
+ offset++;
+ }
+}
+
+void
+waitdisk(void)
+{
+ // wait for disk reaady
+ while ((inb(0x1F7) & 0xC0) != 0x40)
+ /* do nothing */;
+}
+
+void
+readsect(void *dst, uint32 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
index 0000000..8a65e9f
--- /dev/null
+++ b/boot/sign.pl
@@ -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/coding b/coding
new file mode 100644
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/conf/env.mk b/conf/env.mk
new file mode 100644
index 0000000..1518fe9
--- /dev/null
+++ b/conf/env.mk
@@ -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
index 0000000..d74ac7f
--- /dev/null
+++ b/conf/lab.mk
@@ -0,0 +1,2 @@
+LAB=3
+PACKAGEDATE=Thu Sep 28 16:09:45 EDT 2006
diff --git a/grade.sh b/grade.sh
new file mode 100644
index 0000000..c4dc38e
--- /dev/null
+++ b/grade.sh
@@ -0,0 +1,283 @@
+#!/bin/sh
+
+verbose=false
+
+if [ "x$1" = "x-v" ]
+then
+ verbose=true
+ out=/dev/stdout
+ err=/dev/stderr
+else
+ out=/dev/null
+ err=/dev/null
+fi
+
+pts=5
+timeout=30
+preservefs=n
+
+echo_n () {
+ # suns can't echo -n, and Mac OS X can't echo "x\c"
+ # assume argument has no doublequotes
+ awk 'BEGIN { printf("'"$*"'"); }' /dev/null`
+ (
+ # The sleeps are necessary in some Bochs to
+ # make it parse each line separately. Sleeping
+ # here sure beats waiting for the timeout.
+ echo vbreak 0x8:0x$brkaddr
+ sleep .5
+ echo c
+ # EOF will do just fine to quit.
+ ) | (
+ ulimit -t $timeout
+ # date
+ bochs -q 'display_library: nogui' \
+ 'parport1: enabled=1, file="bochs.out"'
+ # date
+ ) >$out 2>$err
+ t1=`date +%s.%N 2>/dev/null`
+ time=`echo "scale=1; ($t1-$t0)/1" | sed 's/.N/.0/g' | bc 2>/dev/null`
+ time="(${time}s)"
+}
+
+
+# Usage: runtest
+runtest () {
+ perl -e "print '$1: '"
+ rm -f obj/kern/init.o obj/kern/kernel obj/kern/bochs.img
+ [ "$preservefs" = y ] || rm -f obj/fs/fs.img
+ if $verbose
+ then
+ echo "gmake $2... "
+ fi
+ gmake $2 >$out
+ if [ $? -ne 0 ]
+ then
+ echo gmake $2 failed
+ exit 1
+ fi
+ runbochs
+ if [ ! -s bochs.out ]
+ then
+ echo 'no bochs.out'
+ else
+ shift
+ shift
+ continuetest "$@"
+ fi
+}
+
+quicktest () {
+ perl -e "print '$1: '"
+ shift
+ continuetest "$@"
+}
+
+stubtest () {
+ perl -e "print qq|$1: OK $2\n|";
+ shift
+ score=`expr $pts + $score`
+}
+
+continuetest () {
+ okay=yes
+
+ not=false
+ for i
+ do
+ if [ "x$i" = "x!" ]
+ then
+ not=true
+ elif $not
+ then
+ if egrep "^$i\$" bochs.out >/dev/null
+ then
+ echo "got unexpected line '$i'"
+ if $verbose
+ then
+ exit 1
+ fi
+ okay=no
+ fi
+ not=false
+ else
+ egrep "^$i\$" bochs.out >/dev/null
+ if [ $? -ne 0 ]
+ then
+ echo "missing '$i'"
+ if $verbose
+ then
+ exit 1
+ fi
+ okay=no
+ fi
+ not=false
+ fi
+ done
+ if [ "$okay" = "yes" ]
+ then
+ score=`expr $pts + $score`
+ echo OK $time
+ else
+ echo WRONG $time
+ fi
+}
+
+# Usage: runtest1 [-tag ] [-Ddef...] STRINGS...
+runtest1 () {
+ if [ $1 = -tag ]
+ then
+ shift
+ tag=$1
+ prog=$2
+ shift
+ shift
+ else
+ tag=$1
+ prog=$1
+ shift
+ fi
+ runtest1_defs=
+ while expr "x$1" : 'x-D.*' >/dev/null; do
+ runtest1_defs="DEFS+='$1' $runtest1_defs"
+ shift
+ done
+ runtest "$tag" "DEFS='-DTEST=_binary_obj_user_${prog}_start' DEFS+='-DTESTSIZE=_binary_obj_user_${prog}_size' $runtest1_defs" "$@"
+}
+
+
+
+score=0
+
+runtest1 hello \
+ '.00000000. new env 00001000' \
+ 'hello, world' \
+ 'i am environment 00001000' \
+ '.00001000. exiting gracefully' \
+ '.00001000. free env 00001000' \
+ 'Destroyed the only environment - nothing more to do!'
+
+# the [00001000] tags should have [] in them, but that's
+# a regular expression reserved character, and i'll be damned if
+# I can figure out how many \ i need to add to get through
+# however many times the shell interprets this string. sigh.
+
+runtest1 buggyhello \
+ '.00001000. user_mem_check assertion failure for va 00000001' \
+ '.00001000. free env 00001000'
+
+runtest1 evilhello \
+ '.00001000. user_mem_check assertion failure for va f0100...' \
+ '.00001000. free env 00001000'
+
+runtest1 divzero \
+ ! '1/0 is ........!' \
+ 'Incoming TRAP frame at 0xefbfff..' \
+ 'TRAP frame at 0xf.......' \
+ ' trap 0x00000000 Divide error' \
+ ' eip 0x008.....' \
+ ' ss 0x----0023' \
+ '.00001000. free env 00001000'
+
+runtest1 breakpoint \
+ 'Welcome to the JOS kernel monitor!' \
+ 'Incoming TRAP frame at 0xefbfffbc' \
+ 'TRAP frame at 0xf.......' \
+ ' trap 0x00000003 Breakpoint' \
+ ' eip 0x008.....' \
+ ' ss 0x----0023' \
+ ! '.00001000. free env 00001000'
+
+runtest1 softint \
+ 'Welcome to the JOS kernel monitor!' \
+ 'Incoming TRAP frame at 0xefbfffbc' \
+ 'TRAP frame at 0xf.......' \
+ ' trap 0x0000000d General Protection' \
+ ' eip 0x008.....' \
+ ' ss 0x----0023' \
+ '.00001000. free env 00001000'
+
+#runtest1 badsegment \
+# 'Incoming TRAP frame at 0xefbfffbc' \
+# 'TRAP frame at 0xf.......' \
+# ' trap 0x0000000d General Protection' \
+# ' err 0x0000001c' \
+# ' eip 0x008.....' \
+# ' ss 0x----0023' \
+# '.00001000. free env 00001000'
+
+##
+## XXX badsegment no longer works on Bochs 2.2.6; Bochs refuses to produce
+## a General Protection fault and instead just panics, with the message:
+##
+## ========================================================================
+## Bochs is exiting with the following message:
+## [CPU0 ] fetch_raw_descriptor: LDTR.valid=0
+## ========================================================================
+##
+## Unfortunately, we've had to comment this test out. Please reenable it if
+## Bochs fixes this bug!!
+##
+stubtest badsegment "(stubbed out due to Bochs 2.2.6 bug)"
+
+runtest1 faultread \
+ ! 'I read ........ from location 0!' \
+ '.00001000. user fault va 00000000 ip 008.....' \
+ 'Incoming TRAP frame at 0xefbfffbc' \
+ 'TRAP frame at 0xf.......' \
+ ' trap 0x0000000e Page Fault' \
+ ' err 0x00000004' \
+ '.00001000. free env 00001000'
+
+runtest1 faultreadkernel \
+ ! 'I read ........ from location 0xf0100000!' \
+ '.00001000. user fault va f0100000 ip 008.....' \
+ 'Incoming TRAP frame at 0xefbfffbc' \
+ 'TRAP frame at 0xf.......' \
+ ' trap 0x0000000e Page Fault' \
+ ' err 0x00000005' \
+ '.00001000. free env 00001000' \
+
+runtest1 faultwrite \
+ '.00001000. user fault va 00000000 ip 008.....' \
+ 'Incoming TRAP frame at 0xefbfffbc' \
+ 'TRAP frame at 0xf.......' \
+ ' trap 0x0000000e Page Fault' \
+ ' err 0x00000006' \
+ '.00001000. free env 00001000'
+
+runtest1 faultwritekernel \
+ '.00001000. user fault va f0100000 ip 008.....' \
+ 'Incoming TRAP frame at 0xefbfffbc' \
+ 'TRAP frame at 0xf.......' \
+ ' trap 0x0000000e Page Fault' \
+ ' err 0x00000007' \
+ '.00001000. free env 00001000'
+
+runtest1 testbss \
+ 'Making sure bss works right...' \
+ 'Yes, good. Now doing a wild write off the end...' \
+ '.00001000. user fault va 00c..... ip 008.....' \
+ '.00001000. free env 00001000'
+
+
+
+echo "Score: $score/60"
+
+if [ $score -lt 60 ]; then
+ exit 1
+fi
+
+
+
diff --git a/inc/COPYRIGHT b/inc/COPYRIGHT
new file mode 100644
index 0000000..54e7f32
--- /dev/null
+++ b/inc/COPYRIGHT
@@ -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
index 0000000..56c3120
--- /dev/null
+++ b/inc/assert.h
@@ -0,0 +1,20 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifndef FOS_INC_ASSERT_H
+#define FOS_INC_ASSERT_H
+
+#include
+
+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 /* !FOS_INC_ASSERT_H */
diff --git a/inc/elf.h b/inc/elf.h
new file mode 100644
index 0000000..a14687a
--- /dev/null
+++ b/inc/elf.h
@@ -0,0 +1,65 @@
+#ifndef FOS_INC_ELF_H
+#define FOS_INC_ELF_H
+
+#define ELF_MAGIC 0x464C457FU /* "\x7FELF" in little endian */
+
+struct Elf {
+ uint32 e_magic; // must equal ELF_MAGIC
+ uint8 e_elf[12];
+ uint16 e_type;
+ uint16 e_machine;
+ uint32 e_version;
+ uint32 e_entry;
+ uint32 e_phoff;
+ uint32 e_shoff;
+ uint32 e_flags;
+ uint16 e_ehsize;
+ uint16 e_phentsize;
+ uint16 e_phnum;
+ uint16 e_shentsize;
+ uint16 e_shnum;
+ uint16 e_shstrndx;
+};
+
+struct Proghdr {
+ uint32 p_type;
+ uint32 p_offset;
+ uint32 p_va;
+ uint32 p_pa;
+ uint32 p_filesz;
+ uint32 p_memsz;
+ uint32 p_flags;
+ uint32 p_align;
+};
+
+struct Secthdr {
+ uint32 sh_name;
+ uint32 sh_type;
+ uint32 sh_flags;
+ uint32 sh_addr;
+ uint32 sh_offset;
+ uint32 sh_size;
+ uint32 sh_link;
+ uint32 sh_info;
+ uint32 sh_addralign;
+ uint32 sh_entsize;
+};
+
+// 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 /* !FOS_INC_ELF_H */
diff --git a/inc/environment_definitions.h b/inc/environment_definitions.h
new file mode 100644
index 0000000..b400f8a
--- /dev/null
+++ b/inc/environment_definitions.h
@@ -0,0 +1,49 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifndef FOS_INC_ENV_H
+#define FOS_INC_ENV_H
+
+#include
+#include
+#include
+#include
+
+// An environment ID 'envid_t' has three parts:
+//
+// +1+---------------21-----------------+--------10--------+
+// |0| Uniqueifier | Environment |
+// | | | Index |
+// +------------------------------------+------------------+
+// \--- ENVX(eid) --/
+//
+// The environment index ENVX(eid) equals the environment's offset in the
+// 'envs[]' array. The uniqueifier distinguishes environments that were
+// created at different times, but share the same environment index.
+//
+// All real environments are greater than 0 (so the sign bit is zero).
+// envid_ts less than 0 signify errors.
+
+#define LOG2NENV 10
+#define NENV (1 << LOG2NENV)
+#define ENVX(envid) ((envid) & (NENV - 1))
+
+// Values of env_status in struct Env
+#define ENV_FREE 0
+#define ENV_RUNNABLE 1
+#define ENV_NOT_RUNNABLE 2
+
+struct Env {
+ struct Trapframe env_tf; // Saved registers
+ LIST_ENTRY(Env) prev_next_info; // Free list link pointers
+ int32 env_id; // Unique environment identifier
+ int32 env_parent_id; // env_id of this env's parent
+ unsigned env_status; // Status of the environment
+ uint32 env_runs; // Number of times environment has run
+
+ // Address space
+ uint32 *env_pgdir; // Kernel virtual address of page dir
+ uint32 env_cr3; // Physical address of page dir
+
+};
+
+#endif // !FOS_INC_ENV_H
diff --git a/inc/error.h b/inc/error.h
new file mode 100644
index 0000000..d2ad122
--- /dev/null
+++ b/inc/error.h
@@ -0,0 +1,19 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifndef FOS_INC_ERROR_H
+#define FOS_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 E_EOF -7 // Unexpected end of file
+
+#define MAXERROR 7
+
+#endif // !FOS_INC_ERROR_H */
diff --git a/inc/kbdreg.h b/inc/kbdreg.h
new file mode 100644
index 0000000..33543e4
--- /dev/null
+++ b/inc/kbdreg.h
@@ -0,0 +1,83 @@
+#ifndef FOS_KBDREG_H
+#define FOS_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 /* !FOS_KBDREG_H */
diff --git a/inc/lib.h b/inc/lib.h
new file mode 100644
index 0000000..fe277e6
--- /dev/null
+++ b/inc/lib.h
@@ -0,0 +1,65 @@
+// Main public header file for our user-land support library,
+// whose code lives in the lib directory.
+// This library is roughly our OS's version of a standard C library,
+// and is intended to be linked into all user-mode applications
+// (NOT the kernel or boot loader).
+
+#ifndef FOS_INC_LIB_H
+#define FOS_INC_LIB_H 1
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define USED(x) (void)(x)
+
+// libos.c or entry.S
+extern char *binaryname;
+extern volatile struct Env *env;
+extern volatile struct Env envs[NENV];
+extern volatile struct Frame_Info frames_info[];
+void exit(void);
+void sleep(void);
+
+// readline.c
+void readline(const char *buf, char*);
+
+// syscall.c
+void sys_cputs(const char *string, uint32 len);
+int sys_cgetc(void);
+int32 sys_getenvid(void);
+int sys_env_destroy(int32);
+void sys_env_sleep();
+int sys_allocate_page(void *va, int perm);
+int sys_get_page(void *va, int perm);
+int sys_map_frame(int32 srcenv, void *srcva, int32 dstenv, void *dstva, int perm);
+int sys_unmap_frame(int32 envid, void *va);
+uint32 sys_calculate_required_frames(uint32 start_virtual_address, uint32 size);
+uint32 sys_calculate_free_frames();
+void sys_freeMem(void* start_virtual_address, uint32 size) ;
+
+// console.c
+void cputchar(int c);
+int getchar(void);
+int iscons(int fd);
+int opencons(void);
+
+/* File open modes */
+#define O_RDONLY 0x0000 /* open for reading only */
+#define O_WRONLY 0x0001 /* open for writing only */
+#define O_RDWR 0x0002 /* open for reading and writing */
+#define O_ACCMODE 0x0003 /* mask for above modes */
+
+#define O_CREAT 0x0100 /* create if nonexistent */
+#define O_TRUNC 0x0200 /* truncate to zero length */
+#define O_EXCL 0x0400 /* error if already exists */
+#define O_MKDIR 0x0800 /* create directory, not regular file */
+
+#endif // !FOS_INC_LIB_H
diff --git a/inc/malloc.h b/inc/malloc.h
new file mode 100644
index 0000000..5669b85
--- /dev/null
+++ b/inc/malloc.h
@@ -0,0 +1,7 @@
+#ifndef FOS_INC_MALLOC_H
+#define FOS_INC_MALLOC_H 1
+
+void *malloc(uint32 size);
+void freeHeap();
+
+#endif
diff --git a/inc/memlayout.h b/inc/memlayout.h
new file mode 100644
index 0000000..b7d3b92
--- /dev/null
+++ b/inc/memlayout.h
@@ -0,0 +1,181 @@
+#ifndef FOS_INC_MEMLAYOUT_H
+#define FOS_INC_MEMLAYOUT_H
+
+#ifndef __ASSEMBLER__
+#include
+#include
+#include
+#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/--
+ * KERNEL_BASE --> +------------------------------+ 0xf0000000
+ * | Cur. Page Table (Kern. RW) | RW/-- PTSIZE
+ * VPT, -------> +------------------------------+ 0xefc00000 --+
+ * KERNEL_STACK_TOP | Kernel Stack | RW/-- KERNEL_STACK_SIZE |
+ * | - - - - - - - - - - - - - - -| PTSIZE
+ * | Invalid Memory (*) | --/-- |
+ * USER_LIMIT ------> +------------------------------+ 0xef800000 --+
+ * | Cur. Page Table (User R-) | R-/R- PTSIZE
+ * UVPT ----> +------------------------------+ 0xef400000
+ * | RO PAGES | R-/R- PTSIZE
+ *READ_ONLY_FRAMES_INFO+------------------------------+ 0xef000000
+ * | RO ENVS | R-/R- PTSIZE
+ * USER_TOP,UENVS --> +------------------------------+ 0xeec00000
+ * UXSTACKTOP -/ | User Exception Stack | RW/RW PAGE_SIZE
+ * +------------------------------+ 0xeebff000
+ * | Empty Memory (*) | --/-- PAGE_SIZE
+ * USTACKTOP ---> +------------------------------+ 0xeebfe000
+ * | Normal User Stack | RW/RW PAGE_SIZE
+ * +------------------------------+ 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" (USER_LIMIT) is *never*
+ * mapped. "Empty Memory" is normally unmapped, but user programs may
+ * map pages there if desired. FOS user programs map pages temporarily
+ * at UTEMP.
+ */
+
+
+// All physical memory mapped at this address
+#define KERNEL_BASE 0xF0000000
+
+// At PHYS_IO_MEM (640K) there is a 384K hole for I/O. From the kernel,
+// PHYS_IO_MEM can be addressed at KERNEL_BASE + PHYS_IO_MEM. The hole ends
+// at physical address PHYS_EXTENDED_MEM.
+#define PHYS_IO_MEM 0x0A0000
+#define PHYS_EXTENDED_MEM 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 page_table_entries containing the page mappings for the entire
+// virtual address space into that 4 Meg region starting at VPT.
+#define VPT (KERNEL_BASE - PTSIZE)
+#define KERNEL_STACK_TOP VPT
+#define KERNEL_STACK_SIZE (8*PAGE_SIZE) // size of a kernel stack
+#define USER_LIMIT (KERNEL_STACK_TOP - PTSIZE)
+
+/*
+ * User read-only mappings! Anything below here til USER_TOP are readonly to user.
+ * They are global pages mapped in at env allocation time.
+ */
+
+// Same as VPT but read-only for users
+#define UVPT (USER_LIMIT - PTSIZE)
+// Read-only copies of the Frame_Info structures
+#define READ_ONLY_FRAMES_INFO (UVPT - PTSIZE)
+// Read-only copies of the global env structures
+#define UENVS (READ_ONLY_FRAMES_INFO - PTSIZE)
+
+/*
+ * Top of user VM. User can manipulate VA from USER_TOP-1 and down!
+ */
+
+// Top of user-accessible VM
+#define USER_TOP UENVS
+// Top of one-page user exception stack
+#define UXSTACKTOP USER_TOP
+// Next page left invalid to guard against exception stack overflow; then:
+// Top of normal user stack
+#define USTACKTOP (USER_TOP - 2*PAGE_SIZE)
+
+// 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 - PAGE_SIZE)
+// The location of the user-level STABS data structure
+#define USTABDATA (PTSIZE / 2)
+
+#define USER_HEAP_START 0x80000000
+#define USER_HEAP_MAX 0xC0000000
+
+
+#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 page_table_entries
+ * can be accessed through a "virtual page table" at virtual address VPT (to
+ * which vpt is set in entry.S). The page_table_entry 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.
+ */
+
+extern volatile uint32 vpt[]; // VA of "virtual page table"
+extern volatile uint32 vpd[]; // VA of current page directory
+
+/*
+ * Frame_Info descriptor structures, mapped at READ_ONLY_FRAMES_INFO.
+ * Read/write to the kernel, read-only to user programs.
+ *
+ * Each Frame_Info describes one physical frame.
+ * You can map a Frame_Info * to the corresponding physical address
+ * with page2pa() in kern/pmap.h.
+ */
+LIST_HEAD(Linked_List, Frame_Info);
+typedef LIST_ENTRY(Frame_Info) Page_LIST_entry_t;
+
+struct Frame_Info {
+ Page_LIST_entry_t prev_next_info; /* free list link */
+
+ // pp_ref is the count of pointers (usually in page table entries)
+ // to this page, for frames allocated using page_alloc.
+ // frames allocated at boot time using pmap.c's
+ // boot_allocate_space do not have valid reference count fields.
+
+ uint16 references;
+};
+
+#endif /* !__ASSEMBLER__ */
+#endif /* !FOS_INC_MEMLAYOUT_H */
diff --git a/inc/mmu.h b/inc/mmu.h
new file mode 100644
index 0000000..fa5e4ea
--- /dev/null
+++ b/inc/mmu.h
@@ -0,0 +1,312 @@
+#ifndef FOS_INC_MMU_H
+#define FOS_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) (((uint32) (la)) >> PTXSHIFT)
+#define VPN(la) PPN(la) // used to index into vpt[]
+
+// page directory index
+#define PDX(la) ((((uint32) (la)) >> PDXSHIFT) & 0x3FF)
+#define VPD(la) PDX(la) // used to index into vpd[]
+
+// page table index
+#define PTX(la) ((((uint32) (la)) >> PTXSHIFT) & 0x3FF)
+
+// offset in page
+#define PGOFF(la) (((uint32) (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 PAGE_SIZE 4096 // bytes mapped by a page
+#define PGSHIFT 12 // log2(PAGE_SIZE)
+
+#define PTSIZE (PAGE_SIZE*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 PERM_PRESENT 0x001 // Present
+#define PERM_WRITEABLE 0x002 // Writeable
+#define PERM_USER 0x004 // User
+#define PTE_PWT 0x008 // Write-Through
+#define PTE_PCD 0x010 // Cache-Disable
+#define PERM_USED 0x020 // Accessed
+#define PERM_MODIFIED 0x040 // Dirty
+#define PTE_PS 0x080 // Page Size
+#define PTE_MBZ 0x180 // Bits must be zero
+
+// The PERM_AVAILABLE bits aren't used by the kernel or interpreted by the
+// hardware, so user processes are allowed to set them arbitrarily.
+#define PERM_AVAILABLE 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 EXTRACT_ADDRESS(entry) ((uint32) (entry) & ~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
+
+// 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 ts_link; // Old ts selector
+ uint32 ts_esp0; // Stack pointers and segment selectors
+ uint16 ts_ss0; // after an increase in privilege level
+ uint16 ts_padding1;
+ uint32 ts_esp1;
+ uint16 ts_ss1;
+ uint16 ts_padding2;
+ uint32 ts_esp2;
+ uint16 ts_ss2;
+ uint16 ts_padding3;
+ uint32 ts_cr3; // Page directory base
+ uint32 ts_eip; // Saved state from last task switch
+ uint32 ts_eflags;
+ uint32 ts_eax; // More saved state (registers)
+ uint32 ts_ecx;
+ uint32 ts_edx;
+ uint32 ts_ebx;
+ uint32 ts_esp;
+ uint32 ts_ebp;
+ uint32 ts_esi;
+ uint32 ts_edi;
+ uint16 ts_es; // Even more saved state (segment selectors)
+ uint16 ts_padding4;
+ uint16 ts_cs;
+ uint16 ts_padding5;
+ uint16 ts_ss;
+ uint16 ts_padding6;
+ uint16 ts_ds;
+ uint16 ts_padding7;
+ uint16 ts_fs;
+ uint16 ts_padding8;
+ uint16 ts_gs;
+ uint16 ts_padding9;
+ uint16 ts_ldt;
+ uint16 ts_padding10;
+ uint16 ts_t; // Trap on task switch
+ uint16 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) (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) (off) >> 16; \
+}
+
+// Set up a call gate descriptor.
+#define SETCALLGATE(gate, ss, off, dpl) \
+{ \
+ (gate).gd_off_15_0 = (uint32) (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) (off) >> 16; \
+}
+
+// Pseudo-descriptors used for LGDT, LLDT and LIDT instructions.
+struct Pseudodesc {
+ uint16 pd_lim; // Limit
+ uint32 pd_base; // Base address
+} __attribute__ ((packed));
+
+#endif /* !__ASSEMBLER__ */
+
+#endif /* !FOS_INC_MMU_H */
diff --git a/inc/queue.h b/inc/queue.h
new file mode 100644
index 0000000..bd23aec
--- /dev/null
+++ b/inc/queue.h
@@ -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 FOS, extra comments have been added to this file, and the original
+ * TAILQ and CIRCLEQ definitions have been removed. - August 9, 2005
+ */
+
+#ifndef FOS_INC_QUEUE_H
+#define FOS_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) prev_next_info" 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 "prev_next_info" name is the link element as above.
+ */
+//#define LIST_NEXT(elm) ((elm)->prev_next_info.le_next)
+#define LIST_NEXT(elm) ((elm)->prev_next_info.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 "prev_next_info" as the link prev_next_info.
+ */
+#define LIST_FOREACH(var, head) \
+ for ((var) = LIST_FIRST((head)); \
+ (var); \
+ (var) = LIST_NEXT((var)))
+
+/*
+ * 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 "prev_next_info" name is the link element
+ * as above.
+ */
+#define LIST_INSERT_AFTER(listelm, elm) do { \
+ if ((LIST_NEXT((elm)) = LIST_NEXT((listelm))) != NULL)\
+ LIST_NEXT((listelm))->prev_next_info.le_prev = \
+ &LIST_NEXT((elm)); \
+ LIST_NEXT((listelm)) = (elm); \
+ (elm)->prev_next_info.le_prev = &LIST_NEXT((listelm)); \
+} while (0)
+
+/*
+ * Insert the element "elm" *before* the element "listelm" which is
+ * already in the list. The "prev_next_info" name is the link element
+ * as above.
+ */
+#define LIST_INSERT_BEFORE(listelm, elm) do { \
+ (elm)->prev_next_info.le_prev = (listelm)->prev_next_info.le_prev; \
+ LIST_NEXT((elm)) = (listelm); \
+ *(listelm)->prev_next_info.le_prev = (elm); \
+ (listelm)->prev_next_info.le_prev = &LIST_NEXT((elm)); \
+} while (0)
+
+/*
+ * Insert the element "elm" at the head of the list named "head".
+ * The "prev_next_info" name is the link element as above.
+ */
+#define LIST_INSERT_HEAD(head, elm) do { \
+ if ((LIST_NEXT((elm)) = LIST_FIRST((head))) != NULL) \
+ LIST_FIRST((head))->prev_next_info.le_prev = &LIST_NEXT((elm));\
+ LIST_FIRST((head)) = (elm); \
+ (elm)->prev_next_info.le_prev = &LIST_FIRST((head)); \
+} while (0)
+
+/*
+ * Remove the element "elm" from the list.
+ * The "prev_next_info" name is the link element as above.
+ */
+#define LIST_REMOVE(elm) do { \
+ if (LIST_NEXT((elm)) != NULL) \
+ LIST_NEXT((elm))->prev_next_info.le_prev = \
+ (elm)->prev_next_info.le_prev; \
+ *(elm)->prev_next_info.le_prev = LIST_NEXT((elm)); \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/inc/stab.h b/inc/stab.h
new file mode 100644
index 0000000..a9dd250
--- /dev/null
+++ b/inc/stab.h
@@ -0,0 +1,52 @@
+#ifndef FOS_STAB_H
+#define FOS_STAB_H
+#include
+
+//
+// STABS debugging info
+
+// The FOS 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. FOS 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 n_strx; // index into string table of name
+ uint8 n_type; // type of symbol
+ uint8 n_other; // misc info (usually empty)
+ uint16 n_desc; // description field
+ uint32* n_value; // value of symbol
+};
+
+
+#endif /* !FOS_STAB_H */
diff --git a/inc/stdarg.h b/inc/stdarg.h
new file mode 100644
index 0000000..eb95a68
--- /dev/null
+++ b/inc/stdarg.h
@@ -0,0 +1,19 @@
+/* $NetBSD: stdarg.h,v 1.12 1995/12/25 23:15:31 mycroft Exp $ */
+
+#ifndef FOS_INC_STDARG_H
+#define FOS_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 /* !FOS_INC_STDARG_H */
diff --git a/inc/stdio.h b/inc/stdio.h
new file mode 100644
index 0000000..448add5
--- /dev/null
+++ b/inc/stdio.h
@@ -0,0 +1,35 @@
+#ifndef FOS_INC_STDIO_H
+#define FOS_INC_STDIO_H
+
+#include
+
+#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
+void readline(const char *prompt, char*);
+
+#endif /* !FOS_INC_STDIO_H */
diff --git a/inc/string.h b/inc/string.h
new file mode 100644
index 0000000..a873bd8
--- /dev/null
+++ b/inc/string.h
@@ -0,0 +1,28 @@
+#ifndef FOS_INC_STRING_H
+#define FOS_INC_STRING_H
+
+#include
+
+#define MAX_ARGUMENTS 16
+
+int strlen(const char *s);
+int strnlen(const char *s, uint32 size);
+char * strcpy(char *dst, const char *src);
+char * strncpy(char *dst, const char *src, uint32 size);
+uint32 strlcpy(char *dst, const char *src, uint32 size);
+int strcmp(const char *s1, const char *s2);
+int strncmp(const char *s1, const char *s2, uint32 size);
+char * strchr(const char *s, char c);
+char * strfind(const char *s, char c);
+
+void * memset(void *dst, int c, uint32 len);
+void * memcpy(void *dst, const void *src, uint32 len);
+void * memmove(void *dst, const void *src, uint32 len);
+int memcmp(const void *s1, const void *s2, uint32 len);
+void * memfind(const void *s, int c, uint32 len);
+
+long strtol(const char *s, char **endptr, int base);
+
+int strsplit(char *string, char *SPLIT_CHARS, char **argv, int * argc);
+
+#endif /* not FOS_INC_STRING_H */
diff --git a/inc/syscall.h b/inc/syscall.h
new file mode 100644
index 0000000..215f976
--- /dev/null
+++ b/inc/syscall.h
@@ -0,0 +1,22 @@
+#ifndef FOS_INC_SYSCALL_H
+#define FOS_INC_SYSCALL_H
+
+/* system call numbers */
+enum
+{
+ SYS_cputs = 0,
+ SYS_cgetc,
+ SYS_getenvid,
+ SYS_env_destroy,
+ SYS_env_sleep,
+ SYS_allocate_page,
+ SYS_get_page,
+ SYS_map_frame,
+ SYS_unmap_frame,
+ SYS_calc_req_frames,
+ SYS_calc_free_frames,
+ SYS_freeMem,
+ NSYSCALLS
+};
+
+#endif /* !FOS_INC_SYSCALL_H */
diff --git a/inc/trap.h b/inc/trap.h
new file mode 100644
index 0000000..19a7e78
--- /dev/null
+++ b/inc/trap.h
@@ -0,0 +1,74 @@
+#ifndef FOS_INC_TRAP_H
+#define FOS_INC_TRAP_H
+
+// Trap numbers
+// These are processor defined:
+#define T_DIVIDE 0 // divide error
+#define T_DEBUG 1 // debug exception
+#define T_NMI 2 // non-maskable interrupt
+#define T_BRKPT 3 // breakpoint
+#define T_OFLOW 4 // overflow
+#define T_BOUND 5 // bounds check
+#define T_ILLOP 6 // illegal opcode
+#define T_DEVICE 7 // device not available
+#define T_DBLFLT 8 // double fault
+/* #define T_COPROC 9 */ // reserved (not generated by recent processors)
+#define T_TSS 10 // invalid task switch segment
+#define T_SEGNP 11 // segment not present
+#define T_STACK 12 // stack exception
+#define T_GPFLT 13 // genernal protection fault
+#define T_PGFLT 14 // page fault
+/* #define T_RES 15 */ // reserved
+#define T_FPERR 16 // floating point error
+#define T_ALIGN 17 // aligment check
+#define T_MCHK 18 // machine check
+#define T_SIMDERR 19 // SIMD floating point error
+
+// These are arbitrarily chosen, but with care not to overlap
+// processor defined exceptions or interrupt vectors.
+#define T_SYSCALL 48 // system call
+#define T_DEFAULT 500 // catchall
+
+#ifndef __ASSEMBLER__
+
+#include
+
+struct PushRegs {
+ /* registers as pushed by pusha */
+ uint32 reg_edi;
+ uint32 reg_esi;
+ uint32 reg_ebp;
+ uint32 reg_oesp; /* Useless */
+ uint32 reg_ebx;
+ uint32 reg_edx;
+ uint32 reg_ecx;
+ uint32 reg_eax;
+};
+
+struct Trapframe {
+ struct PushRegs tf_regs;
+ uint16 tf_es;
+ uint16 tf_padding1;
+ uint16 tf_ds;
+ uint16 tf_padding2;
+ uint32 tf_trapno;
+ /* below here defined by x86 hardware */
+ uint32 tf_err;
+ uint32* tf_eip;
+ uint16 tf_cs;
+ uint16 tf_padding3;
+ uint32 tf_eflags;
+ /* below here only when crossing rings, such as from user to kernel */
+ uint32* tf_esp;
+ uint16 tf_ss;
+ uint16 tf_padding4;
+};
+
+
+#endif /* !__ASSEMBLER__ */
+
+// Must equal 'sizeof(struct Trapframe)'.
+// A static_assert in kern/trap.c checks this.
+#define SIZEOF_STRUCT_TRAPFRAME 0x44
+
+#endif /* !FOS_INC_TRAP_H */
diff --git a/inc/types.h b/inc/types.h
new file mode 100644
index 0000000..924a9d0
--- /dev/null
+++ b/inc/types.h
@@ -0,0 +1,72 @@
+#ifndef FOS_INC_TYPES_H
+#define FOS_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;
+typedef unsigned char uint8;
+typedef short int16;
+typedef unsigned short uint16;
+typedef int int32;
+typedef unsigned int uint32;
+typedef long long int64;
+typedef unsigned long long uint64;
+
+// 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 __a = (uint32) (a); \
+ (typeof(a)) (__a - __a % (n)); \
+})
+// Round up to the nearest multiple of n
+#define ROUNDUP(a, n) \
+({ \
+ uint32 __n = (uint32) (n); \
+ (typeof(a)) (ROUNDDOWN((uint32) (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 /* !FOS_INC_TYPES_H */
diff --git a/inc/x86.h b/inc/x86.h
new file mode 100644
index 0000000..5a4fcd6
--- /dev/null
+++ b/inc/x86.h
@@ -0,0 +1,277 @@
+#ifndef FOS_INC_X86_H
+#define FOS_INC_X86_H
+
+#include
+
+static __inline void breakpoint(void) __attribute__((always_inline));
+static __inline uint8 inb(int port) __attribute__((always_inline));
+static __inline void insb(int port, void *addr, int cnt) __attribute__((always_inline));
+static __inline uint16 inw(int port) __attribute__((always_inline));
+static __inline void insw(int port, void *addr, int cnt) __attribute__((always_inline));
+static __inline uint32 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 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 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 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 sel) __attribute__((always_inline));
+static __inline void ltr(uint16 sel) __attribute__((always_inline));
+static __inline void lcr0(uint32 val) __attribute__((always_inline));
+static __inline uint32 rcr0(void) __attribute__((always_inline));
+static __inline uint32 rcr2(void) __attribute__((always_inline));
+static __inline void lcr3(uint32 val) __attribute__((always_inline));
+static __inline uint32 rcr3(void) __attribute__((always_inline));
+static __inline void lcr4(uint32 val) __attribute__((always_inline));
+static __inline uint32 rcr4(void) __attribute__((always_inline));
+static __inline void tlbflush(void) __attribute__((always_inline));
+static __inline uint32 read_eflags(void) __attribute__((always_inline));
+static __inline void write_eflags(uint32 eflags) __attribute__((always_inline));
+static __inline uint32 read_ebp(void) __attribute__((always_inline));
+static __inline uint32 read_esp(void) __attribute__((always_inline));
+static __inline void cpuid(uint32 info, uint32 *eaxp, uint32 *ebxp, uint32 *ecxp, uint32 *edxp);
+static __inline uint64 read_tsc(void) __attribute__((always_inline));
+
+static __inline void
+breakpoint(void)
+{
+ __asm __volatile("int3");
+}
+
+static __inline uint8
+inb(int port)
+{
+ uint8 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
+inw(int port)
+{
+ uint16 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
+inl(int port)
+{
+ uint32 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 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 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 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 sel)
+{
+ __asm __volatile("lldt %0" : : "r" (sel));
+}
+
+static __inline void
+ltr(uint16 sel)
+{
+ __asm __volatile("ltr %0" : : "r" (sel));
+}
+
+static __inline void
+lcr0(uint32 val)
+{
+ __asm __volatile("movl %0,%%cr0" : : "r" (val));
+}
+
+static __inline uint32
+rcr0(void)
+{
+ uint32 val;
+ __asm __volatile("movl %%cr0,%0" : "=r" (val));
+ return val;
+}
+
+static __inline uint32
+rcr2(void)
+{
+ uint32 val;
+ __asm __volatile("movl %%cr2,%0" : "=r" (val));
+ return val;
+}
+
+static __inline void
+lcr3(uint32 val)
+{
+ __asm __volatile("movl %0,%%cr3" : : "r" (val));
+}
+
+static __inline uint32
+rcr3(void)
+{
+ uint32 val;
+ __asm __volatile("movl %%cr3,%0" : "=r" (val));
+ return val;
+}
+
+static __inline void
+lcr4(uint32 val)
+{
+ __asm __volatile("movl %0,%%cr4" : : "r" (val));
+}
+
+static __inline uint32
+rcr4(void)
+{
+ uint32 cr4;
+ __asm __volatile("movl %%cr4,%0" : "=r" (cr4));
+ return cr4;
+}
+
+static __inline void
+tlbflush(void)
+{
+ uint32 cr3;
+ __asm __volatile("movl %%cr3,%0" : "=r" (cr3));
+ __asm __volatile("movl %0,%%cr3" : : "r" (cr3));
+}
+
+static __inline uint32
+read_eflags(void)
+{
+ uint32 eflags;
+ __asm __volatile("pushfl; popl %0" : "=r" (eflags));
+ return eflags;
+}
+
+static __inline void
+write_eflags(uint32 eflags)
+{
+ __asm __volatile("pushl %0; popfl" : : "r" (eflags));
+}
+
+static __inline uint32
+read_ebp(void)
+{
+ uint32 ebp;
+ __asm __volatile("movl %%ebp,%0" : "=r" (ebp));
+ return ebp;
+}
+
+static __inline uint32
+read_esp(void)
+{
+ uint32 esp;
+ __asm __volatile("movl %%esp,%0" : "=r" (esp));
+ return esp;
+}
+
+static __inline void
+cpuid(uint32 info, uint32 *eaxp, uint32 *ebxp, uint32 *ecxp, uint32 *edxp)
+{
+ uint32 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
+read_tsc(void)
+{
+ uint64 tsc;
+ __asm __volatile("rdtsc" : "=A" (tsc));
+ return tsc;
+}
+
+#endif /* !FOS_INC_X86_H */
diff --git a/kern/COPYRIGHT b/kern/COPYRIGHT
new file mode 100644
index 0000000..6a0270c
--- /dev/null
+++ b/kern/COPYRIGHT
@@ -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
index 0000000..d08f87e
--- /dev/null
+++ b/kern/Makefrag
@@ -0,0 +1,85 @@
+#
+# Makefile fragment for FOS 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/command_prompt.c \
+ kern/helpers.c \
+ kern/memory_manager.c \
+ kern/user_environment.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_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 := $(wildcard user/*.c)
+
+KERN_BINFILES := $(patsubst %.c, $(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
+
+all: $(OBJDIR)/kern/bochs.img
+
+grub: $(OBJDIR)/fos-grub
+
+$(OBJDIR)/fos-grub: $(OBJDIR)/kern/kernel
+ @echo + oc $@
+ $(V)$(OBJCOPY) --adjust-vma=0x10000000 $^ $@
diff --git a/kern/command_prompt.c b/kern/command_prompt.c
new file mode 100644
index 0000000..a15da61
--- /dev/null
+++ b/kern/command_prompt.c
@@ -0,0 +1,408 @@
+/* Simple command-line kernel prompt useful for
+ controlling the kernel and exploring the system interactively.
+
+
+KEY WORDS
+==========
+CONSTANTS: WHITESPACE, NUM_OF_COMMANDS
+VARIABLES: Command, commands, name, description, function_to_execute, number_of_arguments, arguments, command_string, command_line, command_found
+FUNCTIONS: readline, cprintf, execute_command, run_command_prompt, command_kernel_info, command_help, strcmp, strsplit, start_of_kernel, start_of_uninitialized_data_section, end_of_kernel_code_section, end_of_kernel
+=====================================================================================================================================================================================================
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+//TODO:LAB3.Hands-on: declare start address variable of "My int array"
+
+//=============================================================
+
+//Structure for each command
+struct Command
+{
+ char *name;
+ char *description;
+ // return -1 to force command prompt to exit
+ int (*function_to_execute)(int number_of_arguments, char** arguments);
+};
+
+//Functions Declaration
+int execute_command(char *command_string);
+int command_writemem(int number_of_arguments, char **arguments);
+int command_readmem(int number_of_arguments, char **arguments);
+int command_meminfo(int , char **);
+
+//Lab2.Hands.On
+//=============
+//TODO: LAB2 Hands-on: declare the command function here
+
+
+//LAB3.Examples
+//=============
+int command_kernel_base_info(int , char **);
+int command_del_kernel_base(int , char **);
+int command_share_page(int , char **);
+
+//Lab4.Hands.On
+//=============
+int command_show_mapping(int number_of_arguments, char **arguments);
+int command_set_permission(int number_of_arguments, char **arguments);
+int command_share_range(int number_of_arguments, char **arguments);
+
+//Lab5.Examples
+//=============
+int command_nr(int number_of_arguments, char **arguments);
+int command_ap(int , char **);
+int command_fp(int , char **);
+
+//Lab5.Hands-on
+//=============
+int command_asp(int, char **);
+int command_cfp(int, char **);
+
+//Lab6.Examples
+//=============
+int command_run(int , char **);
+int command_kill(int , char **);
+int command_ft(int , char **);
+
+
+//Array of commands. (initialized)
+struct Command commands[] =
+{
+ { "help", "Display this list of commands", command_help },
+ { "kernel_info", "Display information about the kernel", command_kernel_info },
+ { "wum", "writes one byte to specific location" ,command_writemem},
+ { "rum", "reads one byte from specific location" ,command_readmem},
+ { "meminfo", "Display number of free frames", command_meminfo},
+
+ //TODO: LAB2 Hands-on: add the commands here
+
+
+ //LAB3: Examples
+ { "ikb", "Lab3.Example: shows mapping info of KERNEL_BASE" ,command_kernel_base_info},
+ { "dkb", "Lab3.Example: delete the mapping of KERNEL_BASE" ,command_del_kernel_base},
+ { "shr", "Lab3.Example: share one page on another" ,command_share_page},
+
+ //LAB4: Hands-on
+ { "sm", "Lab4.HandsOn: display the mapping info for the given virtual address", command_show_mapping},
+ { "sp", "Lab4.HandsOn: set the desired permission to a given virtual address page", command_set_permission},
+ { "sr", "Lab4.HandsOn: shares the physical frames of the first virtual range with the 2nd virtual range", command_share_range},
+
+ //LAB5: Examples
+ { "nr", "Lab5.Example: show the number of references of the physical frame" ,command_nr},
+ { "ap", "Lab5.Example: allocate one page [if not exists] in the user space at the given virtual address", command_ap},
+ { "fp", "Lab5.Example: free one page in the user space at the given virtual address", command_fp},
+
+ //LAB5: Hands-on
+ { "asp", "Lab5.HandsOn: allocate 2 shared pages with the given virtual addresses" ,command_asp},
+ { "cfp", "Lab5.HandsOn: count the number of free pages in the given range", command_cfp},
+
+ //LAB6: Examples
+ { "ft", "Lab6.Example: Free table", command_ft},
+ { "run", "Lab6.Example: Load and Run User Program", command_run},
+ { "kill", "Lab6.Example: Kill User Program", command_kill},
+
+};
+
+//Number of commands = size of the array / size of command structure
+#define NUM_OF_COMMANDS (sizeof(commands)/sizeof(commands[0]))
+
+
+//invoke the command prompt
+void run_command_prompt()
+{
+ char command_line[1024];
+
+ while (1==1)
+ {
+ //get command line
+ readline("FOS> ", command_line);
+
+ //parse and execute the command
+ if (command_line != NULL)
+ if (execute_command(command_line) < 0)
+ break;
+ }
+}
+
+/***** Kernel command prompt command interpreter *****/
+
+//define the white-space symbols
+#define WHITESPACE "\t\r\n "
+
+//Function to parse any command and execute it
+//(simply by calling its corresponding function)
+int execute_command(char *command_string)
+{
+ // Split the command string into whitespace-separated arguments
+ int number_of_arguments;
+ //allocate array of char * of size MAX_ARGUMENTS = 16 found in string.h
+ char *arguments[MAX_ARGUMENTS];
+
+
+ strsplit(command_string, WHITESPACE, arguments, &number_of_arguments) ;
+ if (number_of_arguments == 0)
+ return 0;
+
+ // Lookup in the commands array and execute the command
+ int command_found = 0;
+ int i ;
+ for (i = 0; i < NUM_OF_COMMANDS; i++)
+ {
+ if (strcmp(arguments[0], commands[i].name) == 0)
+ {
+ command_found = 1;
+ break;
+ }
+ }
+
+ if(command_found)
+ {
+ int return_value;
+ return_value = commands[i].function_to_execute(number_of_arguments, arguments);
+ return return_value;
+ }
+ else
+ {
+ //if not found, then it's unknown command
+ cprintf("Unknown command '%s'\n", arguments[0]);
+ return 0;
+ }
+}
+
+/***** Implementations of basic kernel command prompt commands *****/
+
+//print name and description of each command
+int command_help(int number_of_arguments, char **arguments)
+{
+ int i;
+ for (i = 0; i < NUM_OF_COMMANDS; i++)
+ cprintf("%s - %s\n", commands[i].name, commands[i].description);
+
+ cprintf("-------------------\n");
+
+ return 0;
+}
+
+//print information about kernel addresses and kernel size
+int command_kernel_info(int number_of_arguments, char **arguments )
+{
+ extern char start_of_kernel[], end_of_kernel_code_section[], start_of_uninitialized_data_section[], end_of_kernel[];
+
+ cprintf("Special kernel symbols:\n");
+ cprintf(" Start Address of the kernel %08x (virt) %08x (phys)\n", start_of_kernel, start_of_kernel - KERNEL_BASE);
+ cprintf(" End address of kernel code %08x (virt) %08x (phys)\n", end_of_kernel_code_section, end_of_kernel_code_section - KERNEL_BASE);
+ cprintf(" Start addr. of uninitialized data section %08x (virt) %08x (phys)\n", start_of_uninitialized_data_section, start_of_uninitialized_data_section - KERNEL_BASE);
+ cprintf(" End address of the kernel %08x (virt) %08x (phys)\n", end_of_kernel, end_of_kernel - KERNEL_BASE);
+ cprintf("Kernel executable memory footprint: %d KB\n",
+ (end_of_kernel-start_of_kernel+1023)/1024);
+ return 0;
+}
+
+
+int command_readmem(int number_of_arguments, char **arguments)
+{
+ unsigned int address = strtol(arguments[1], NULL, 16);
+ unsigned char *ptr = (unsigned char *)(address ) ;
+
+ cprintf("value at address %x = %c\n", ptr, *ptr);
+
+ return 0;
+}
+
+int command_writemem(int number_of_arguments, char **arguments)
+{
+ unsigned int address = strtol(arguments[1], NULL, 16);
+ unsigned char *ptr = (unsigned char *)(address) ;
+
+ *ptr = arguments[2][0];
+
+ return 0;
+}
+
+int command_meminfo(int number_of_arguments, char **arguments)
+{
+ cprintf("Free frames = %d\n", calculate_free_frames());
+ return 0;
+}
+
+//===========================================================================
+//Lab2.Hands.On
+//=============
+//TODO: LAB2 Hands-on: write the command function here
+
+
+//===========================================================================
+//Lab3.Examples
+//=============
+int command_kernel_base_info(int number_of_arguments, char **arguments)
+{
+ //TODO: LAB3 Example: fill this function. corresponding command name is "ikb"
+ //Comment the following line
+ panic("Function is not implemented yet!");
+
+ return 0;
+}
+
+
+int command_del_kernel_base(int number_of_arguments, char **arguments)
+{
+ //TODO: LAB3 Example: fill this function. corresponding command name is "dkb"
+ //Comment the following line
+ panic("Function is not implemented yet!");
+
+ return 0;
+}
+
+int command_share_page(int number_of_arguments, char **arguments)
+{
+ //TODO: LAB3 Example: fill this function. corresponding command name is "shr"
+ //Comment the following line
+ panic("Function is not implemented yet!");
+
+ return 0;
+}
+
+//===========================================================================
+//Lab4.Hands.On
+//=============
+int command_show_mapping(int number_of_arguments, char **arguments)
+{
+ //TODO: LAB4 Hands-on: fill this function. corresponding command name is "sm"
+ //Comment the following line
+ panic("Function is not implemented yet!");
+
+ return 0 ;
+}
+
+int command_set_permission(int number_of_arguments, char **arguments)
+{
+ //TODO: LAB4 Hands-on: fill this function. corresponding command name is "sp"
+ //Comment the following line
+ panic("Function is not implemented yet!");
+
+ return 0 ;
+}
+
+int command_share_range(int number_of_arguments, char **arguments)
+{
+ //TODO: LAB4 Hands-on: fill this function. corresponding command name is "sr"
+ //Comment the following line
+ panic("Function is not implemented yet!");
+
+ return 0;
+}
+
+//===========================================================================
+//Lab5.Examples
+//==============
+//[1] Number of references on the given physical address
+int command_nr(int number_of_arguments, char **arguments)
+{
+ //TODO: LAB5 Example: fill this function. corresponding command name is "nr"
+ //Comment the following line
+ panic("Function is not implemented yet!");
+
+ return 0;
+}
+
+//[2] Allocate Page: If the given user virtual address is mapped, do nothing. Else, allocate a single frame and map it to a given virtual address in the user space
+int command_ap(int number_of_arguments, char **arguments)
+{
+ //TODO: LAB5 Example: fill this function. corresponding command name is "ap"
+ //Comment the following line
+ //panic("Function is not implemented yet!");
+
+ uint32 va = strtol(arguments[1], NULL, 16);
+ struct Frame_Info* ptr_frame_info;
+ int ret = allocate_frame(&ptr_frame_info) ;
+ map_frame(ptr_page_directory, ptr_frame_info, (void*)va, PERM_USER | PERM_WRITEABLE);
+
+ return 0 ;
+}
+
+//[3] Free Page: Un-map a single page at the given virtual address in the user space
+int command_fp(int number_of_arguments, char **arguments)
+{
+ //TODO: LAB5 Example: fill this function. corresponding command name is "fp"
+ //Comment the following line
+ //panic("Function is not implemented yet!");
+
+ uint32 va = strtol(arguments[1], NULL, 16);
+ // Un-map the page at this address
+ unmap_frame(ptr_page_directory, (void*)va);
+
+ return 0;
+}
+
+//===========================================================================
+//Lab5.Hands-on
+//==============
+//[1] Allocate Shared Pages
+int command_asp(int number_of_arguments, char **arguments)
+{
+ //TODO: LAB5 Hands-on: fill this function. corresponding command name is "asp"
+ //Comment the following line
+ panic("Function is not implemented yet!");
+
+ return 0;
+}
+
+
+//[2] Count Free Pages in Range
+int command_cfp(int number_of_arguments, char **arguments)
+{
+ //TODO: LAB5 Hands-on: fill this function. corresponding command name is "cfp"
+ //Comment the following line
+ panic("Function is not implemented yet!");
+
+ return 0;
+}
+
+//===========================================================================
+//Lab6.Examples
+//=============
+int command_run(int number_of_arguments, char **arguments)
+{
+ //[1] Create and initialize a new environment for the program to be run
+ struct UserProgramInfo* ptr_program_info = env_create(arguments[1]);
+ if(ptr_program_info == 0) return 0;
+
+ //[2] Run the created environment using "env_run" function
+ env_run(ptr_program_info->environment);
+ return 0;
+}
+
+int command_kill(int number_of_arguments, char **arguments)
+{
+ //[1] Get the user program info of the program (by searching in the "userPrograms" array
+ struct UserProgramInfo* ptr_program_info = get_user_program_info(arguments[1]) ;
+ if(ptr_program_info == 0) return 0;
+
+ //[2] Kill its environment using "env_free" function
+ env_free(ptr_program_info->environment);
+ ptr_program_info->environment = NULL;
+ return 0;
+}
+
+int command_ft(int number_of_arguments, char **arguments)
+{
+ //TODO: LAB6 Example: fill this function. corresponding command name is "ft"
+ //Comment the following line
+
+ return 0;
+}
+
diff --git a/kern/command_prompt.h b/kern/command_prompt.h
new file mode 100644
index 0000000..3d5deba
--- /dev/null
+++ b/kern/command_prompt.h
@@ -0,0 +1,16 @@
+#ifndef FOS_KERN_MONITOR_H
+#define FOS_KERN_MONITOR_H
+#ifndef FOS_KERNEL
+# error "This is a FOS kernel header; user programs should not #include it"
+#endif
+
+#include
+
+// Function to activate the kernel command prompt
+void run_command_prompt();
+
+// Declaration of functions that implement command prompt commands.
+int command_help(int , char **);
+int command_kernel_info(int , char **);
+
+#endif // !FOS_KERN_MONITOR_H
diff --git a/kern/console.c b/kern/console.c
new file mode 100644
index 0000000..0ad4d80
--- /dev/null
+++ b/kern/console.c
@@ -0,0 +1,456 @@
+/* See COPYRIGHT for copyright information. */
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+
+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) (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 < 2800; i++) //12800
+ 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 *crt_buf;
+static uint16 crt_pos;
+
+void
+cga_init(void)
+{
+ volatile uint16 *cp;
+ uint16 was;
+ unsigned pos;
+
+ cp = (uint16*) (KERNEL_BASE + CGA_BUF);
+ was = *cp;
+ *cp = (uint16) 0xA55A;
+ if (*cp != 0xA55A) {
+ cp = (uint16*) (KERNEL_BASE + 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*) 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));
+ 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 shiftcode[256] =
+{
+ [0x1D] CTL,
+ [0x2A] SHIFT,
+ [0x36] SHIFT,
+ [0x38] ALT,
+ [0x9D] CTL,
+ [0xB8] ALT
+};
+
+static uint8 togglecode[256] =
+{
+ [0x3A] CAPSLOCK,
+ [0x45] NUMLOCK,
+ [0x46] SCROLLLOCK
+};
+
+static uint8 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
+ [0x97] 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 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
+ [0x97] 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 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 *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 data;
+ static uint32 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 buf[CONSBUFSIZE];
+ uint32 rpos;
+ uint32 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
+console_initialize(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
index 0000000..85c82bc
--- /dev/null
+++ b/kern/console.h
@@ -0,0 +1,27 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifndef _CONSOLE_H_
+#define _CONSOLE_H_
+#ifndef FOS_KERNEL
+# error "This is a FOS kernel header; user programs should not #include it"
+#endif
+
+#include
+
+#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 console_initialize(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
index 0000000..7230ce7
--- /dev/null
+++ b/kern/entry.S
@@ -0,0 +1,105 @@
+/* See COPYRIGHT for copyright information. */
+
+#include
+#include
+#include
+
+# Shift Right Logical
+#define SRL(val, shamt) (((val) >> (shamt)) & ~(-1 << (32 - (shamt))))
+
+
+###################################################################
+# The kernel (this code) is linked at address ~(KERNEL_BASE + 1 Meg),
+# but the bootloader load it at address ~1 Meg.
+#
+# RELOC(x) maps a symbol x from its link address to its actual
+# location in physical memory (its load address).
+###################################################################
+
+#define RELOC(x) ((x) - KERNEL_BASE)
+
+
+.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_of_kernel
+start_of_kernel:
+ 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
+
+ # Leave a few words on the stack for the user trap frame
+ movl $(ptr_stack_top-SIZEOF_STRUCT_TRAPFRAME),%esp
+
+ # now to C code
+ call FOS_initialize
+
+ # Should never get here, but in case we do, just spin.
+spin: jmp spin
+
+
+###################################################################
+# See 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 ptr_stack_bottom
+ptr_stack_bottom:
+ .space KERNEL_STACK_SIZE
+ .globl ptr_stack_top
+ptr_stack_top:
+
+###################################################################
+# setup the GDT
+###################################################################
+ .p2align 2 # force 4 byte alignment
+mygdt:
+ SEG_NULL # null seg
+ SEG(STA_X|STA_R, -KERNEL_BASE, 0xffffffff) # code seg
+ SEG(STA_W, -KERNEL_BASE, 0xffffffff) # data seg
+mygdtdesc:
+ .word 0x17 # sizeof(mygdt) - 1
+ .long RELOC(mygdt) # address mygdt
+
diff --git a/kern/helpers.c b/kern/helpers.c
new file mode 100644
index 0000000..c5a1319
--- /dev/null
+++ b/kern/helpers.c
@@ -0,0 +1,366 @@
+/* See COPYRIGHT for copyright information. */
+/*
+KEY WORDS
+==========
+MACROS: K_PHYSICAL_ADDRESS, K_VIRTUAL_ADDRESS, PDX, PTX, CONSTRUCT_ENTRY, EXTRACT_ADDRESS, ROUNDUP, ROUNDDOWN, LIST_INIT, LIST_INSERT_HEAD, LIST_FIRST, LIST_REMOVE
+CONSTANTS: PAGE_SIZE, PERM_PRESENT, PERM_WRITEABLE, PERM_USER, KERNEL_STACK_TOP, KERNEL_STACK_SIZE, KERNEL_BASE, READ_ONLY_FRAMES_INFO, PHYS_IO_MEM, PHYS_EXTENDED_MEM, E_NO_MEM
+VARIABLES: ptr_free_mem, ptr_page_directory, phys_page_directory, bootstack, Frame_Info, frames_info, free_frame_list, references, prev_next_info, size_of_extended_mem, number_of_frames, ptr_frame_info ,create, perm, va
+FUNCTIONS: to_physical_address, get_frame_info, tlb_invalidate
+=====================================================================================================================================================================================================
+*/
+
+#include
+#include
+
+// Global descriptor table.
+//
+// The kernel and user segments are identical(except for the DPL).
+// To load the SS register, the CPL must equal the DPL. Thus,
+// we must duplicate the segments for the user and the kernel.
+//
+struct Segdesc gdt[] =
+{
+ // 0x0 - unused (always faults -- for trapping NULL far pointers)
+ SEG_NULL,
+
+ // 0x8 - kernel code segment
+ [GD_KT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 0),
+
+ // 0x10 - kernel data segment
+ [GD_KD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 0),
+
+ // 0x18 - user code segment
+ [GD_UT >> 3] = SEG(STA_X | STA_R, 0x0, 0xffffffff, 3),
+
+ // 0x20 - user data segment
+ [GD_UD >> 3] = SEG(STA_W, 0x0, 0xffffffff, 3),
+
+ // 0x28 - tss, initialized in idt_init()
+ [GD_TSS >> 3] = SEG_NULL
+};
+
+struct Pseudodesc gdt_pd =
+{
+ sizeof(gdt) - 1, (unsigned long) gdt
+};
+
+int nvram_read(int r)
+{
+ return mc146818_read(r) | (mc146818_read(r + 1) << 8);
+}
+
+void detect_memory()
+{
+ // CMOS tells us how many kilobytes there are
+ size_of_base_mem = ROUNDDOWN(nvram_read(NVRAM_BASELO)*1024, PAGE_SIZE);
+ size_of_extended_mem = ROUNDDOWN(nvram_read(NVRAM_EXTLO)*1024, PAGE_SIZE);
+
+ // Calculate the maxmium physical address based on whether
+ // or not there is any extended memory. See comment in ../inc/mmu.h.
+ if (size_of_extended_mem)
+ maxpa = PHYS_EXTENDED_MEM + size_of_extended_mem;
+ else
+ maxpa = size_of_extended_mem;
+
+ number_of_frames = maxpa / PAGE_SIZE;
+
+ cprintf("Physical memory: %dK available, ", (int)(maxpa/1024));
+ cprintf("base = %dK, extended = %dK\n", (int)(size_of_base_mem/1024), (int)(size_of_extended_mem/1024));
+}
+
+// --------------------------------------------------------------
+// Set up initial memory mappings and turn on MMU.
+// --------------------------------------------------------------
+
+void check_boot_pgdir();
+
+//
+// Checks that the kernel part of virtual address space
+// has been setup roughly correctly(by initialize_kernel_VM()).
+//
+// This function doesn't test every corner case,
+// in fact it doesn't test the permission bits at all,
+// but it is a pretty good check.
+//
+uint32 check_va2pa(uint32 *ptr_page_directory, uint32 va);
+
+void check_boot_pgdir()
+{
+ uint32 i, n;
+
+ // check frames_info array
+ n = ROUNDUP(number_of_frames*sizeof(struct Frame_Info), PAGE_SIZE);
+ for (i = 0; i < n; i += PAGE_SIZE)
+ assert(check_va2pa(ptr_page_directory, READ_ONLY_FRAMES_INFO + i) == K_PHYSICAL_ADDRESS(frames_info) + i);
+
+ // check phys mem
+ for (i = 0; KERNEL_BASE + i != 0; i += PAGE_SIZE)
+ assert(check_va2pa(ptr_page_directory, KERNEL_BASE + i) == i);
+
+ // check kernel stack
+ for (i = 0; i < KERNEL_STACK_SIZE; i += PAGE_SIZE)
+ assert(check_va2pa(ptr_page_directory, KERNEL_STACK_TOP - KERNEL_STACK_SIZE + i) == K_PHYSICAL_ADDRESS(ptr_stack_bottom) + i);
+
+ // check for zero/non-zero in PDEs
+ for (i = 0; i < NPDENTRIES; i++) {
+ switch (i) {
+ case PDX(VPT):
+ case PDX(UVPT):
+ case PDX(KERNEL_STACK_TOP-1):
+ case PDX(UENVS):
+ case PDX(READ_ONLY_FRAMES_INFO):
+ assert(ptr_page_directory[i]);
+ break;
+ default:
+ if (i >= PDX(KERNEL_BASE))
+ assert(ptr_page_directory[i]);
+ else
+ assert(ptr_page_directory[i] == 0);
+ break;
+ }
+ }
+ cprintf("check_boot_pgdir() succeeded!\n");
+}
+
+// This function returns the physical address of the page containing 'va',
+// defined by the page directory 'ptr_page_directory'. The hardware normally performs
+// this functionality for us! We define our own version to help check
+// the check_boot_pgdir() function; it shouldn't be used elsewhere.
+
+uint32 check_va2pa(uint32 *ptr_page_directory, uint32 va)
+{
+ uint32 *p;
+
+ ptr_page_directory = &ptr_page_directory[PDX(va)];
+ if (!(*ptr_page_directory & PERM_PRESENT))
+ return ~0;
+ p = (uint32*) K_VIRTUAL_ADDRESS(EXTRACT_ADDRESS(*ptr_page_directory));
+ if (!(p[PTX(va)] & PERM_PRESENT))
+ return ~0;
+ return EXTRACT_ADDRESS(p[PTX(va)]);
+}
+
+void tlb_invalidate(uint32 *ptr_page_directory, void *virtual_address)
+{
+ // Flush the entry only if we're modifying the current address space.
+ // For now, there is only one address space, so always invalidate.
+ invlpg(virtual_address);
+}
+
+void page_check()
+{
+ struct Frame_Info *pp, *pp0, *pp1, *pp2;
+ struct Linked_List fl;
+
+ // should be able to allocate three frames_info
+ pp0 = pp1 = pp2 = 0;
+ assert(allocate_frame(&pp0) == 0);
+ assert(allocate_frame(&pp1) == 0);
+ assert(allocate_frame(&pp2) == 0);
+
+ assert(pp0);
+ assert(pp1 && pp1 != pp0);
+ assert(pp2 && pp2 != pp1 && pp2 != pp0);
+
+ // temporarily steal the rest of the free frames_info
+ fl = free_frame_list;
+ LIST_INIT(&free_frame_list);
+
+ // should be no free memory
+ assert(allocate_frame(&pp) == E_NO_MEM);
+
+ // there is no free memory, so we can't allocate a page table
+ assert(map_frame(ptr_page_directory, pp1, 0x0, 0) < 0);
+
+ // free pp0 and try again: pp0 should be used for page table
+ free_frame(pp0);
+ assert(map_frame(ptr_page_directory, pp1, 0x0, 0) == 0);
+ assert(EXTRACT_ADDRESS(ptr_page_directory[0]) == to_physical_address(pp0));
+ assert(check_va2pa(ptr_page_directory, 0x0) == to_physical_address(pp1));
+ assert(pp1->references == 1);
+ assert(pp0->references == 1);
+
+ // should be able to map pp2 at PAGE_SIZE because pp0 is already allocated for page table
+ assert(map_frame(ptr_page_directory, pp2, (void*) PAGE_SIZE, 0) == 0);
+ assert(check_va2pa(ptr_page_directory, PAGE_SIZE) == to_physical_address(pp2));
+ assert(pp2->references == 1);
+
+ // should be no free memory
+ assert(allocate_frame(&pp) == E_NO_MEM);
+
+ // should be able to map pp2 at PAGE_SIZE because it's already there
+ assert(map_frame(ptr_page_directory, pp2, (void*) PAGE_SIZE, 0) == 0);
+ assert(check_va2pa(ptr_page_directory, PAGE_SIZE) == to_physical_address(pp2));
+ assert(pp2->references == 1);
+
+ // pp2 should NOT be on the free list
+ // could happen in ref counts are handled sloppily in map_frame
+ assert(allocate_frame(&pp) == E_NO_MEM);
+
+ // should not be able to map at PTSIZE because need free frame for page table
+ assert(map_frame(ptr_page_directory, pp0, (void*) PTSIZE, 0) < 0);
+
+ // insert pp1 at PAGE_SIZE (replacing pp2)
+ assert(map_frame(ptr_page_directory, pp1, (void*) PAGE_SIZE, 0) == 0);
+
+ // should have pp1 at both 0 and PAGE_SIZE, pp2 nowhere, ...
+ assert(check_va2pa(ptr_page_directory, 0) == to_physical_address(pp1));
+ assert(check_va2pa(ptr_page_directory, PAGE_SIZE) == to_physical_address(pp1));
+ // ... and ref counts should reflect this
+ assert(pp1->references == 2);
+ assert(pp2->references == 0);
+
+ // pp2 should be returned by allocate_frame
+ assert(allocate_frame(&pp) == 0 && pp == pp2);
+
+ // unmapping pp1 at 0 should keep pp1 at PAGE_SIZE
+ unmap_frame(ptr_page_directory, 0x0);
+ assert(check_va2pa(ptr_page_directory, 0x0) == ~0);
+ assert(check_va2pa(ptr_page_directory, PAGE_SIZE) == to_physical_address(pp1));
+ assert(pp1->references == 1);
+ assert(pp2->references == 0);
+
+ // unmapping pp1 at PAGE_SIZE should free it
+ unmap_frame(ptr_page_directory, (void*) PAGE_SIZE);
+ assert(check_va2pa(ptr_page_directory, 0x0) == ~0);
+ assert(check_va2pa(ptr_page_directory, PAGE_SIZE) == ~0);
+ assert(pp1->references == 0);
+ assert(pp2->references == 0);
+
+ // so it should be returned by allocate_frame
+ assert(allocate_frame(&pp) == 0 && pp == pp1);
+
+ // should be no free memory
+ assert(allocate_frame(&pp) == E_NO_MEM);
+
+ // forcibly take pp0 back
+ assert(EXTRACT_ADDRESS(ptr_page_directory[0]) == to_physical_address(pp0));
+ ptr_page_directory[0] = 0;
+ assert(pp0->references == 1);
+ pp0->references = 0;
+
+ // give free list back
+ free_frame_list = fl;
+
+ // free the frames_info we took
+ free_frame(pp0);
+ free_frame(pp1);
+ free_frame(pp2);
+
+ cprintf("page_check() succeeded!\n");
+}
+
+void turn_on_paging()
+{
+ //////////////////////////////////////////////////////////////////////
+ // On x86, segmentation maps a VA to a LA (linear addr) and
+ // paging maps the LA to a PA. I.e. VA => LA => PA. If paging is
+ // turned off the LA is used as the PA. Note: there is no way to
+ // turn off segmentation. The closest thing is to set the base
+ // address to 0, so the VA => LA mapping is the identity.
+
+ // Current mapping: VA (KERNEL_BASE+x) => PA (x).
+ // (segmentation base = -KERNEL_BASE and paging is off)
+
+ // From here on down we must maintain this VA (KERNEL_BASE + x) => PA (x)
+ // mapping, even though we are turning on paging and reconfiguring
+ // segmentation.
+
+ // Map VA 0:4MB same as VA (KERNEL_BASE), i.e. to PA 0:4MB.
+ // (Limits our kernel to <4MB)
+ ptr_page_directory[0] = ptr_page_directory[PDX(KERNEL_BASE)];
+
+ // Install page table.
+ lcr3(phys_page_directory);
+
+ // Turn on paging.
+ uint32 cr0;
+ cr0 = rcr0();
+ cr0 |= CR0_PE|CR0_PG|CR0_AM|CR0_WP|CR0_NE|CR0_TS|CR0_EM|CR0_MP;
+ cr0 &= ~(CR0_TS|CR0_EM);
+ lcr0(cr0);
+
+ // Current mapping: KERNEL_BASE+x => x => x.
+ // (x < 4MB so uses paging ptr_page_directory[0])
+
+ // Reload all segment registers.
+ asm volatile("lgdt gdt_pd");
+ asm volatile("movw %%ax,%%gs" :: "a" (GD_UD|3));
+ asm volatile("movw %%ax,%%fs" :: "a" (GD_UD|3));
+ asm volatile("movw %%ax,%%es" :: "a" (GD_KD));
+ asm volatile("movw %%ax,%%ds" :: "a" (GD_KD));
+ asm volatile("movw %%ax,%%ss" :: "a" (GD_KD));
+ asm volatile("ljmp %0,$1f\n 1:\n" :: "i" (GD_KT)); // reload cs
+ asm volatile("lldt %%ax" :: "a" (0));
+
+ // Final mapping: KERNEL_BASE + x => KERNEL_BASE + x => x.
+
+ // This mapping was only used after paging was turned on but
+ // before the segment registers were reloaded.
+ ptr_page_directory[0] = 0;
+
+ // Flush the TLB for good measure, to kill the ptr_page_directory[0] mapping.
+ lcr3(phys_page_directory);
+}
+
+void setup_listing_to_all_page_tables_entries()
+{
+ //////////////////////////////////////////////////////////////////////
+ // Recursively insert PD in itself as a page table, to form
+ // a virtual page table at virtual address VPT.
+
+ // Permissions: kernel RW, user NONE
+ uint32 phys_frame_address = K_PHYSICAL_ADDRESS(ptr_page_directory);
+ ptr_page_directory[PDX(VPT)] = CONSTRUCT_ENTRY(phys_frame_address , PERM_PRESENT | PERM_WRITEABLE);
+
+ // same for UVPT
+ //Permissions: kernel R, user R
+ ptr_page_directory[PDX(UVPT)] = K_PHYSICAL_ADDRESS(ptr_page_directory)|PERM_USER|PERM_PRESENT;
+
+}
+
+//
+// Converts an envid to an env pointer.
+//
+// RETURNS
+// 0 on success, -E_BAD_ENV on error.
+// On success, sets *penv to the environment.
+// On error, sets *penv to NULL.
+//
+int envid2env(int32 envid, struct Env **env_store, bool checkperm)
+{
+ struct Env *e;
+
+ // If envid is zero, return the current environment.
+ if (envid == 0) {
+ *env_store = curenv;
+ return 0;
+ }
+
+ // Look up the Env structure via the index part of the envid,
+ // then check the env_id field in that struct Env
+ // to ensure that the envid is not stale
+ // (i.e., does not refer to a _previous_ environment
+ // that used the same slot in the envs[] array).
+ e = &envs[ENVX(envid)];
+ if (e->env_status == ENV_FREE || e->env_id != envid) {
+ *env_store = 0;
+ return -E_BAD_ENV;
+ }
+
+ // Check that the calling environment has legitimate permission
+ // to manipulate the specified environment.
+ // If checkperm is set, the specified environment
+ // must be either the current environment
+ // or an immediate child of the current environment.
+ if (checkperm && e != curenv && e->env_parent_id != curenv->env_id) {
+ *env_store = 0;
+ return -E_BAD_ENV;
+ }
+
+ *env_store = e;
+ return 0;
+}
+
+//
+
diff --git a/kern/helpers.h b/kern/helpers.h
new file mode 100644
index 0000000..c573493
--- /dev/null
+++ b/kern/helpers.h
@@ -0,0 +1,80 @@
+/* See COPYRIGHT for copyright information. */
+#ifndef FOS_KERN_HELPER_H
+#define FOS_KERN_HELPER_H
+#ifndef FOS_KERNEL
+# error "This is a FOS kernel header; user programs should not #include it"
+#endif
+
+#include
+
+extern struct Segdesc gdt[];
+extern struct Pseudodesc gdt_pd;
+
+extern char ptr_stack_top[], ptr_stack_bottom[];
+
+// These variables are set by detect_memory()
+uint32 maxpa; // Maximum physical address
+uint32 number_of_frames; // Amount of physical memory (in frames)
+uint32 size_of_base_mem; // Amount of base memory (in bytes)
+uint32 size_of_extended_mem; // Amount of extended memory (in bytes)
+
+extern uint32* ptr_page_directory;
+extern uint32 phys_page_directory;
+extern char* ptr_free_mem;
+
+extern struct Frame_Info *frames_info;
+extern struct Linked_List free_frame_list; // Free list of physical frames
+extern uint32 number_of_frames;
+
+/* This macro takes a user supplied address and turns it into
+ * something that will cause a fault if it is a kernel address. ULIM
+ * itself is guaranteed never to contain a valid page.
+ */
+#define TRUP(_p) \
+({ \
+ register typeof((_p)) __m_p = (_p); \
+ (uint32) __m_p > ULIM ? (typeof(_p)) ULIM : __m_p; \
+})
+
+/* This macro takes a kernel virtual address -- an address that points above
+ * KERNEL_BASE, where the machine's maximum 256MB of physical memory is mapped --
+ * and returns the corresponding physical address. It panics if you pass it a
+ * non-kernel virtual address.
+ */
+#define K_PHYSICAL_ADDRESS(kva) \
+({ \
+ uint32 __m_kva = (uint32) (kva); \
+ if (__m_kva < KERNEL_BASE) \
+ panic("K_PHYSICAL_ADDRESS called with invalid kva %08lx", __m_kva);\
+ __m_kva - KERNEL_BASE; \
+})
+
+/* This macro takes a physical address and returns the corresponding kernel
+ * virtual address. It panics if you pass an invalid physical address. */
+#define K_VIRTUAL_ADDRESS(pa) \
+({ \
+ uint32 __m_pa = (pa); \
+ uint32 __m_ppn = PPN(__m_pa); \
+ if (__m_ppn >= number_of_frames) \
+ panic("K_VIRTUAL_ADDRESS called with invalid pa %08lx", __m_pa);\
+ (void*) (__m_pa + KERNEL_BASE); \
+})
+
+/* This Macro creates a page table/direcotry entry (32 bits)
+* according to the format of Intel page table/diretory entry
+*/
+#define CONSTRUCT_ENTRY(phys_frame_address, permissions) \
+( \
+ phys_frame_address | permissions \
+)
+
+
+void detect_memory();
+void turn_on_paging();
+void page_check();
+void tlb_invalidate(uint32 *pgdir, void *ptr);
+void check_boot_pgdir();
+void setup_listing_to_all_page_tables_entries();
+int envid2env(int32 envid, struct Env **env_store, bool checkperm);
+
+#endif /* !FOS_KERN_HELPER_H */
diff --git a/kern/init.c b/kern/init.c
new file mode 100644
index 0000000..62c6224
--- /dev/null
+++ b/kern/init.c
@@ -0,0 +1,116 @@
+/* See COPYRIGHT for copyright information. */
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+//Functions Declaration
+//======================
+void print_welcome_message();
+//=======================================
+
+
+
+//First ever function called in FOS kernel
+void FOS_initialize()
+{
+ //get actual addresses after code linking
+ extern char start_of_uninitialized_data_section[], end_of_kernel[];
+
+ // Before doing anything else,
+ // clear the uninitialized global data (BSS) section of our program, from start_of_uninitialized_data_section to end_of_kernel
+ // This ensures that all static/global variables start with zero value.
+ memset(start_of_uninitialized_data_section, 0, end_of_kernel - start_of_uninitialized_data_section);
+
+ // Initialize the console.
+ // Can't call cprintf until after we do this!
+ console_initialize();
+
+ //print welcome message
+ print_welcome_message();
+
+ // Lab 2 memory management initialization functions
+ detect_memory();
+ initialize_kernel_VM();
+ initialize_paging();
+ page_check();
+
+
+ // Lab 3 user environment initialization functions
+ env_init();
+ idt_init();
+
+
+ // start the kernel command prompt.
+ while (1==1)
+ {
+ cprintf("\nWelcome to the FOS kernel command prompt!\n");
+ cprintf("Type 'help' for a list of commands.\n");
+ run_command_prompt();
+ }
+}
+
+
+void print_welcome_message()
+{
+ cprintf("\n\n\n");
+ cprintf("\t\t!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+ cprintf("\t\t!! !!\n");
+ cprintf("\t\t!! !! FCIS says HELLO !! !!\n");
+ cprintf("\t\t!! !!\n");
+ cprintf("\t\t!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+ cprintf("\n\n\n\n");
+}
+
+
+/*
+ * 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 command prompt.
+ */
+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 command prompt */
+ while (1==1)
+ run_command_prompt();
+}
+
+/* like panic, but don't enters the kernel command prompt*/
+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);
+}
+
diff --git a/kern/kclock.c b/kern/kclock.c
new file mode 100644
index 0000000..5898eb5
--- /dev/null
+++ b/kern/kclock.c
@@ -0,0 +1,26 @@
+/* See COPYRIGHT for copyright information. */
+
+/* The Run Time Clock and other NVRAM access functions that go with it. */
+/* The run time clock is hard-wired to IRQ8. */
+
+#include
+
+#include
+
+
+unsigned
+mc146818_read(unsigned reg)
+{
+ outb(IO_RTC, reg);
+ return inb(IO_RTC+1);
+}
+
+void
+mc146818_write(unsigned reg, unsigned datum)
+{
+ outb(IO_RTC, reg);
+ outb(IO_RTC+1, datum);
+}
+
+
+
diff --git a/kern/kclock.h b/kern/kclock.h
new file mode 100644
index 0000000..ea9f2bd
--- /dev/null
+++ b/kern/kclock.h
@@ -0,0 +1,33 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifndef FOS_KERN_KCLOCK_H
+#define FOS_KERN_KCLOCK_H
+#ifndef FOS_KERNEL
+# error "This is a FOS kernel header; user programs should not #include it"
+#endif
+
+#define IO_RTC 0x070 /* RTC port */
+
+#define MC_NVRAM_START 0xe /* start of NVRAM: offset 14 */
+#define MC_NVRAM_SIZE 50 /* 50 bytes of NVRAM */
+
+/* NVRAM bytes 7 & 8: base memory size */
+#define NVRAM_BASELO (MC_NVRAM_START + 7) /* low byte; RTC off. 0x15 */
+#define NVRAM_BASEHI (MC_NVRAM_START + 8) /* high byte; RTC off. 0x16 */
+
+/* NVRAM bytes 9 & 10: extended memory size */
+#define NVRAM_EXTLO (MC_NVRAM_START + 9) /* low byte; RTC off. 0x17 */
+#define NVRAM_EXTHI (MC_NVRAM_START + 10) /* high byte; RTC off. 0x18 */
+
+/* NVRAM bytes 34 and 35: extended memory POSTed size */
+#define NVRAM_PEXTLO (MC_NVRAM_START + 34) /* low byte; RTC off. 0x30 */
+#define NVRAM_PEXTHI (MC_NVRAM_START + 35) /* high byte; RTC off. 0x31 */
+
+/* NVRAM byte 36: current century. (please increment in Dec99!) */
+#define NVRAM_CENTURY (MC_NVRAM_START + 36) /* RTC offset 0x32 */
+
+unsigned mc146818_read(unsigned reg);
+void mc146818_write(unsigned reg, unsigned datum);
+void kclock_init(void);
+
+#endif // !FOS_KERN_KCLOCK_H
diff --git a/kern/kdebug.c b/kern/kdebug.c
new file mode 100644
index 0000000..7ebe4f8
--- /dev/null
+++ b/kern/kdebug.c
@@ -0,0 +1,228 @@
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+extern const struct Stab __STAB_BEGIN__[]; // Beginning of stabs table
+extern const struct Stab __STAB_END__[]; // End of stabs table
+extern const char __STABSTR_BEGIN__[]; // Beginning of string table
+extern const char __STABSTR_END__[]; // End of string table
+
+struct UserStabData {
+ const struct Stab *stabs;
+ const struct Stab *stab_end;
+ const char *stabstr;
+ const char *stabstr_end;
+};
+
+
+// stab_binsearch(stabs, region_left, region_right, type, addr)
+//
+// Some stab types are arranged in increasing order by instruction
+// address. For example, N_FUN stabs (stab entries with n_type ==
+// N_FUN), which mark functions, and N_SO stabs, which mark source files.
+//
+// Given an instruction address, this function finds the single stab
+// entry of type 'type' that contains that address.
+//
+// The search takes place within the range [*region_left, *region_right].
+// Thus, to search an entire set of N stabs, you might do:
+//
+// left = 0;
+// right = N - 1; /* rightmost stab */
+// stab_binsearch(stabs, &left, &right, type, addr);
+//
+// The search modifies *region_left and *region_right to bracket the
+// 'addr'. *region_left points to the matching stab that contains
+// 'addr', and *region_right points just before the next stab. If
+// *region_left > *region_right, then 'addr' is not contained in any
+// matching stab.
+//
+// For example, given these N_SO stabs:
+// Index Type Address
+// 0 SO f0100000
+// 13 SO f0100040
+// 117 SO f0100176
+// 118 SO f0100178
+// 555 SO f0100652
+// 556 SO f0100654
+// 657 SO f0100849
+// this code:
+// left = 0, right = 657;
+// stab_binsearch(stabs, &left, &right, N_SO, 0xf0100184);
+// will exit setting left = 118, right = 554.
+//
+static void
+stab_binsearch(const struct Stab *stabs, int *region_left, int *region_right,
+ int type, uint32* addr)
+{
+ int l = *region_left, r = *region_right, any_matches = 0;
+
+ while (l <= r) {
+ int true_m = (l + r) / 2, m = true_m;
+
+ // search for earliest stab with right type
+ while (m >= l && stabs[m].n_type != type)
+ m--;
+ if (m < l) { // no match in [l, m]
+ l = true_m + 1;
+ continue;
+ }
+
+ // actual binary search
+ any_matches = 1;
+ if (stabs[m].n_value < addr) {
+ *region_left = m;
+ l = true_m + 1;
+ } else if (stabs[m].n_value > addr) {
+ *region_right = m - 1;
+ r = m - 1;
+ } else {
+ // exact match for 'addr', but continue loop to find
+ // *region_right
+ *region_left = m;
+ l = m;
+ addr++;
+ }
+ }
+
+ if (!any_matches)
+ *region_right = *region_left - 1;
+ else {
+ // find rightmost region containing 'addr'
+ for (l = *region_right;
+ l > *region_left && stabs[l].n_type != type;
+ l--)
+ /* do nothing */;
+ *region_left = l;
+ }
+}
+
+
+// debuginfo_eip(addr, info)
+//
+// Fill in the 'info' structure with information about the specified
+// instruction address, 'addr'. Returns 0 if information was found, and
+// negative if not. But even if it returns negative it has stored some
+// information into '*info'.
+//
+int
+debuginfo_eip(uint32* addr, struct Eipdebuginfo *info)
+{
+ const struct Stab *stabs, *stab_end;
+ const char *stabstr, *stabstr_end;
+ int lfile, rfile, lfun, rfun, lline, rline;
+
+ // Initialize *info
+ info->eip_file = "";
+ info->eip_line = 0;
+ info->eip_fn_name = "";
+ info->eip_fn_namelen = 9;
+ info->eip_fn_addr = addr;
+ info->eip_fn_narg = 0;
+
+ // Find the relevant set of stabs
+ if ((uint32)addr >= USER_LIMIT) {
+ stabs = __STAB_BEGIN__;
+ stab_end = __STAB_END__;
+ stabstr = __STABSTR_BEGIN__;
+ stabstr_end = __STABSTR_END__;
+ } else {
+ // The user-application linker script, user/user.ld,
+ // puts information about the application's stabs (equivalent
+ // to __STAB_BEGIN__, __STAB_END__, __STABSTR_BEGIN__, and
+ // __STABSTR_END__) in a structure located at virtual address
+ // USTABDATA.
+ const struct UserStabData *usd = (const struct UserStabData *) USTABDATA;
+
+ // Make sure this memory is valid.
+ // Return -1 if it is not. Hint: Call user_mem_check.
+ // LAB 3: Your code here.
+
+ stabs = usd->stabs;
+ stab_end = usd->stab_end;
+ stabstr = usd->stabstr;
+ stabstr_end = usd->stabstr_end;
+
+ // Make sure the STABS and string table memory is valid.
+ // LAB 3: Your code here.
+ }
+
+ // String table validity checks
+ if (stabstr_end <= stabstr || stabstr_end[-1] != 0)
+ return -1;
+
+ // Now we find the right stabs that define the function containing
+ // 'eip'. First, we find the basic source file containing 'eip'.
+ // Then, we look in that source file for the function. Then we look
+ // for the line number.
+
+ // Search the entire set of stabs for the source file (type N_SO).
+ lfile = 0;
+ rfile = (stab_end - stabs) - 1;
+ stab_binsearch(stabs, &lfile, &rfile, N_SO, addr);
+ if (lfile == 0)
+ return -1;
+
+ // Search within that file's stabs for the function definition
+ // (N_FUN).
+ lfun = lfile;
+ rfun = rfile;
+ stab_binsearch(stabs, &lfun, &rfun, N_FUN, addr);
+
+ if (lfun <= rfun) {
+ // stabs[lfun] points to the function name
+ // in the string table, but check bounds just in case.
+ if (stabs[lfun].n_strx < stabstr_end - stabstr)
+ info->eip_fn_name = stabstr + stabs[lfun].n_strx;
+ info->eip_fn_addr = (uint32*) stabs[lfun].n_value;
+ addr = (uint32*)(addr - (info->eip_fn_addr));
+ // Search within the function definition for the line number.
+ lline = lfun;
+ rline = rfun;
+ } else {
+ // Couldn't find function stab! Maybe we're in an assembly
+ // file. Search the whole file for the line number.
+ info->eip_fn_addr = addr;
+ lline = lfile;
+ rline = rfile;
+ }
+ // Ignore stuff after the colon.
+ info->eip_fn_namelen = strfind(info->eip_fn_name, ':') - info->eip_fn_name;
+
+
+ // Search within [lline, rline] for the line number stab.
+ // If found, set info->eip_line to the right line number.
+ // If not found, return -1.
+ //
+ // Hint:
+ // There's a particular stabs type used for line numbers.
+ // Look at the STABS documentation and to find
+ // which one.
+ // Your code here.
+
+
+ // Search backwards from the line number for the relevant filename
+ // stab.
+ // We can't just use the "lfile" stab because inlined functions
+ // can interpolate code from a different file!
+ // Such included source files use the N_SOL stab type.
+ while (lline >= lfile
+ && stabs[lline].n_type != N_SOL
+ && (stabs[lline].n_type != N_SO || !stabs[lline].n_value))
+ lline--;
+ if (lline >= lfile && stabs[lline].n_strx < stabstr_end - stabstr)
+ info->eip_file = stabstr + stabs[lline].n_strx;
+
+
+ // Set eip_fn_narg to the number of arguments taken by the function,
+ // or 0 if there was no containing function.
+ // Your code here.
+
+
+ return 0;
+}
diff --git a/kern/kdebug.h b/kern/kdebug.h
new file mode 100644
index 0000000..f4510b0
--- /dev/null
+++ b/kern/kdebug.h
@@ -0,0 +1,20 @@
+#ifndef FOS_KERN_KDEBUG_H
+#define FOS_KERN_KDEBUG_H
+
+#include
+
+// Debug information about a particular instruction pointer
+struct Eipdebuginfo {
+ const char *eip_file; // Source code filename for EIP
+ int eip_line; // Source code linenumber for EIP
+
+ const char *eip_fn_name; // Name of function containing EIP
+ // - Note: not null terminated!
+ int eip_fn_namelen; // Length of function name
+ uint32* eip_fn_addr; // Address of start of function
+ int eip_fn_narg; // Number of function arguments
+};
+
+int debuginfo_eip(uint32 *eip, struct Eipdebuginfo *info);
+
+#endif
diff --git a/kern/kernel.ld b/kern/kernel.ld
new file mode 100644
index 0000000..dbcaa5d
--- /dev/null
+++ b/kern/kernel.ld
@@ -0,0 +1,59 @@
+/* Simple linker script for the FOS 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_of_kernel)
+
+SECTIONS
+{
+ /* Load the kernel at this address: "." means the current address */
+ . = 0xF0100000;
+
+ .text : {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ }
+
+ PROVIDE(end_of_kernel_code_section = .); /* Define the 'etext' symbol to this value */
+
+ .rodata : {
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ }
+
+ /* Include debugging information in kernel memory */
+ .stab : {
+ PROVIDE(__STAB_BEGIN__ = .);
+ *(.stab);
+ PROVIDE(__STAB_END__ = .);
+ BYTE(0) /* Force the linker to allocate space
+ for this section */
+ }
+
+ .stabstr : {
+ PROVIDE(__STABSTR_BEGIN__ = .);
+ *(.stabstr);
+ PROVIDE(__STABSTR_END__ = .);
+ 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(start_of_uninitialized_data_section = .);
+
+ .bss : {
+ *(.bss)
+ }
+
+ PROVIDE(end_of_kernel = .);
+
+ /DISCARD/ : {
+ *(.eh_frame .note.GNU-stack)
+ }
+}
diff --git a/kern/memory_manager.c b/kern/memory_manager.c
new file mode 100644
index 0000000..1c45fb2
--- /dev/null
+++ b/kern/memory_manager.c
@@ -0,0 +1,595 @@
+/* See COPYRIGHT for copyright information.
+
+KEY WORDS
+==========
+MACROS: K_PHYSICAL_ADDRESS, K_VIRTUAL_ADDRESS, PDX, PTX, CONSTRUCT_ENTRY, EXTRACT_ADDRESS, ROUNDUP, ROUNDDOWN, LIST_INIT, LIST_INSERT_HEAD, LIST_FIRST, LIST_REMOVE
+CONSTANTS: PAGE_SIZE, PERM_PRESENT, PERM_WRITEABLE, PERM_USER, KERNEL_STACK_TOP, KERNEL_STACK_SIZE, KERNEL_BASE, READ_ONLY_FRAMES_INFO, PHYS_IO_MEM, PHYS_EXTENDED_MEM, E_NO_MEM
+VARIABLES: ptr_free_mem, ptr_page_directory, phys_page_directory, phys_stack_bottom, Frame_Info, frames_info, free_frame_list, references, prev_next_info, size_of_extended_mem, number_of_frames, ptr_frame_info ,create, perm, va
+FUNCTIONS: to_physical_address, get_frame_info, tlb_invalidate
+=====================================================================================================================================================================================================
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+extern uint32 number_of_frames; // Amount of physical memory (in frames_info)
+extern uint32 size_of_base_mem; // Amount of base memory (in bytes)
+extern uint32 size_of_extended_mem; // Amount of extended memory (in bytes)
+
+// These variables are set in initialize_kernel_VM()
+uint32* ptr_page_directory; // Virtual address of boot time page directory
+uint32 phys_page_directory; // Physical address of boot time page directory
+char* ptr_free_mem; // Pointer to next byte of free mem
+
+struct Frame_Info* frames_info; // Virtual address of physical frames_info array
+struct Linked_List free_frame_list; // Free list of physical frames_info
+
+
+//==================== MAPPING KERNEL SPACE ==============================
+
+// Set up a two-level page table:
+// ptr_page_directory is the virtual address of the page directory
+// phys_page_directory is the physical adresss of the page directory
+// Then turn on paging. Then effectively turn off segmentation.
+// (i.e., the segment base addrs are set to zero).
+//
+// This function only sets up the kernel part of the address space
+// (ie. addresses >= USER_TOP). The user part of the address space
+// will be setup later.
+//
+// From USER_TOP to USER_LIMIT, the user is allowed to read but not write.
+// Above USER_LIMIT the user cannot read (or write).
+
+void initialize_kernel_VM()
+{
+ // Remove this line when you're ready to test this function.
+ //panic("initialize_kernel_VM: This function is not finished\n");
+
+ //////////////////////////////////////////////////////////////////////
+ // create initial page directory.
+
+ ptr_page_directory = boot_allocate_space(PAGE_SIZE, PAGE_SIZE);
+ memset(ptr_page_directory, 0, PAGE_SIZE);
+ phys_page_directory = K_PHYSICAL_ADDRESS(ptr_page_directory);
+
+ //////////////////////////////////////////////////////////////////////
+ // Map the kernel stack with VA range :
+ // [KERNEL_STACK_TOP-KERNEL_STACK_SIZE, KERNEL_STACK_TOP),
+ // to physical address : "phys_stack_bottom".
+ // Permissions: kernel RW, user NONE
+ // Your code goes here:
+ boot_map_range(ptr_page_directory, KERNEL_STACK_TOP - KERNEL_STACK_SIZE, KERNEL_STACK_SIZE, K_PHYSICAL_ADDRESS(ptr_stack_bottom), PERM_WRITEABLE) ;
+
+ //////////////////////////////////////////////////////////////////////
+ // Map all of physical memory at KERNEL_BASE.
+ // i.e. the VA range [KERNEL_BASE, 2^32) should map to
+ // the PA range [0, 2^32 - KERNEL_BASE)
+ // We might not have 2^32 - KERNEL_BASE bytes of physical memory, but
+ // we just set up the mapping anyway.
+ // Permissions: kernel RW, user NONE
+ // Your code goes here:
+ boot_map_range(ptr_page_directory, KERNEL_BASE, 0xFFFFFFFF - KERNEL_BASE, 0, PERM_WRITEABLE) ;
+
+ //////////////////////////////////////////////////////////////////////
+ // Make 'frames_info' point to an array of size 'number_of_frames' of 'struct Frame_Info'.
+ // The kernel uses this structure to keep track of physical frames;
+ // 'number_of_frames' equals the number of physical frames in memory. User-level
+ // programs get read-only access to the array as well.
+ // You must allocate the array yourself.
+ // Map this array read-only by the user at virtual address READ_ONLY_FRAMES_INFO
+ // (ie. perm = PERM_USER | PERM_PRESENT)
+ // Permissions:
+ // - frames_info -- kernel RW, user NONE
+ // - the image mapped at READ_ONLY_FRAMES_INFO -- kernel R, user R
+ // Your code goes here:
+ uint32 array_size;
+ array_size = number_of_frames * sizeof(struct Frame_Info) ;
+ frames_info = boot_allocate_space(array_size, PAGE_SIZE);
+ boot_map_range(ptr_page_directory, READ_ONLY_FRAMES_INFO, array_size, K_PHYSICAL_ADDRESS(frames_info), PERM_USER) ;
+
+
+ // This allows the kernel & user to access any page table entry using a
+ // specified VA for each: VPT for kernel and UVPT for User.
+ setup_listing_to_all_page_tables_entries();
+
+ //////////////////////////////////////////////////////////////////////
+ // Make 'envs' point to an array of size 'NENV' of 'struct Env'.
+ // Map this array read-only by the user at linear address UENVS
+ // (ie. perm = PTE_U | PTE_P).
+ // Permissions:
+ // - envs itself -- kernel RW, user NONE
+ // - the image of envs mapped at UENVS -- kernel R, user R
+
+ // LAB 3: Your code here.
+ int envs_size = NENV * sizeof(struct Env) ;
+
+ //allocate space for "envs" array aligned on 4KB boundary
+ envs = boot_allocate_space(envs_size, PAGE_SIZE);
+
+ //make the user to access this array by mapping it to UPAGES linear address (UPAGES is in User/Kernel space)
+ boot_map_range(ptr_page_directory, UENVS, envs_size, K_PHYSICAL_ADDRESS(envs), PERM_USER) ;
+
+ //update permissions of the corresponding entry in page directory to make it USER with PERMISSION read only
+ ptr_page_directory[PDX(UENVS)] = ptr_page_directory[PDX(UENVS)]|(PERM_USER|(PERM_PRESENT & (~PERM_WRITEABLE)));
+
+
+ // Check that the initial page directory has been set up correctly.
+ check_boot_pgdir();
+
+ // NOW: Turn off the segmentation by setting the segments' base to 0, and
+ // turn on the paging by setting the corresponding flags in control register 0 (cr0)
+ turn_on_paging() ;
+}
+
+//
+// Allocate "size" bytes of physical memory aligned on an
+// "align"-byte boundary. Align must be a power of two.
+// Return the start kernel virtual address of the allocated space.
+// Returned memory is uninitialized.
+//
+// If we're out of memory, boot_allocate_space should panic.
+// It's too early to run out of memory.
+// This function may ONLY be used during boot time,
+// before the free_frame_list has been set up.
+//
+void* boot_allocate_space(uint32 size, uint32 align)
+ {
+ extern char end_of_kernel[];
+
+ // Initialize ptr_free_mem if this is the first time.
+ // 'end_of_kernel' is a symbol automatically generated by the linker,
+ // which points to the end of the kernel-
+ // i.e., the first virtual address that the linker
+ // did not assign to any kernel code or global variables.
+ if (ptr_free_mem == 0)
+ ptr_free_mem = end_of_kernel;
+
+ // Your code here:
+ // Step 1: round ptr_free_mem up to be aligned properly
+ ptr_free_mem = ROUNDUP(ptr_free_mem, PAGE_SIZE) ;
+
+ // Step 2: save current value of ptr_free_mem as allocated space
+ void *ptr_allocated_mem;
+ ptr_allocated_mem = ptr_free_mem ;
+
+ // Step 3: increase ptr_free_mem to record allocation
+ ptr_free_mem += size ;
+
+ // Step 4: return allocated space
+ return ptr_allocated_mem ;
+
+ }
+
+//
+// Map [virtual_address, virtual_address+size) of virtual address space to
+// physical [physical_address, physical_address+size)
+// in the page table rooted at ptr_page_directory.
+// "size" is a multiple of PAGE_SIZE.
+// Use permission bits perm|PERM_PRESENT for the entries.
+//
+// This function may ONLY be used during boot time,
+// before the free_frame_list has been set up.
+//
+void boot_map_range(uint32 *ptr_page_directory, uint32 virtual_address, uint32 size, uint32 physical_address, int perm)
+{
+ int i = 0 ;
+ physical_address = ROUNDUP(physical_address, PAGE_SIZE) ;
+ for (i = 0 ; i < size ; i += PAGE_SIZE)
+ {
+ uint32 *ptr_page_table = boot_get_page_table(ptr_page_directory, virtual_address, 1) ;
+ uint32 index_page_table = PTX(virtual_address);
+ ptr_page_table[index_page_table] = CONSTRUCT_ENTRY(physical_address, perm | PERM_PRESENT) ;
+ physical_address += PAGE_SIZE ;
+ virtual_address += PAGE_SIZE ;
+ }
+}
+
+//
+// Given ptr_page_directory, a pointer to a page directory,
+// traverse the 2-level page table structure to find
+// the page table for "virtual_address".
+// Return a pointer to the table.
+//
+// If the relevant page table doesn't exist in the page directory:
+// - If create == 0, return 0.
+// - Otherwise allocate a new page table, install it into ptr_page_directory,
+// and return a pointer into it.
+// (Questions: What data should the new page table contain?
+// And what permissions should the new ptr_page_directory entry have?)
+//
+// This function allocates new page tables as needed.
+//
+// boot_get_page_table cannot fail. It's too early to fail.
+// This function may ONLY be used during boot time,
+// before the free_frame_list has been set up.
+//
+uint32* boot_get_page_table(uint32 *ptr_page_directory, uint32 virtual_address, int create)
+ {
+ uint32 index_page_directory = PDX(virtual_address);
+ uint32 page_directory_entry = ptr_page_directory[index_page_directory];
+
+ uint32 phys_page_table = EXTRACT_ADDRESS(page_directory_entry);
+ uint32 *ptr_page_table = K_VIRTUAL_ADDRESS(phys_page_table);
+ if (phys_page_table == 0)
+ {
+ if (create)
+ {
+ ptr_page_table = boot_allocate_space(PAGE_SIZE, PAGE_SIZE) ;
+ phys_page_table = K_PHYSICAL_ADDRESS(ptr_page_table);
+ ptr_page_directory[index_page_directory] = CONSTRUCT_ENTRY(phys_page_table, PERM_PRESENT | PERM_WRITEABLE);
+ return ptr_page_table ;
+ }
+ else
+ return 0 ;
+ }
+ return ptr_page_table ;
+ }
+
+//==================== END of MAPPING KERNEL SPACE ==============================
+
+
+
+
+//========================== MAPPING USER SPACE ==============================
+
+// --------------------------------------------------------------
+// Tracking of physical frames.
+// The 'frames_info' array has one 'struct Frame_Info' entry per physical frame.
+// frames_info are reference counted, and free frames are kept on a linked list.
+// --------------------------------------------------------------
+
+// Initialize paging structure and free_frame_list.
+// After this point, ONLY use the functions below
+// to allocate and deallocate physical memory via the free_frame_list,
+// and NEVER use boot_allocate_space() or the related boot-time functions above.
+//
+void initialize_paging()
+{
+ // The example code here marks all frames_info as free.
+ // However this is not truly the case. What memory is free?
+ // 1) Mark frame 0 as in use.
+ // This way we preserve the real-mode IDT and BIOS structures
+ // in case we ever need them. (Currently we don't, but...)
+ // 2) Mark the rest of base memory as free.
+ // 3) Then comes the IO hole [PHYS_IO_MEM, PHYS_EXTENDED_MEM).
+ // Mark it as in use so that it can never be allocated.
+ // 4) Then extended memory [PHYS_EXTENDED_MEM, ...).
+ // Some of it is in use, some is free. Where is the kernel?
+ // Which frames are used for page tables and other data structures?
+ //
+ // Change the code to reflect this.
+ int i;
+ LIST_INIT(&free_frame_list);
+
+ frames_info[0].references = 1;
+
+ int range_end = ROUNDUP(PHYS_IO_MEM,PAGE_SIZE);
+
+ for (i = 1; i < range_end/PAGE_SIZE; i++)
+ {
+ frames_info[i].references = 0;
+ LIST_INSERT_HEAD(&free_frame_list, &frames_info[i]);
+ }
+
+ for (i = PHYS_IO_MEM/PAGE_SIZE ; i < PHYS_EXTENDED_MEM/PAGE_SIZE; i++)
+ {
+ frames_info[i].references = 1;
+ }
+
+ range_end = ROUNDUP(K_PHYSICAL_ADDRESS(ptr_free_mem), PAGE_SIZE);
+
+ for (i = PHYS_EXTENDED_MEM/PAGE_SIZE ; i < range_end/PAGE_SIZE; i++)
+ {
+ frames_info[i].references = 1;
+ }
+
+ for (i = range_end/PAGE_SIZE ; i < number_of_frames; i++)
+ {
+ frames_info[i].references = 0;
+ LIST_INSERT_HEAD(&free_frame_list, &frames_info[i]);
+ }
+}
+
+//
+// Initialize a Frame_Info structure.
+// The result has null links and 0 references.
+// Note that the corresponding physical frame is NOT initialized!
+//
+void initialize_frame_info(struct Frame_Info *ptr_frame_info)
+{
+ memset(ptr_frame_info, 0, sizeof(*ptr_frame_info));
+}
+
+//
+// Allocates a physical frame.
+// Does NOT set the contents of the physical frame to zero -
+// the caller must do that if necessary.
+//
+// *ptr_frame_info -- is set to point to the Frame_Info struct of the
+// newly allocated frame
+//
+// RETURNS
+// 0 -- on success
+// E_NO_MEM -- otherwise
+//
+// Hint: use LIST_FIRST, LIST_REMOVE, and initialize_frame_info
+// Hint: references should not be incremented
+int allocate_frame(struct Frame_Info **ptr_frame_info)
+{
+ // Fill this function in
+ *ptr_frame_info = LIST_FIRST(&free_frame_list);
+ if(*ptr_frame_info == NULL)
+ return E_NO_MEM;
+
+ LIST_REMOVE(*ptr_frame_info);
+ initialize_frame_info(*ptr_frame_info);
+ return 0;
+}
+
+//
+// Return a frame to the free_frame_list.
+// (This function should only be called when ptr_frame_info->references reaches 0.)
+//
+void free_frame(struct Frame_Info *ptr_frame_info)
+{
+ // Fill this function in
+ LIST_INSERT_HEAD(&free_frame_list, ptr_frame_info);
+}
+
+//
+// Decrement the reference count on a frame
+// freeing it if there are no more references.
+//
+void decrement_references(struct Frame_Info* ptr_frame_info)
+{
+ if (--(ptr_frame_info->references) == 0)
+ free_frame(ptr_frame_info);
+}
+
+//
+// This is like "boot_get_page_table()" with a different allocate function:
+// namely, it should use allocate_frame() instead of boot_allocate_space().
+// Unlike boot_get_page_table(), get_page_table() can fail, so we have to
+// return "ptr_page_table" via a pointer parameter.
+//
+// Stores address of page table entry in *ptr_page_table .
+// Stores 0 if there is no such entry or on error.
+//
+// RETURNS:
+// 0 on success
+// E_NO_MEM, if page table couldn't be allocated
+//
+// Hint: you can use "to_physical_address()" to turn a Frame_Info*
+// into the physical address of the frame it refers to.
+
+int get_page_table(uint32 *ptr_page_directory, const void *virtual_address, int create, uint32 **ptr_page_table)
+{
+ // Fill this function in
+ uint32 page_directory_entry = ptr_page_directory[PDX(virtual_address)];
+
+ *ptr_page_table = K_VIRTUAL_ADDRESS(EXTRACT_ADDRESS(page_directory_entry)) ;
+
+ if (page_directory_entry == 0)
+ {
+ if (create)
+ {
+ struct Frame_Info* ptr_frame_info;
+ int err = allocate_frame(&ptr_frame_info) ;
+ if(err == E_NO_MEM)
+ {
+ *ptr_page_table = 0;
+ return E_NO_MEM;
+ }
+
+ uint32 phys_page_table = to_physical_address(ptr_frame_info);
+ *ptr_page_table = K_VIRTUAL_ADDRESS(phys_page_table) ;
+
+ //initialize new page table by 0's
+ memset(*ptr_page_table , 0, PAGE_SIZE);
+
+ ptr_frame_info->references = 1;
+ ptr_page_directory[PDX(virtual_address)] = CONSTRUCT_ENTRY(phys_page_table, PERM_PRESENT | PERM_USER | PERM_WRITEABLE);
+ }
+ else
+ {
+ *ptr_page_table = 0;
+ return 0;
+ }
+ }
+ return 0;
+}
+
+//
+// Map the physical frame 'ptr_frame_info' at 'virtual_address'.
+// The permissions (the low 12 bits) of the page table
+// entry should be set to 'perm|PERM_PRESENT'.
+//
+// Details
+// - If there is already a frame mapped at 'virtual_address', it should be unmaped
+// using unmap_frame().
+// - If necesary, on demand, allocates a page table and inserts it into 'ptr_page_directory'.
+// - ptr_frame_info->references should be incremented if the insertion succeeds
+//
+// RETURNS:
+// 0 on success
+// E_NO_MEM, if page table couldn't be allocated
+//
+// Hint: implement using get_page_table() and unmap_frame().
+//
+int map_frame(uint32 *ptr_page_directory, struct Frame_Info *ptr_frame_info, void *virtual_address, int perm)
+{
+ // Fill this function in
+ uint32 physical_address = to_physical_address(ptr_frame_info);
+ uint32 *ptr_page_table;
+ if( get_page_table(ptr_page_directory, virtual_address, 1, &ptr_page_table) == 0)
+ {
+ uint32 page_table_entry = ptr_page_table[PTX(virtual_address)];
+
+ //If already mapped
+ if ((page_table_entry & PERM_PRESENT) == PERM_PRESENT)
+ {
+ //on this pa, then do nothing
+ if (EXTRACT_ADDRESS(page_table_entry) == physical_address)
+ return 0;
+ //on another pa, then unmap it
+ else
+ unmap_frame(ptr_page_directory , virtual_address);
+ }
+ ptr_frame_info->references++;
+ ptr_page_table[PTX(virtual_address)] = CONSTRUCT_ENTRY(physical_address , perm | PERM_PRESENT);
+
+ return 0;
+ }
+ return E_NO_MEM;
+}
+
+//
+// Return the frame mapped at 'virtual_address'.
+// If the page table entry corresponding to 'virtual_address' exists, then we store a pointer to the table in 'ptr_page_table'
+// This is used by 'unmap_frame()'
+// but should not be used by other callers.
+//
+// Return 0 if there is no frame mapped at virtual_address.
+//
+// Hint: implement using get_page_table() and get_frame_info().
+//
+struct Frame_Info * get_frame_info(uint32 *ptr_page_directory, void *virtual_address, uint32 **ptr_page_table)
+ {
+ // Fill this function in
+ uint32 ret = get_page_table(ptr_page_directory, virtual_address, 0, ptr_page_table) ;
+ if((*ptr_page_table) != 0)
+ {
+ uint32 index_page_table = PTX(virtual_address);
+ uint32 page_table_entry = (*ptr_page_table)[index_page_table];
+ if( page_table_entry != 0)
+ return to_frame_info( EXTRACT_ADDRESS ( page_table_entry ) );
+ return 0;
+ }
+ return 0;
+ }
+
+//
+// Unmaps the physical frame at 'virtual_address'.
+//
+// Details:
+// - The references count on the physical frame should decrement.
+// - The physical frame should be freed if the 'references' reaches 0.
+// - The page table entry corresponding to 'virtual_address' should be set to 0.
+// (if such a page table exists)
+// - The TLB must be invalidated if you remove an entry from
+// the page directory/page table.
+//
+// Hint: implement using get_frame_info(),
+// tlb_invalidate(), and decrement_references().
+//
+void unmap_frame(uint32 *ptr_page_directory, void *virtual_address)
+{
+ // Fill this function in
+ uint32 *ptr_page_table;
+ struct Frame_Info* ptr_frame_info = get_frame_info(ptr_page_directory, virtual_address, &ptr_page_table);
+ if( ptr_frame_info != 0 )
+ {
+ decrement_references(ptr_frame_info);
+ ptr_page_table[PTX(virtual_address)] = 0;
+ tlb_invalidate(ptr_page_directory, virtual_address);
+ }
+}
+
+//========================== END OF MAPPING USER SPACE ==============================
+//===================================================================================
+//===================================================================================
+//===================================================================================
+//===================================================================================
+//===================================================================================
+
+
+
+
+//======================================================
+// functions used as helpers for malloc() and freeHeap()
+//======================================================
+//[1] get_page:
+// it should allocate one frame and map it to the given virtual address
+// if the virtual address is already mapped, then it return 0
+// Return 0 on success, < 0 on error. Errors are:
+// E_INVAL if virtual_address >= USER_TOP.
+// E_INVAL if perm is not containing PERM_USER.
+// E_NO_MEM if there's no memory to allocate the new page,
+// or to allocate any necessary page tables.
+// HINT: remember to free the allocated frame if there is no space
+// for the necessary page tables
+
+int get_page(uint32* ptr_page_directory, void *virtual_address, int perm)
+{
+ // PROJECT 2008: Your code here.
+ panic("get_page function is not completed yet") ;
+
+ //[1] check virtual address to be < USER_TOP
+ // return E_INVAL if not
+
+ //[2] check the value of perm to contain PERM_USER
+ // return E_INVAL if not
+
+ //[3] check if the page containing the "virtual_address" is already mapped or not
+ // return 0 if the page is already mapped
+ // else:
+ // Allocate a frame from the physical memory,
+ // Map the page to the allocated frame
+ // if there is no free space , return E_NO_MEM
+ // else return 0
+
+ return 0 ;
+}
+
+//[2] calculate_required_frames:
+uint32 calculate_required_frames(uint32* ptr_page_directory, uint32 start_virtual_address, uint32 size)
+{
+ // PROJECT 2008: Your code here.
+ panic("calculate_required_frames function is not completed yet") ;
+
+ //calculate the required page tables
+
+
+ //calc the required page frames
+
+ //return total number of frames
+ return 0;
+}
+
+
+//[3] calculate_free_frames:
+
+uint32 calculate_free_frames()
+{
+ // PROJECT 2008: Your code here.
+ //panic("calculate_free_frames function is not completed yet") ;
+
+ //calculate the free frames from the free frame list
+ struct Frame_Info *ptr;
+ uint32 cnt = 0 ;
+ LIST_FOREACH(ptr, &free_frame_list)
+ {
+ cnt++ ;
+ }
+ return cnt;
+}
+
+//[4] freeMem:
+// This function is used to frees all pages and page tables that are mapped on
+// range [ virtual_address, virtual_address + size ]
+// Steps:
+// 1) Unmap all mapped pages in the range [virtual_address, virtual_address + size ]
+// 2) Free all mapped page tables in this range
+
+void freeMem(uint32* ptr_page_directory, void *virtual_address, uint32 size)
+{
+ // PROJECT 2008: Your code here.
+ panic("freeMem function is not completed yet") ;
+}
diff --git a/kern/memory_manager.h b/kern/memory_manager.h
new file mode 100644
index 0000000..20f480a
--- /dev/null
+++ b/kern/memory_manager.h
@@ -0,0 +1,71 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifndef FOS_KERN_MEM_MAN_H
+#define FOS_KERN_MEM_MAN_H
+#ifndef FOS_KERNEL
+# error "This is a FOS kernel header; user programs should not #include it"
+#endif
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+struct Env;
+
+extern char ptr_stack_top[], ptr_stack_bottom[];
+
+extern struct Frame_Info *frames_info;
+extern uint32 number_of_frames;
+
+
+extern uint32 phys_page_directory;
+extern uint32 *ptr_page_directory;
+
+void boot_map_range(uint32 *ptr_page_directory, uint32 virtual_address, uint32 size, uint32 physical_address, int perm);
+uint32* boot_get_page_table(uint32 *ptr_page_directory, uint32 virtual_address, int create);
+void* boot_allocate_space(uint32 size, uint32 align);
+void initialize_kernel_VM();
+
+void initialize_paging();
+int allocate_frame(struct Frame_Info **ptr_frame_info);
+void free_frame(struct Frame_Info *ptr_frame_info);
+int get_page_table(uint32 *ptr_page_directory, const void *virtual_address, int create, uint32 **ptr_page_table);
+int map_frame(uint32 *ptr_page_directory, struct Frame_Info *ptr_frame_info, void *virtual_address, int perm);
+void unmap_frame(uint32 *pgdir, void *va);
+struct Frame_Info *get_frame_info(uint32 *ptr_page_directory, void *virtual_address, uint32 **ptr_page_table);
+void decrement_references(struct Frame_Info* ptr_frame_info);
+
+static inline uint32 to_frame_number(struct Frame_Info *ptr_frame_info)
+{
+ return ptr_frame_info - frames_info;
+}
+
+static inline uint32 to_physical_address(struct Frame_Info *ptr_frame_info)
+{
+ return to_frame_number(ptr_frame_info) << PGSHIFT;
+}
+
+static inline struct Frame_Info* to_frame_info(uint32 physical_address)
+{
+ if (PPN(physical_address) >= number_of_frames)
+ panic("to_frame_info called with invalid pa");
+ return &frames_info[PPN(physical_address)];
+}
+
+
+int get_page_table(uint32 *ptr_page_directory, const void *virtual_address, int create, uint32 **ptr_page_table);
+
+void loadProcess(int id);
+void initialize_process(int id);
+
+uint32 calculate_free_frames();
+uint32 calculate_required_frames(uint32* ptr_page_directory, uint32 start_virtual_address, uint32 size);
+int get_page(uint32* ptr_page_directory, void *va, int perm);
+void freeMem(uint32* ptr_page_directory, void *virtual_address, uint32 size);
+#endif /* !FOS_KERN_MEM_MAN_H */
diff --git a/kern/printf.c b/kern/printf.c
new file mode 100644
index 0000000..6932ca5
--- /dev/null
+++ b/kern/printf.c
@@ -0,0 +1,37 @@
+// Simple implementation of cprintf console output for the kernel,
+// based on printfmt() and the kernel console's cputchar().
+
+#include
+#include
+#include
+
+
+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/kern/sched.h b/kern/sched.h
new file mode 100644
index 0000000..bb2e770
--- /dev/null
+++ b/kern/sched.h
@@ -0,0 +1,12 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifndef FOS_KERN_SCHED_H
+#define FOS_KERN_SCHED_H
+#ifndef FOS_KERNEL
+# error "This is a FOS kernel header; user programs should not #include it"
+#endif
+
+// This function does not return.
+void sched_yield(void) __attribute__((noreturn));
+
+#endif // !FOS_KERN_SCHED_H
diff --git a/kern/syscall.c b/kern/syscall.c
new file mode 100644
index 0000000..3c9456b
--- /dev/null
+++ b/kern/syscall.c
@@ -0,0 +1,269 @@
+/* See COPYRIGHT for copyright information. */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+// Print a string to the system console.
+// The string is exactly 'len' characters long.
+// Destroys the environment on memory errors.
+static void sys_cputs(const char *s, uint32 len)
+{
+ // Check that the user has permission to read memory [s, s+len).
+ // Destroy the environment if not.
+
+ // LAB 3: Your code here.
+
+ // Print the string supplied by the user.
+ cprintf("%.*s", len, s);
+}
+
+// Read a character from the system console.
+// Returns the character.
+static int
+sys_cgetc(void)
+{
+ int c;
+
+ // The cons_getc() primitive doesn't wait for a character,
+ // but the sys_cgetc() system call does.
+ while ((c = cons_getc()) == 0)
+ /* do nothing */;
+
+ return c;
+}
+
+// Returns the current environment's envid.
+static int32 sys_getenvid(void)
+{
+ return curenv->env_id;
+}
+
+// Destroy a given environment (possibly the currently running environment).
+//
+// Returns 0 on success, < 0 on error. Errors are:
+// -E_BAD_ENV if environment envid doesn't currently exist,
+// or the caller doesn't have permission to change envid.
+static int sys_env_destroy(int32 envid)
+{
+ int r;
+ struct Env *e;
+
+ if ((r = envid2env(envid, &e, 1)) < 0)
+ return r;
+ if (e == curenv)
+ cprintf("[%08x] exiting gracefully\n", curenv->env_id);
+ else
+ cprintf("[%08x] destroying %08x\n", curenv->env_id, e->env_id);
+ env_destroy(e);
+ return 0;
+}
+
+static void sys_env_sleep()
+{
+ env_run_cmd_prmpt();
+}
+
+
+// Allocate a page of memory and map it at 'va' with permission
+// 'perm' in the address space of 'envid'.
+// The page's contents are set to 0.
+// If a page is already mapped at 'va', that page is unmapped as a
+// side effect.
+//
+// perm -- PTE_U | PTE_P must be set, PTE_AVAIL | PTE_W may or may not be set,
+// but no other bits may be set.
+//
+// Return 0 on success, < 0 on error. Errors are:
+// E_BAD_ENV if environment envid doesn't currently exist,
+// or the caller doesn't have permission to change envid.
+// E_INVAL if va >= UTOP, or va is not page-aligned.
+// E_INVAL if perm is inappropriate (see above).
+// E_NO_MEM if there's no memory to allocate the new page,
+// or to allocate any necessary page tables.
+static int sys_allocate_page(void *va, int perm)
+{
+ // Hint: This function is a wrapper around page_alloc() and
+ // page_insert() from kern/pmap.c.
+ // Most of the new code you write should be to check the
+ // parameters for correctness.
+ // If page_insert() fails, remember to free the page you
+ // allocated!
+
+ int r;
+ struct Env *e = curenv;
+
+ //if ((r = envid2env(envid, &e, 1)) < 0)
+ //return r;
+
+ struct Frame_Info *ptr_frame_info ;
+ r = allocate_frame(&ptr_frame_info) ;
+ if (r == E_NO_MEM)
+ return r ;
+
+ //check virtual address to be paged_aligned and < USER_TOP
+ if ((uint32)va >= USER_TOP || (uint32)va % PAGE_SIZE != 0)
+ return E_INVAL;
+
+ //check permissions to be appropriatess
+ if ((perm & (~PERM_AVAILABLE & ~PERM_WRITEABLE)) != (PERM_USER))
+ return E_INVAL;
+
+
+ uint32 physical_address = to_physical_address(ptr_frame_info) ;
+
+ memset(K_VIRTUAL_ADDRESS(physical_address), 0, PAGE_SIZE);
+
+ r = map_frame(e->env_pgdir, ptr_frame_info, va, perm) ;
+ if (r == E_NO_MEM)
+ {
+ decrement_references(ptr_frame_info);
+ return r;
+ }
+ return 0 ;
+}
+
+// Allocate a page of memory and map it at 'va' with permission
+// 'perm' in the address space of 'envid'.
+// The page's contents are set to 0.
+// If a page is already mapped at 'va', that function does nothing
+//
+// Return 0 on success, < 0 on error. Errors are:
+// E_BAD_ENV if environment envid doesn't currently exist,
+// or the caller doesn't have permission to change envid.
+// E_INVAL if va >= UTOP, or va is not page-aligned.
+// E_INVAL if perm is inappropriate (see above).
+// E_NO_MEM if there's no memory to allocate the new page,
+// or to allocate any necessary page tables.
+static int sys_get_page(void *va, int perm)
+{
+ return get_page(curenv->env_pgdir, va, perm) ;
+}
+
+// Map the page of memory at 'srcva' in srcenvid's address space
+// at 'dstva' in dstenvid's address space with permission 'perm'.
+// Perm has the same restrictions as in sys_page_alloc, except
+// that it also must not grant write access to a read-only
+// page.
+//
+// Return 0 on success, < 0 on error. Errors are:
+// -E_BAD_ENV if srcenvid and/or dstenvid doesn't currently exist,
+// or the caller doesn't have permission to change one of them.
+// -E_INVAL if srcva >= UTOP or srcva is not page-aligned,
+// or dstva >= UTOP or dstva is not page-aligned.
+// -E_INVAL is srcva is not mapped in srcenvid's address space.
+// -E_INVAL if perm is inappropriate (see sys_page_alloc).
+// -E_INVAL if (perm & PTE_W), but srcva is read-only in srcenvid's
+// address space.
+// -E_NO_MEM if there's no memory to allocate the new page,
+// or to allocate any necessary page tables.
+static int sys_map_frame(int32 srcenvid, void *srcva, int32 dstenvid, void *dstva, int perm)
+{
+ // Hint: This function is a wrapper around page_lookup() and
+ // page_insert() from kern/pmap.c.
+ // Again, most of the new code you write should be to check the
+ // parameters for correctness.
+ // Use the third argument to page_lookup() to
+ // check the current permissions on the page.
+
+ // LAB 4: Your code here.
+ panic("sys_map_frame not implemented");
+}
+
+// Unmap the page of memory at 'va' in the address space of 'envid'.
+// If no page is mapped, the function silently succeeds.
+//
+// Return 0 on success, < 0 on error. Errors are:
+// -E_BAD_ENV if environment envid doesn't currently exist,
+// or the caller doesn't have permission to change envid.
+// -E_INVAL if va >= UTOP, or va is not page-aligned.
+static int sys_unmap_frame(int32 envid, void *va)
+{
+ // Hint: This function is a wrapper around page_remove().
+
+ // LAB 4: Your code here.
+ panic("sys_page_unmap not implemented");
+}
+
+uint32 sys_calculate_required_frames(uint32 start_virtual_address, uint32 size)
+{
+ return calculate_required_frames(curenv->env_pgdir, start_virtual_address, size);
+}
+
+uint32 sys_calculate_free_frames()
+{
+ return calculate_free_frames();
+}
+void sys_freeMem(void* start_virtual_address, uint32 size)
+{
+ freeMem((uint32*)curenv->env_pgdir, (void*)start_virtual_address, size);
+ return;
+}
+// Dispatches to the correct kernel function, passing the arguments.
+uint32
+syscall(uint32 syscallno, uint32 a1, uint32 a2, uint32 a3, uint32 a4, uint32 a5)
+{
+ // Call the function corresponding to the 'syscallno' parameter.
+ // Return any appropriate return value.
+ // LAB 3: Your code here.
+ switch(syscallno)
+ {
+ case SYS_cputs:
+ sys_cputs((const char*)a1,a2);
+ return 0;
+ break;
+ case SYS_cgetc:
+ return sys_cgetc();
+ break;
+ case SYS_getenvid:
+ return sys_getenvid();
+ break;
+ case SYS_env_destroy:
+ return sys_env_destroy(a1);
+ break;
+ case SYS_env_sleep:
+ sys_env_sleep();
+ return 0;
+ break;
+ case SYS_calc_req_frames:
+ return sys_calculate_required_frames(a1, a2);
+ break;
+ case SYS_calc_free_frames:
+ return sys_calculate_free_frames();
+ break;
+ case SYS_freeMem:
+ sys_freeMem((void*)a1, a2);
+ return 0;
+ break;
+ //======================
+
+ case SYS_allocate_page:
+ sys_allocate_page((void*)a1, a2);
+ return 0;
+ break;
+ case SYS_get_page:
+ sys_get_page((void*)a1, a2);
+ return 0;
+ break;case SYS_map_frame:
+ sys_map_frame(a1, (void*)a2, a3, (void*)a4, a5);
+ return 0;
+ break;
+ case SYS_unmap_frame:
+ sys_unmap_frame(a1, (void*)a2);
+ return 0;
+ break;
+ case NSYSCALLS:
+ return -E_INVAL;
+ break;
+ }
+ //panic("syscall not implemented");
+ return -E_INVAL;
+}
+
diff --git a/kern/syscall.h b/kern/syscall.h
new file mode 100644
index 0000000..752aa5a
--- /dev/null
+++ b/kern/syscall.h
@@ -0,0 +1,11 @@
+#ifndef FOS_KERN_SYSCALL_H
+#define FOS_KERN_SYSCALL_H
+#ifndef FOS_KERNEL
+# error "This is a FOS kernel header; user programs should not #include it"
+#endif
+
+#include
+
+uint32 syscall(uint32 num, uint32 a1, uint32 a2, uint32 a3, uint32 a4, uint32 a5);
+
+#endif /* !FOS_KERN_SYSCALL_H */
diff --git a/kern/trap.c b/kern/trap.c
new file mode 100644
index 0000000..b448600
--- /dev/null
+++ b/kern/trap.c
@@ -0,0 +1,219 @@
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+static struct Taskstate ts;
+
+/* Interrupt descriptor table. (Must be built at run time because
+ * shifted function addresses can't be represented in relocation records.)
+ */
+struct Gatedesc idt[256] = { { 0 } };
+struct Pseudodesc idt_pd = {
+ sizeof(idt) - 1, (uint32) idt
+};
+extern void (*PAGE_FAULT)();
+extern void (*SYSCALL_HANDLER)();
+
+static const char *trapname(int trapno)
+{
+ static const char * const excnames[] = {
+ "Divide error",
+ "Debug",
+ "Non-Maskable Interrupt",
+ "Breakpoint",
+ "Overflow",
+ "BOUND Range Exceeded",
+ "Invalid Opcode",
+ "Device Not Available",
+ "Double Falt",
+ "Coprocessor Segment Overrun",
+ "Invalid TSS",
+ "Segment Not Present",
+ "Stack Fault",
+ "General Protection",
+ "Page Fault",
+ "(unknown trap)",
+ "x87 FPU Floating-Point Error",
+ "Alignment Check",
+ "Machine-Check",
+ "SIMD Floating-Point Exception"
+ };
+
+ if (trapno < sizeof(excnames)/sizeof(excnames[0]))
+ return excnames[trapno];
+ if (trapno == T_SYSCALL)
+ return "System call";
+ return "(unknown trap)";
+}
+
+
+void
+idt_init(void)
+{
+ extern struct Segdesc gdt[];
+
+ // LAB 3: Your code here.
+ //initialize idt
+ SETGATE(idt[T_PGFLT], 0, GD_KT , &PAGE_FAULT, 0) ;
+ SETGATE(idt[T_SYSCALL], 0, GD_KT , &SYSCALL_HANDLER, 3) ;
+
+ // Setup a TSS so that we get the right stack
+ // when we trap to the kernel.
+ ts.ts_esp0 = KERNEL_STACK_TOP;
+ ts.ts_ss0 = GD_KD;
+
+ // Initialize the TSS field of the gdt.
+ gdt[GD_TSS >> 3] = SEG16(STS_T32A, (uint32) (&ts),
+ sizeof(struct Taskstate), 0);
+ gdt[GD_TSS >> 3].sd_s = 0;
+
+ // Load the TSS
+ ltr(GD_TSS);
+
+ // Load the IDT
+ asm volatile("lidt idt_pd");
+}
+
+void
+print_trapframe(struct Trapframe *tf)
+{
+ cprintf("TRAP frame at %p\n", tf);
+ print_regs(&tf->tf_regs);
+ cprintf(" es 0x----%04x\n", tf->tf_es);
+ cprintf(" ds 0x----%04x\n", tf->tf_ds);
+ cprintf(" trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
+ cprintf(" err 0x%08x\n", tf->tf_err);
+ cprintf(" eip 0x%08x\n", tf->tf_eip);
+ cprintf(" cs 0x----%04x\n", tf->tf_cs);
+ cprintf(" flag 0x%08x\n", tf->tf_eflags);
+ cprintf(" esp 0x%08x\n", tf->tf_esp);
+ cprintf(" ss 0x----%04x\n", tf->tf_ss);
+}
+
+void
+print_regs(struct PushRegs *regs)
+{
+ cprintf(" edi 0x%08x\n", regs->reg_edi);
+ cprintf(" esi 0x%08x\n", regs->reg_esi);
+ cprintf(" ebp 0x%08x\n", regs->reg_ebp);
+ cprintf(" oesp 0x%08x\n", regs->reg_oesp);
+ cprintf(" ebx 0x%08x\n", regs->reg_ebx);
+ cprintf(" edx 0x%08x\n", regs->reg_edx);
+ cprintf(" ecx 0x%08x\n", regs->reg_ecx);
+ cprintf(" eax 0x%08x\n", regs->reg_eax);
+}
+
+static void
+trap_dispatch(struct Trapframe *tf)
+{
+ // Handle processor exceptions.
+ // LAB 3: Your code here.
+
+ if(tf->tf_trapno == T_PGFLT)
+ {
+ page_fault_handler(tf);
+ }
+ else if (tf->tf_trapno == T_SYSCALL)
+ {
+ uint32 ret = syscall(tf->tf_regs.reg_eax
+ ,tf->tf_regs.reg_edx
+ ,tf->tf_regs.reg_ecx
+ ,tf->tf_regs.reg_ebx
+ ,tf->tf_regs.reg_edi
+ ,tf->tf_regs.reg_esi);
+ tf->tf_regs.reg_eax = ret;
+ }
+ else
+ {
+ // Unexpected trap: The user process or the kernel has a bug.
+ print_trapframe(tf);
+ if (tf->tf_cs == GD_KT)
+ panic("unhandled trap in kernel");
+ else {
+ env_destroy(curenv);
+ return;
+ }
+ }
+ return;
+}
+
+void
+trap(struct Trapframe *tf)
+{
+ //cprintf("Incoming TRAP frame at %p\n", tf);
+
+ if ((tf->tf_cs & 3) == 3) {
+ // Trapped from user mode.
+ // Copy trap frame (which is currently on the stack)
+ // into 'curenv->env_tf', so that running the environment
+ // will restart at the trap point.
+ assert(curenv);
+ curenv->env_tf = *tf;
+ // The trapframe on the stack should be ignored from here on.
+ tf = &curenv->env_tf;
+ }
+
+ // Dispatch based on what type of trap occurred
+ trap_dispatch(tf);
+
+ // Return to the current environment, which should be runnable.
+ assert(curenv && curenv->env_status == ENV_RUNNABLE);
+ env_run(curenv);
+}
+
+
+void
+page_fault_handler(struct Trapframe *tf)
+{
+ uint32 fault_va;
+
+ // Read processor's CR2 register to find the faulting address
+ fault_va = rcr2();
+
+ // Handle kernel-mode page faults.
+
+ // LAB 3: Your code here.
+
+ // We've already handled kernel-mode exceptions, so if we get here,
+ // the page fault happened in user mode.
+
+ // Call the environment's page fault upcall, if one exists. Set up a
+ // page fault stack frame on the user exception stack (below
+ // UXSTACKTOP), then branch to curenv->env_pgfault_upcall.
+ //
+ // The page fault upcall might cause another page fault, in which case
+ // we branch to the page fault upcall recursively, pushing another
+ // page fault stack frame on top of the user exception stack.
+ //
+ // The trap handler needs one word of scratch space at the top of the
+ // trap-time stack in order to return. In the non-recursive case, we
+ // don't have to worry about this because the top of the regular user
+ // stack is free. In the recursive case, this means we have to leave
+ // an extra word between the current top of the exception stack and
+ // the new stack frame because the exception stack _is_ the trap-time
+ // stack.
+ //
+ // If there's no page fault upcall, the environment didn't allocate a
+ // page for its exception stack, or the exception stack overflows,
+ // then destroy the environment that caused the fault.
+ //
+ // Hints:
+ // user_mem_assert() and env_run() are useful here.
+ // To change what the user environment runs, modify 'curenv->env_tf'
+ // (the 'tf' variable points at 'curenv->env_tf').
+
+ // Destroy the environment that caused the fault.
+ cprintf("[%08x] user fault va %08x ip %08x\n",
+ curenv->env_id, fault_va, tf->tf_eip);
+ print_trapframe(tf);
+ env_destroy(curenv);
+
+}
+
diff --git a/kern/trap.h b/kern/trap.h
new file mode 100644
index 0000000..fe080f2
--- /dev/null
+++ b/kern/trap.h
@@ -0,0 +1,21 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifndef FOS_KERN_TRAP_H
+#define FOS_KERN_TRAP_H
+#ifndef FOS_KERNEL
+# error "This is a FOS kernel header; user programs should not #include it"
+#endif
+
+#include
+#include
+
+/* The kernel's interrupt descriptor table */
+extern struct Gatedesc idt[];
+
+void idt_init(void);
+void print_regs(struct PushRegs *regs);
+void print_trapframe(struct Trapframe *tf);
+void page_fault_handler(struct Trapframe *);
+void backtrace(struct Trapframe *);
+
+#endif /* FOS_KERN_TRAP_H */
diff --git a/kern/trapentry.S b/kern/trapentry.S
new file mode 100644
index 0000000..873b89c
--- /dev/null
+++ b/kern/trapentry.S
@@ -0,0 +1,76 @@
+/* See COPYRIGHT for copyright information. */
+
+#include
+#include
+#include
+
+
+
+###################################################################
+# exceptions/interrupts
+###################################################################
+
+/* The TRAPHANDLER macro defines a globally-visible function for handling
+ * a trap. It pushes a trap number onto the stack, then jumps to _alltraps.
+ * Use TRAPHANDLER for traps where the CPU automatically pushes an error code.
+ */
+#define TRAPHANDLER(name, num) \
+ .globl name; /* define global symbol for 'name' */ \
+ .type name, @function; /* symbol type is function */ \
+ .align 2; /* align function definition */ \
+ name: /* function starts here */ \
+ pushl $(num); \
+ jmp _alltraps
+
+/* Use TRAPHANDLER_NOEC for traps where the CPU doesn't push an error code.
+ * It pushes a 0 in place of the error code, so the trap frame has the same
+ * format in either case.
+ */
+#define TRAPHANDLER_NOEC(name, num) \
+ .globl name; \
+ .type name, @function; \
+ .align 2; \
+ name: \
+ pushl $0; \
+ pushl $(num); \
+ jmp _alltraps
+
+.text
+
+/*
+ * Lab 3: Your code here for generating entry points for the different traps.
+ */
+
+TRAPHANDLER(PAGE_FAULT, T_PGFLT)
+
+TRAPHANDLER_NOEC(SYSCALL_HANDLER, T_SYSCALL)
+
+
+/*
+ * Lab 3: Your code here for _alltraps
+ */
+_alltraps:
+
+push %ds
+push %es
+pushal
+
+mov $(GD_KD), %ax
+mov %ax,%ds
+mov %ax,%es
+
+push %esp
+
+call trap
+
+pop %ecx /* poping the pointer to the tf from the stack so that the stack top is at the values of the registers posuhed by pusha*/
+popal
+pop %es
+pop %ds
+
+/*skipping the trap_no and the error code so that the stack top is at the old eip value*/
+add $(8),%esp
+
+iret
+
+
diff --git a/kern/user_environment.c b/kern/user_environment.c
new file mode 100644
index 0000000..8a2d43e
--- /dev/null
+++ b/kern/user_environment.c
@@ -0,0 +1,541 @@
+/* See COPYRIGHT for copyright information. */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+struct Env *envs = NULL; // All environments
+struct Env *curenv = NULL; // The current env
+static struct Env_list env_free_list; // Free Environment list
+
+#define ENVGENSHIFT 12 // >= LOGNENV
+
+//Contains information about each program segment (e.g. start address, size, virtual address...)
+//It will be used below in "env_create" to load each program segment into the user environment
+struct ProgramSegment {
+ uint8 *ptr_start;
+ uint32 size_in_file;
+ uint32 size_in_memory;
+ uint8 *virtual_address;
+
+ // for use only with PROGRAM_SEGMENT_FOREACH
+ uint32 segment_id;
+};
+
+// Used inside the PROGRAM_SEGMENT_FOREACH macro to get the first program segment
+// and then iterate on the next ones
+struct ProgramSegment* PROGRAM_SEGMENT_NEXT(struct ProgramSegment* seg, uint8* ptr_program_start);
+struct ProgramSegment PROGRAM_SEGMENT_FIRST( uint8* ptr_program_start);
+
+// Used inside "env_create" function to get information about each program segment inside the user program
+#define PROGRAM_SEGMENT_FOREACH(Seg, ptr_program_start) \
+ struct ProgramSegment* first; \
+ struct ProgramSegment tmp; \
+ tmp = (PROGRAM_SEGMENT_FIRST(ptr_program_start)); \
+ first = &tmp; \
+ if(first->segment_id == -1) first = NULL;\
+ Seg = first; \
+ for (; \
+ Seg; \
+ Seg = PROGRAM_SEGMENT_NEXT(Seg,ptr_program_start) )
+
+// Helper functions to be used below
+void complete_environment_initialization(struct Env* e);
+void set_environment_entry_point(struct UserProgramInfo *ptr_user_program_info);
+
+//=========================================================
+//PROJECT 2008: your code is here
+// To add FOS support for new user program, just add the appropriate lines like below
+
+//The input for any DECLARE_START_OF macro must be the ".c" filename of the user program
+DECLARE_START_OF(fos_helloWorld)
+DECLARE_START_OF(fos_add)
+DECLARE_START_OF(fos_alloc)
+DECLARE_START_OF(fos_input)
+DECLARE_START_OF(game)
+
+
+//User Programs Table
+//The input for any PTR_START_OF macro must be the ".c" filename of the user program
+struct UserProgramInfo userPrograms[] = {
+ { "fos_helloWorld", "Created by FOS team, fos@nowhere.com", PTR_START_OF(fos_helloWorld), 0 },
+ { "fos_add", "Created by FOS team, fos@nowhere.com", PTR_START_OF(fos_add), 0},
+ { "fos_alloc", "Created by FOS team, fos@nowhere.com", PTR_START_OF(fos_alloc), 0},
+ { "fos_input", "Created by FOS team, fos@nowhere.com", PTR_START_OF(fos_input), 0},
+ { "fos_game", "Created by FOS team, fos@nowhere.com", PTR_START_OF(game), 0},
+};
+
+//=========================================================
+
+// To be used as extrern in other files
+struct UserProgramInfo* ptr_UserPrograms = &userPrograms[0];
+
+// Number of user programs in the program table
+int NUM_USER_PROGS = (sizeof(userPrograms)/sizeof(userPrograms[0]));
+
+//
+// Allocates and initializes a new environment.
+// On success, the new environment is stored in *e.
+//
+// Returns 0 on success, < 0 on failure. Errors include:
+// E_NO_FREE_ENV if all NENVS environments are allocated
+//
+int allocate_environment(struct Env** e)
+{
+ if (!(*e = LIST_FIRST(&env_free_list)))
+ return E_NO_FREE_ENV;
+ return 0;
+}
+
+// Free the given environment "e", simply by adding it to the free environment list.
+void free_environment(struct Env* e)
+{
+ curenv = NULL;
+ // return the environment to the free list
+ e->env_status = ENV_FREE;
+ LIST_INSERT_HEAD(&env_free_list, e);
+}
+
+
+
+//
+// Allocate length bytes of physical memory for environment e,
+// and map it at virtual address va in the environment's address space.
+// Does not zero or otherwise initialize the mapped pages in any way.
+// Pages should be writable by user and kernel.
+//
+// if the allocation failed, return E_NO_MEM
+// otherwise return 0
+//
+static int program_segment_alloc_map(struct Env *e, void *va, uint32 length)
+{
+ //TODO: LAB6 Hands-on: fill this function.
+ //Comment the following line
+ panic("Function is not implemented yet!");
+
+ //You should round round "va + length" up, and "va" down.
+ //your code here ...
+
+ return 0;
+}
+
+//
+// Allocates a new env and loads the named user program into it.
+struct UserProgramInfo* env_create(char* user_program_name)
+{
+ //[1] get pointer to the start of the "user_program_name" program in memory
+ // Hint: use "get_user_program_info" function,
+ // you should set the following "ptr_program_start" by the start address of the user program
+ uint8* ptr_program_start = 0;
+
+ struct UserProgramInfo* ptr_user_program_info =get_user_program_info(user_program_name);
+
+ if (ptr_user_program_info == 0)
+ return NULL ;
+
+ ptr_program_start = ptr_user_program_info->ptr_start ;
+
+ //[2] allocate new environment, (from the free environment list)
+ //if there's no one, return NULL
+ // Hint: use "allocate_environment" function
+ struct Env* e = NULL;
+ if(allocate_environment(&e) == E_NO_FREE_ENV)
+ {
+ return 0;
+ }
+
+ //=========================================================
+ //TODO: LAB6 Hands-on: fill this part.
+ //Comment the following line
+ panic("env_create: directory creation is not implemented yet!");
+
+ //[3] allocate a frame for the page directory, Don't forget to set the references of the allocated frame.
+ //if there's no free space, return NULL
+ //your code here . . .
+
+
+ //[4] copy kernel directory into the new directory
+ //your code here . . .
+
+
+ //[5] set e->env_pgdir to page directory virtual address
+ //and e->env_cr3 to page directory physical address.
+ //your code here
+
+
+ //============================================================
+
+ //Complete other environment initializations, (envID, status and most of registers)
+ complete_environment_initialization(e);
+
+ //[6] update the UserProgramInfo in userPrograms[] corresponding to this program
+ ptr_user_program_info->environment = e;
+
+ // We want to load the program into the user virtual space
+ // each program is constructed from one or more segments,
+ // each segment has the following information grouped in "struct ProgramSegment"
+ // 1- uint8 *ptr_start: start address of this segment in memory
+ // 2- uint32 size_in_file: size occupied by this segment inside the program file,
+ // 3- uint32 size_in_memory: actual size required by this segment in memory
+ // usually size_in_file < or = size_in_memory
+ // 4- uint8 *virtual_address: start virtual address that this segment should be copied to it
+
+ //switch to user page directory
+ // rcr3() reads cr3, lcr3() loads cr3
+ int32 kern_phys_pgdir = rcr3() ;
+ lcr3(e->env_cr3) ;
+
+ //load each program segment into user virtual space
+ struct ProgramSegment* seg = NULL; //use inside PROGRAM_SEGMENT_FOREACH as current segment information
+
+ PROGRAM_SEGMENT_FOREACH(seg, ptr_program_start)
+ {
+ //============================================================
+ //[7] allocate space for current program segment and map it at
+ //seg->virtual_address
+ // if program_segment_alloc_map() returns E_NO_MEM, call env_free() to free all environment memory,
+ // zero the UserProgramInfo* ptr->environment then return NULL
+
+ //Hands On 2: implementation of function program_segment_alloc_map()
+ int ret = program_segment_alloc_map(e, (void *)seg->virtual_address, seg->size_in_memory) ;
+
+ if (ret == E_NO_MEM)
+ {
+ cprintf("Load program failed: no enough memory\n\nProgram will be unloaded now...\n\n");
+ env_free(e);
+ ptr_user_program_info->environment = NULL;
+ return NULL;
+ }
+ //============================================================
+
+ //[8] copy program segment from (seg->ptr_start) to
+ //(seg->virtual_address) with size seg->size_in_file
+ uint8 *src_ptr = (uint8 *)(seg->ptr_start) ;
+ uint8 *dst_ptr = (uint8 *) seg->virtual_address;
+
+ int i ;
+
+ for(i = 0 ; i < seg->size_in_file; i++)
+ {
+ *dst_ptr = *src_ptr ;
+ dst_ptr++ ;
+ src_ptr++ ;
+ }
+
+ //Initialize the rest of the program segment the rest
+ //(seg->size_in_memory - seg->size_in_file) bytes
+ //By Zero
+ for(i = seg->size_in_file ; i < seg->size_in_memory ; i++)
+ {
+ *dst_ptr = 0 ;
+ dst_ptr++;
+ }
+ }
+
+ //[9] now set the entry point of the environment
+ set_environment_entry_point(ptr_user_program_info);
+
+
+ //[10] Allocate and map one page for the program's initial stack
+ // at virtual address USTACKTOP - PAGE_SIZE.
+ // if there is no free memory, call env_free() to free all env. memory,
+ // zero the UserProgramInfo* ptr->environment then return NULL
+
+ struct Frame_Info *pp = NULL;
+ if (allocate_frame(&pp) == E_NO_MEM)
+ {
+ cprintf("Load program failed: no enough memory\n\nProgram will be unloaded now...\n\n");
+ env_free(e);
+ ptr_user_program_info->environment = NULL;
+ return NULL;
+ }
+
+ // map the allocated page
+ void* ptr_user_stack_bottom = (void *)(USTACKTOP - PAGE_SIZE);
+ int ret = map_frame(e->env_pgdir, pp, ptr_user_stack_bottom, PERM_USER|PERM_WRITEABLE);
+
+ if (ret == E_NO_MEM)
+ {
+ cprintf("Load program failed: no enough memory\n\nProgram will be unloaded now...\n\n");
+ env_free(e);
+ ptr_user_program_info->environment = NULL;
+ return NULL;
+ }
+
+ //initialize new page by 0's
+ memset(ptr_user_stack_bottom, 0, PAGE_SIZE);
+
+ //[11] switch back to the page directory exists before segment loading
+ lcr3(kern_phys_pgdir) ;
+
+ return ptr_user_program_info;
+}
+
+// Used to run the given environment "e", simply by
+// context switch from curenv to env e.
+// (This function does not return.)
+//
+void env_run(struct Env *e)
+{
+ if(curenv != e)
+ {
+ curenv = e ;
+ curenv->env_runs++ ;
+ lcr3(curenv->env_cr3) ;
+ }
+ env_pop_tf(&(curenv->env_tf));
+}
+
+//
+// Frees environment "e" and all memory it uses.
+//
+void env_free(struct Env *e)
+{
+ panic("env_free function is not completed yet") ;
+
+ // [1] Unmap all mapped pages in the user portion of the environment (i.e. below USER_TOP)
+
+ // [2] Free all mapped page tables in the user portion of the environment
+
+ // [3] free the page directory of the environment
+
+ // [4] switch back to the kernel page directory
+
+ // [5] free the environment (return it back to the free environment list)
+ // Hint: use free_environment()
+}
+
+
+//====================================================================================
+//====================================================================================
+//====================================================================================
+//====================================================================================
+//====================================================================================
+
+
+// Mark all environments in 'envs' as free, set their env_ids to 0,
+// and insert them into the env_free_list.
+// Insert in reverse order, so that the first call to allocate_environment()
+// returns envs[0].
+//
+void
+env_init(void)
+{
+ int iEnv = NENV-1;
+ for(; iEnv >= 0; iEnv--)
+ {
+ envs[iEnv].env_status = ENV_FREE;
+ envs[iEnv].env_id = 0;
+ LIST_INSERT_HEAD(&env_free_list, &envs[iEnv]);
+ }
+}
+
+void complete_environment_initialization(struct Env* e)
+{
+ //VPT and UVPT map the env's own page table, with
+ //different permissions.
+ e->env_pgdir[PDX(VPT)] = e->env_cr3 | PERM_PRESENT | PERM_WRITEABLE;
+ e->env_pgdir[PDX(UVPT)] = e->env_cr3 | PERM_PRESENT | PERM_USER;
+
+ int32 generation;
+ // Generate an env_id for this environment.
+ generation = (e->env_id + (1 << ENVGENSHIFT)) & ~(NENV - 1);
+ if (generation <= 0) // Don't create a negative env_id.
+ generation = 1 << ENVGENSHIFT;
+ e->env_id = generation | (e - envs);
+
+ // Set the basic status variables.
+ e->env_parent_id = 0;//parent_id;
+ e->env_status = ENV_RUNNABLE;
+ e->env_runs = 0;
+
+ // Clear out all the saved register state,
+ // to prevent the register values
+ // of a prior environment inhabiting this Env structure
+ // from "leaking" into our new environment.
+ memset(&e->env_tf, 0, sizeof(e->env_tf));
+
+ // Set up appropriate initial values for the segment registers.
+ // GD_UD is the user data segment selector in the GDT, and
+ // GD_UT is the user text segment selector (see inc/memlayout.h).
+ // The low 2 bits of each segment register contains the
+ // Requestor Privilege Level (RPL); 3 means user mode.
+
+ e->env_tf.tf_ds = GD_UD | 3;
+ e->env_tf.tf_es = GD_UD | 3;
+ e->env_tf.tf_ss = GD_UD | 3;
+ e->env_tf.tf_esp = (uint32*)USTACKTOP;
+ e->env_tf.tf_cs = GD_UT | 3;
+ // You will set e->env_tf.tf_eip later.
+
+ // commit the allocation
+ LIST_REMOVE(e);
+ return ;
+}
+
+struct ProgramSegment* PROGRAM_SEGMENT_NEXT(struct ProgramSegment* seg, uint8* ptr_program_start)
+ {
+ int index = (*seg).segment_id++;
+
+ struct Proghdr *ph, *eph;
+ struct Elf * pELFHDR = (struct Elf *)ptr_program_start ;
+ if (pELFHDR->e_magic != ELF_MAGIC)
+ panic("Matafa2nash 3ala Keda");
+ ph = (struct Proghdr *) ( ((uint8 *) ptr_program_start) + pELFHDR->e_phoff);
+
+ while (ph[(*seg).segment_id].p_type != ELF_PROG_LOAD && ((*seg).segment_id < pELFHDR->e_phnum)) (*seg).segment_id++;
+ index = (*seg).segment_id;
+
+ if(index < pELFHDR->e_phnum)
+ {
+ (*seg).ptr_start = (uint8 *) ptr_program_start + ph[index].p_offset;
+ (*seg).size_in_memory = ph[index].p_memsz;
+ (*seg).size_in_file = ph[index].p_filesz;
+ (*seg).virtual_address = (uint8*)ph[index].p_va;
+ return seg;
+ }
+ return 0;
+ }
+
+struct ProgramSegment PROGRAM_SEGMENT_FIRST( uint8* ptr_program_start)
+{
+ struct ProgramSegment seg;
+ seg.segment_id = 0;
+
+ struct Proghdr *ph, *eph;
+ struct Elf * pELFHDR = (struct Elf *)ptr_program_start ;
+ if (pELFHDR->e_magic != ELF_MAGIC)
+ panic("Matafa2nash 3ala Keda");
+ ph = (struct Proghdr *) ( ((uint8 *) ptr_program_start) + pELFHDR->e_phoff);
+ while (ph[(seg).segment_id].p_type != ELF_PROG_LOAD && ((seg).segment_id < pELFHDR->e_phnum)) (seg).segment_id++;
+ int index = (seg).segment_id;
+
+ if(index < pELFHDR->e_phnum)
+ {
+ (seg).ptr_start = (uint8 *) ptr_program_start + ph[index].p_offset;
+ (seg).size_in_memory = ph[index].p_memsz;
+ (seg).size_in_file = ph[index].p_filesz;
+ (seg).virtual_address = (uint8*)ph[index].p_va;
+ return seg;
+ }
+ seg.segment_id = -1;
+ return seg;
+}
+
+struct UserProgramInfo* get_user_program_info(char* user_program_name)
+ {
+ int i;
+ for (i = 0; i < NUM_USER_PROGS; i++) {
+ if (strcmp(user_program_name, userPrograms[i].name) == 0)
+ break;
+ }
+ if(i==NUM_USER_PROGS)
+ {
+ cprintf("Unknown user program '%s'\n", user_program_name);
+ return 0;
+ }
+
+ return &userPrograms[i];
+ }
+
+struct UserProgramInfo* get_user_program_info_by_env(struct Env* e)
+ {
+ int i;
+ for (i = 0; i < NUM_USER_PROGS; i++) {
+ if (e== userPrograms[i].environment)
+ break;
+ }
+ if(i==NUM_USER_PROGS)
+ {
+ cprintf("Unknown user program \n");
+ return 0;
+ }
+
+ return &userPrograms[i];
+ }
+
+void set_environment_entry_point(struct UserProgramInfo* ptr_user_program)
+{
+ uint8* ptr_program_start=ptr_user_program->ptr_start;
+ struct Env* e = ptr_user_program->environment;
+
+ struct Elf * pELFHDR = (struct Elf *)ptr_program_start ;
+ if (pELFHDR->e_magic != ELF_MAGIC)
+ panic("Matafa2nash 3ala Keda");
+ e->env_tf.tf_eip = (uint32*)pELFHDR->e_entry ;
+}
+
+
+
+//
+// Frees environment e.
+// If e was the current env, then runs a new environment (and does not return
+// to the caller).
+//
+void
+env_destroy(struct Env *e)
+{
+ env_free(e);
+
+ //cprintf("Destroyed the only environment - nothing more to do!\n");
+ while (1)
+ run_command_prompt();
+}
+
+void env_run_cmd_prmpt()
+{
+ struct UserProgramInfo* upi= get_user_program_info_by_env(curenv);
+ // Clear out all the saved register state,
+ // to prevent the register values
+ // of a prior environment inhabiting this Env structure
+ // from "leaking" into our new environment.
+ memset(&curenv->env_tf, 0, sizeof(curenv->env_tf));
+
+ // Set up appropriate initial values for the segment registers.
+ // GD_UD is the user data segment selector in the GDT, and
+ // GD_UT is the user text segment selector (see inc/memlayout.h).
+ // The low 2 bits of each segment register contains the
+ // Requestor Privilege Level (RPL); 3 means user mode.
+
+ curenv->env_tf.tf_ds = GD_UD | 3;
+ curenv->env_tf.tf_es = GD_UD | 3;
+ curenv->env_tf.tf_ss = GD_UD | 3;
+ curenv->env_tf.tf_esp = (uint32*)USTACKTOP;
+ curenv->env_tf.tf_cs = GD_UT | 3;
+ set_environment_entry_point(upi);
+
+ lcr3(K_PHYSICAL_ADDRESS(ptr_page_directory));
+
+ curenv = NULL;
+
+ while (1)
+ run_command_prompt();
+}
+
+//
+// Restores the register values in the Trapframe with the 'iret' instruction.
+// This exits the kernel and starts executing some environment's code.
+// This function does not return.
+//
+void
+env_pop_tf(struct Trapframe *tf)
+{
+ __asm __volatile("movl %0,%%esp\n"
+ "\tpopal\n"
+ "\tpopl %%es\n"
+ "\tpopl %%ds\n"
+ "\taddl $0x8,%%esp\n" /* skip tf_trapno and tf_errcode */
+ "\tiret"
+ : : "g" (tf) : "memory");
+ panic("iret failed"); /* mostly to placate the compiler */
+}
+
diff --git a/kern/user_environment.h b/kern/user_environment.h
new file mode 100644
index 0000000..3cc1dee
--- /dev/null
+++ b/kern/user_environment.h
@@ -0,0 +1,53 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifndef FOS_KERN_ENV_H
+#define FOS_KERN_ENV_H
+
+#ifndef FOS_MULTIENV
+// Change this value to 1 once you're allowing multiple environments
+// (for UCLA: Lab 3, Part 3; for MIT: Lab 4).
+#define FOS_MULTIENV 0
+#endif
+
+#include
+
+#define DECLARE_START_OF(binary_name) \
+ extern uint8 _binary_obj_user_##binary_name##_start[];
+
+#define PTR_START_OF(binary_name) ( \
+ (uint8*) _binary_obj_user_##binary_name##_start \
+)
+
+//=========================================================
+struct UserProgramInfo {
+ const char *name;
+ const char *desc;
+ uint8* ptr_start;
+ struct Env* environment;
+};
+
+//========================================================
+//extern struct UserProgramInfo userPrograms[];
+extern struct UserProgramInfo* ptr_UserPrograms;
+extern int NUM_USER_PROGS;
+
+//=========================================================
+
+extern struct Env *envs; // All environments
+extern struct Env *curenv; // Current environment
+
+LIST_HEAD(Env_list, Env); // Declares 'struct Env_list'
+
+void env_init(void);
+int env_alloc(struct Env **e, int32 parent_id);
+void env_free(struct Env *e);
+struct UserProgramInfo* env_create(char* user_program_name);
+void env_destroy(struct Env *e); // Does not return if e == curenv
+
+// The following two functions do not return
+void env_run(struct Env *e) __attribute__((noreturn));
+void env_pop_tf(struct Trapframe *tf) __attribute__((noreturn));
+struct UserProgramInfo* get_user_program_info(char* user_program_name);
+void env_run_cmd_prmpt();
+
+#endif // !FOS_KERN_ENV_H
diff --git a/lib/Makefrag b/lib/Makefrag
new file mode 100644
index 0000000..e1d5a0d
--- /dev/null
+++ b/lib/Makefrag
@@ -0,0 +1,32 @@
+OBJDIRS += lib
+
+LIB_SRCFILES := lib/console.c \
+ lib/libmain.c \
+ lib/exit.c \
+ lib/panic.c \
+ lib/printf.c \
+ lib/printfmt.c \
+ lib/readline.c \
+ lib/string.c \
+ lib/malloc.c \
+ lib/syscall.c
+
+
+
+
+LIB_OBJFILES := $(patsubst lib/%.c, $(OBJDIR)/lib/%.o, $(LIB_SRCFILES))
+LIB_OBJFILES := $(patsubst lib/%.S, $(OBJDIR)/lib/%.o, $(LIB_OBJFILES))
+
+$(OBJDIR)/lib/%.o: lib/%.c
+ @echo + cc[USER] $<
+ @mkdir -p $(@D)
+ $(V)$(CC) -nostdinc $(USER_CFLAGS) -c -o $@ $<
+
+$(OBJDIR)/lib/%.o: lib/%.S
+ @echo + as [USER] $<
+ @mkdir -p $(@D)
+ $(V)$(CC) -nostdinc $(USER_CFLAGS) -c -o $@ $<
+
+$(OBJDIR)/lib/libfos.a: $(LIB_OBJFILES)
+ @echo + ar $@
+ $(V)$(AR) r $@ $(LIB_OBJFILES)
diff --git a/lib/console.c b/lib/console.c
new file mode 100644
index 0000000..095a877
--- /dev/null
+++ b/lib/console.c
@@ -0,0 +1,26 @@
+
+#include
+#include
+
+void
+cputchar(int ch)
+{
+ char c = ch;
+
+ // Unlike standard Unix's putchar,
+ // the cputchar function _always_ outputs to the system console.
+ sys_cputs(&c, 1);
+}
+
+int
+getchar(void)
+{
+ return sys_cgetc();
+}
+
+
+int iscons(int fdnum)
+{
+ // used by readline
+ return 1;
+}
diff --git a/lib/entry.S b/lib/entry.S
new file mode 100644
index 0000000..28272fb
--- /dev/null
+++ b/lib/entry.S
@@ -0,0 +1,38 @@
+#include
+#include
+
+.data
+
+
+// Define the global symbols 'envs', 'pages', 'vpt', and 'vpd'
+// so that they can be used in C as if they were ordinary global arrays.
+ .globl envs
+ .set envs, UENVS
+ .globl frames_info
+ .set frames_info, READ_ONLY_FRAMES_INFO
+ .globl vpt
+ .set vpt, UVPT
+ .globl vpd
+ .set vpd, (UVPT+(UVPT>>12)*4)
+
+
+// Entrypoint - this is where the kernel (or our parent environment)
+// starts us running when we are initially loaded into a new environment.
+.text
+.globl _start
+_start:
+ // See if we were started with arguments on the stack
+ mov $0, %eax
+ cmpl $USTACKTOP, %esp
+ jne args_exist
+
+ // If not, push dummy argc/argv arguments.
+ // This happens when we are loaded by the kernel,
+ // because the kernel does not know about passing arguments.
+ pushl $0
+ pushl $0
+
+args_exist:
+ call libmain
+1: jmp 1b
+
diff --git a/lib/exit.c b/lib/exit.c
new file mode 100644
index 0000000..1e44523
--- /dev/null
+++ b/lib/exit.c
@@ -0,0 +1,14 @@
+
+#include
+
+void
+exit(void)
+{
+ sys_env_destroy(0);
+}
+
+void
+sleep(void)
+{
+ sys_env_sleep();
+}
diff --git a/lib/libmain.c b/lib/libmain.c
new file mode 100644
index 0000000..ec123ac
--- /dev/null
+++ b/lib/libmain.c
@@ -0,0 +1,29 @@
+// Called from entry.S to get us going.
+// entry.S already took care of defining envs, pages, vpd, and vpt.
+
+#include
+
+extern void _main(int argc, char **argv);
+
+volatile struct Env *env;
+char *binaryname = "(PROGRAM NAME UNKNOWN)";
+
+void
+libmain(int argc, char **argv)
+{
+ // set env to point at our env structure in envs[].
+ // LAB 3: Your code here.
+ env = envs;
+
+ // save the name of the program so that panic() can use it
+ if (argc > 0)
+ binaryname = argv[0];
+
+ // call user main routine
+ _main(argc, argv);
+
+ // exit gracefully
+ //exit();
+ sleep();
+}
+
diff --git a/lib/malloc.c b/lib/malloc.c
new file mode 100644
index 0000000..37b2945
--- /dev/null
+++ b/lib/malloc.c
@@ -0,0 +1,107 @@
+
+#include
+
+/*
+ * Simple malloc
+ *
+ * The address space for the dynamic allocation is
+ * from "ptr_user_free_mem" to USER_TOP-1
+ * Pages are allocated, used to fill successive
+ * malloc requests.
+ * On succeed, return void pointer to the allocated space
+ * return NULL if
+ * the required allocation is outside the user heap area
+ * the required number of frames (pages and page tables) is not available
+ */
+
+// Hint: since malloc deal with memory, and since we now in the user mode,
+// so you will need to use some functions that switch to the kernel to apply
+// certain operation using the kern/memory_manager functions and
+// then switch back to the user mode to continue execution
+// These functions are:
+// [1] uint32 sys_calculate_free_frames()
+// calculate the number of free frames in the physical memory and return it
+// [2] uint32 sys_calculate_required_frames(uint32 start_virtual_address, uint32 size)
+// Calculate the required number of frames (for pages and page tables)
+// for mapping the virtual range [start_virtual_address, start_virtual_address + size]
+// and return it
+// [3] int sys_get_page(void *virtual_address, int perm)
+// allocate one frame in the physical memory and map it to "virtual_address"
+// with the given "perm" permissions.
+// if the page is already mapped , sys_get_page will do nothing
+// If allocation and mapping succeed, it return 0
+// else, it return -ve value
+
+
+static uint8 *ptr_user_free_mem = (uint8*) USER_HEAP_START;
+
+void* malloc(uint32 size)
+{
+ //PROJECT 2008: your code here
+ //
+
+ panic("malloc is not implemented yet");
+
+ // [1] Check if the required allocation is within the user heap area,
+ // if not then return NULL.
+
+
+ // [2] Calculate the required number of frames (for pages and page tables) for the new heap allocation.
+ // Hint: Use function sys_calculate_required_frames(uint32 start_virtual_address,uint32 size).
+ // This function will switch to the kernel mode, calls the kernel function
+ // calculate_required_frames(uint32* ptr_page_directory, uint32 start_virtual_address, uint32 size) in
+ // "memory_manager.c" then switch back to user mode, the later function is empty, please go fill it.
+
+
+ // [3] Calculate the number of free frames in the physical memory.
+ // Hint: Use function sys_calculate_free_frames() to calculate the free frames.
+ // This function will switch to the kernel mode, calls the kernel function calculate_free_frames() in
+ // "memory_manager.c" then switch back to user mode, the later function is empty, please go fill it.
+
+
+ // [4] Check if the required number of frames available.
+ // If available:
+ // For each page in the range [ ptr_user_free_mem, ptr_user_free_mem + size ] do:
+ // Make sure that the page is not mapped to an allocated frame
+ // Note: the first page of the range may be partially used by previous allocation (i.e. already allocated)
+ // If the page is not mapped:
+ // Allocate a frame from the physical memory,
+ // Map the page to the allocated frame
+ // Hint: Use sys_get_page (void *virtual _address, int perm) to perform these steps. This function will switch to kernel mode, calls the kernel function get_page (uint32* ptr_page_directory, void *virtual_address, int perm) in "memory_manager.c" then switch back to user mode, the later function is empty, please go fill it.
+
+
+ // Update the ptr_user_free_mem.
+ // Return pointer containing the virtual address of allocated space, the pointer should not exceed USER_HEAP_MAX - 1
+ // Else:
+ // Print error message and return NULL.
+
+
+ return NULL ;
+}
+
+//=================================================================================//
+//============================== BONUS FUNCTION ===================================//
+//=================================================================================//
+
+// freeHeap:
+// This function frees all the dynamic allocated space starting at USER_HEAP_START
+// to ptr_user_free_mem
+// Steps:
+// 1) Unmap all mapped pages in the range [USER_HEAP_START, ptr_user_free_mem]
+// 2) Free all mapped page tables in this range
+// 3) Set ptr_user_free_mem to USER_HEAP_START
+// To do these steps, we need to switch to the kernel, unmap the pages and page tables
+// then switch back to the user again.
+// Hint: Use function sys_freeMem(void* start_virtual_address, uint32 size) which
+// will switch to the kernel mode, then calls
+// freeMem(uint32* ptr_page_directory, void* start_virtual_address, uint32 size) in
+// "memory_manager.c" then switch back to user mode, the later function is empty,
+// please go fill it.
+
+void freeHeap()
+{
+ //PROJECT 2008: your code here
+ //
+
+ panic("freeHeap is not implemented yet");
+}
diff --git a/lib/panic.c b/lib/panic.c
new file mode 100644
index 0000000..bd7833a
--- /dev/null
+++ b/lib/panic.c
@@ -0,0 +1,29 @@
+
+#include
+
+char *argv0;
+
+/*
+ * Panic is called on unresolvable fatal errors.
+ * It prints "panic: ", then causes a breakpoint exception,
+ * which causes FOS to enter the FOS kernel monitor.
+ */
+void
+_panic(const char *file, int line, const char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ // Print the panic message
+ if (argv0)
+ cprintf("%s: ", argv0);
+ cprintf("user panic in %s at %s:%d: ", binaryname, file, line);
+ vcprintf(fmt, ap);
+ cprintf("\n");
+
+ // Cause a breakpoint exception
+ while (1)
+ asm volatile("int3");
+}
+
diff --git a/lib/printf.c b/lib/printf.c
new file mode 100644
index 0000000..59d90c6
--- /dev/null
+++ b/lib/printf.c
@@ -0,0 +1,62 @@
+// Implementation of cprintf console output for user environments,
+// based on printfmt() and the sys_cputs() system call.
+//
+// cprintf is a debugging statement, not a generic output statement.
+// It is very important that it always go to the console, especially when
+// debugging file descriptor code!
+
+#include
+#include
+#include
+#include
+
+
+// Collect up to 256 characters into a buffer
+// and perform ONE system call to print all of them,
+// in order to make the lines output to the console atomic
+// and prevent interrupts from causing context switches
+// in the middle of a console output line and such.
+struct printbuf {
+ int idx; // current buffer index
+ int cnt; // total bytes printed so far
+ char buf[256];
+};
+
+
+static void
+putch(int ch, struct printbuf *b)
+{
+ b->buf[b->idx++] = ch;
+ if (b->idx == 256-1) {
+ sys_cputs(b->buf, b->idx);
+ b->idx = 0;
+ }
+ b->cnt++;
+}
+
+int
+vcprintf(const char *fmt, va_list ap)
+{
+ struct printbuf b;
+
+ b.idx = 0;
+ b.cnt = 0;
+ vprintfmt((void*)putch, &b, fmt, ap);
+ sys_cputs(b.buf, b.idx);
+
+ return b.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
index 0000000..50f18ab
--- /dev/null
+++ b/lib/printfmt.c
@@ -0,0 +1,301 @@
+// 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
+#include
+#include
+#include
+#include
+
+/*
+ * 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':
+ // Replace this with your code.
+ putch('X', putdat);
+ putch('X', putdat);
+ putch('X', putdat);
+ break;
+
+ // pointer
+ case 'p':
+ putch('0', putdat);
+ putch('x', putdat);
+ num = (unsigned long long)
+ (uint32) 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
index 0000000..1b2e474
--- /dev/null
+++ b/lib/readline.c
@@ -0,0 +1,38 @@
+#include
+#include
+
+#define BUFLEN 1024
+//static char buf[BUFLEN];
+
+void readline(const char *prompt, char* buf)
+{
+ int i, c, echoing;
+
+ if (prompt != NULL)
+ cprintf("%s", prompt);
+
+
+ i = 0;
+ echoing = iscons(0);
+ while (1) {
+ c = getchar();
+ if (c < 0) {
+ if (c != -E_EOF)
+ cprintf("read error: %e\n", c);
+ return;
+ } 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;
+ }
+ }
+}
diff --git a/lib/string.c b/lib/string.c
new file mode 100644
index 0000000..babf02a
--- /dev/null
+++ b/lib/string.c
@@ -0,0 +1,255 @@
+// Basic string routines. Not hardware optimized, but not shabby.
+
+#include
+
+int
+strlen(const char *s)
+{
+ int n;
+
+ for (n = 0; *s != '\0'; s++)
+ n++;
+ return n;
+}
+
+int
+strnlen(const char *s, uint32 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, uint32 size) {
+ uint32 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;
+}
+
+uint32
+strlcpy(char *dst, const char *src, uint32 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, uint32 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, uint32 n)
+{
+ char *p;
+ int m;
+
+ p = v;
+ m = n;
+ while (--m >= 0)
+ *p++ = c;
+
+ return v;
+}
+
+void *
+memcpy(void *dst, const void *src, uint32 n)
+{
+ const char *s;
+ char *d;
+
+ s = src;
+ d = dst;
+ while (n-- > 0)
+ *d++ = *s++;
+
+ return dst;
+}
+
+void *
+memmove(void *dst, const void *src, uint32 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, uint32 n)
+{
+ const uint8 *s1 = (const uint8 *) v1;
+ const uint8 *s2 = (const uint8 *) v2;
+
+ while (n-- > 0) {
+ if (*s1 != *s2)
+ return (int) *s1 - (int) *s2;
+ s1++, s2++;
+ }
+
+ return 0;
+}
+
+void *
+memfind(const void *s, int c, uint32 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);
+}
+
+int strsplit(char *string, char *SPLIT_CHARS, char **argv, int * argc)
+{
+ // Parse the command string into splitchars-separated arguments
+ *argc = 0;
+ (argv)[*argc] = 0;
+ while (1)
+ {
+ // trim splitchars
+ while (*string && strchr(SPLIT_CHARS, *string))
+ *string++ = 0;
+
+ //if the command string is finished, then break the loop
+ if (*string == 0)
+ break;
+
+ //check current number of arguments
+ if (*argc == MAX_ARGUMENTS-1)
+ {
+ return 0;
+ }
+
+ // save the previous argument and scan past next arg
+ (argv)[(*argc)++] = string;
+ while (*string && !strchr(SPLIT_CHARS, *string))
+ string++;
+ }
+ (argv)[*argc] = 0;
+ return 1 ;
+}
diff --git a/lib/syscall.c b/lib/syscall.c
new file mode 100644
index 0000000..0d5e0d0
--- /dev/null
+++ b/lib/syscall.c
@@ -0,0 +1,99 @@
+// System call stubs.
+
+#include
+#include
+
+static inline uint32
+syscall(int num, uint32 a1, uint32 a2, uint32 a3, uint32 a4, uint32 a5)
+{
+ uint32 ret;
+
+ // Generic system call: pass system call number in AX,
+ // up to five parameters in DX, CX, BX, DI, SI.
+ // Interrupt kernel with T_SYSCALL.
+ //
+ // The "volatile" tells the assembler not to optimize
+ // this instruction away just because we don't use the
+ // return value.
+ //
+ // The last clause tells the assembler that this can
+ // potentially change the condition codes and arbitrary
+ // memory locations.
+
+ asm volatile("int %1\n"
+ : "=a" (ret)
+ : "i" (T_SYSCALL),
+ "a" (num),
+ "d" (a1),
+ "c" (a2),
+ "b" (a3),
+ "D" (a4),
+ "S" (a5)
+ : "cc", "memory");
+
+ return ret;
+}
+
+void
+sys_cputs(const char *s, uint32 len)
+{
+ syscall(SYS_cputs, (uint32) s, len, 0, 0, 0);
+}
+
+int
+sys_cgetc(void)
+{
+ return syscall(SYS_cgetc, 0, 0, 0, 0, 0);
+}
+
+int sys_env_destroy(int32 envid)
+{
+ return syscall(SYS_env_destroy, envid, 0, 0, 0, 0);
+}
+
+int32 sys_getenvid(void)
+{
+ return syscall(SYS_getenvid, 0, 0, 0, 0, 0);
+}
+
+void sys_env_sleep(void)
+{
+ syscall(SYS_env_sleep, 0, 0, 0, 0, 0);
+}
+
+
+int sys_allocate_page(void *va, int perm)
+{
+ return syscall(SYS_allocate_page, (uint32) va, perm, 0 , 0, 0);
+}
+
+int sys_get_page(void *va, int perm)
+{
+ return syscall(SYS_get_page, (uint32) va, perm, 0 , 0, 0);
+}
+
+int sys_map_frame(int32 srcenv, void *srcva, int32 dstenv, void *dstva, int perm)
+{
+ return syscall(SYS_map_frame, srcenv, (uint32) srcva, dstenv, (uint32) dstva, perm);
+}
+
+int sys_unmap_frame(int32 envid, void *va)
+{
+ return syscall(SYS_unmap_frame, envid, (uint32) va, 0, 0, 0);
+}
+
+uint32 sys_calculate_required_frames(uint32 start_virtual_address, uint32 size)
+{
+ return syscall(SYS_calc_req_frames, start_virtual_address, (uint32) size, 0, 0, 0);
+}
+
+uint32 sys_calculate_free_frames()
+{
+ return syscall(SYS_calc_free_frames, 0, 0, 0, 0, 0);
+}
+
+void sys_freeMem(void* start_virtual_address, uint32 size)
+{
+ syscall(SYS_freeMem, (uint32) start_virtual_address, size, 0, 0, 0);
+ return;
+}
diff --git a/mergedep.pl b/mergedep.pl
new file mode 100644
index 0000000..1730d53
--- /dev/null
+++ b/mergedep.pl
@@ -0,0 +1,86 @@
+#!/usr/bin/perl
+# Copyright 2003 Bryan Ford
+# Distributed under the GNU General Public License.
+#
+# Usage: mergedep [ ...]
+#
+# This script merges the contents of all specified
+# on the command line into the single file ,
+# which may or may not previously exist.
+# Dependencies in the will override
+# any existing dependencies for the same targets in .
+# The are deleted after is updated.
+#
+# The are typically generated by GCC with the -MD option,
+# and the 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 ,
+# 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 () {
+ if (/([^:]*):([^\\:]*)([\\]?)$/) {
+ my $target = $1;
+ my $deplines = $2;
+ my $slash = $3;
+ while ($slash ne '') {
+ $_ = ;
+ 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 [ ..]\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/snapshot.txt b/snapshot.txt
new file mode 100644
index 0000000..80a7777
Binary files /dev/null and b/snapshot.txt differ
diff --git a/user/Makefrag b/user/Makefrag
new file mode 100644
index 0000000..2e35b13
--- /dev/null
+++ b/user/Makefrag
@@ -0,0 +1,12 @@
+OBJDIRS += user
+
+$(OBJDIR)/user/%.o: user/%.c
+ @echo + cc[USER] $<
+ @mkdir -p $(@D)
+ $(V)$(CC) -nostdinc $(USER_CFLAGS) -c -o $@ $<
+
+$(OBJDIR)/user/%: $(OBJDIR)/user/%.o $(OBJDIR)/lib/entry.o $(OBJDIR)/lib/libfos.a user/user.ld
+ @echo + ld -m elf_i386 $@
+ $(V)$(LD) -o $@ $(ULDFLAGS) $(LDFLAGS) -nostdlib $(OBJDIR)/lib/entry.o $@.o -L$(OBJDIR)/lib -lfos $(GCC_LIB)
+ $(V)$(OBJDUMP) -S $@ > $@.asm
+ $(V)$(NM) -n $@ > $@.sym
diff --git a/user/fos_add.c b/user/fos_add.c
new file mode 100644
index 0000000..2fc09c5
--- /dev/null
+++ b/user/fos_add.c
@@ -0,0 +1,15 @@
+// hello, world
+#include
+
+void
+_main(void)
+{
+ int i1=0;
+ int i2=0;
+
+ i1 = strtol("1", NULL, 10);
+ i2 = strtol("2", NULL, 10);
+
+ cprintf("number 1 + number 2 = %d\n",i1+i2);
+ return;
+}
diff --git a/user/fos_alloc.c b/user/fos_alloc.c
new file mode 100644
index 0000000..6fecf98
--- /dev/null
+++ b/user/fos_alloc.c
@@ -0,0 +1,35 @@
+
+#include
+
+void
+_main(void)
+{
+ int size = 10 ;
+ int *x = malloc(sizeof(int)*size) ;
+ int *y = malloc(sizeof(int)*size) ;
+ int *z = malloc(sizeof(int)*size) ;
+
+ int i ;
+ for (i = 0 ; i < size ; i++)
+ {
+ x[i] = i ;
+ y[i] = 10 ;
+ z[i] = (int)x[i] * y[i] ;
+ }
+
+ for (i = 0 ; i < size ; i++)
+ cprintf("%d * %d = %d\n",x[i], y[i], z[i]);
+
+ freeHeap();
+ cprintf("the heap is freed successfully\n");
+ z = malloc(sizeof(int)*size) ;
+ for (i = 0 ; i < size ; i++)
+ {
+ cprintf("x[i] = %d\t",x[i]);
+ cprintf("y[i] = %d\t",y[i]);
+ cprintf("z[i] = %d\n",z[i]);
+
+ }
+
+ return;
+}
diff --git a/user/fos_helloWorld.c b/user/fos_helloWorld.c
new file mode 100644
index 0000000..0a76546
--- /dev/null
+++ b/user/fos_helloWorld.c
@@ -0,0 +1,8 @@
+// hello, world
+#include
+
+void
+_main(void)
+{
+ cprintf("HELLO WORLD , FOS IS SAYING HI :D:D:D\n");
+}
diff --git a/user/fos_input.c b/user/fos_input.c
new file mode 100644
index 0000000..ddba422
--- /dev/null
+++ b/user/fos_input.c
@@ -0,0 +1,20 @@
+
+#include
+
+void
+_main(void)
+{
+ int i1=0;
+ int i2=0;
+ char buff1[256];
+ char buff2[256];
+
+ readline("Please enter first number :", buff1);
+ i1 = strtol(buff1, NULL, 10);
+ readline("Please enter second number :", buff2);
+
+ i2 = strtol(buff2, NULL, 10);
+
+ cprintf("number 1 + number 2 = %d\n",i1+i2);
+ return;
+}
diff --git a/user/game.c b/user/game.c
new file mode 100644
index 0000000..f3bbc49
--- /dev/null
+++ b/user/game.c
@@ -0,0 +1,24 @@
+#include
+
+void
+_main(void)
+{
+ int i=28;
+ for(;i<128; i++)
+ {
+ int c=0;
+ for(;c<10; c++)
+ {
+ cprintf("%c",i);
+ }
+ int d=0;
+ for(; d< 500000; d++);
+ c=0;
+ for(;c<10; c++)
+ {
+ cprintf("\b");
+ }
+ }
+
+ return;
+}
diff --git a/user/user.ld b/user/user.ld
new file mode 100644
index 0000000..e1d0cfe
--- /dev/null
+++ b/user/user.ld
@@ -0,0 +1,72 @@
+/* Simple linker script for FOS 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)
+ }
+}