From 8639fae15e1de34f8ce40ce98dfff434158c0a90 Mon Sep 17 00:00:00 2001 From: Youssef Raafat Date: Sun, 23 Feb 2020 08:33:20 +0200 Subject: [PATCH] Add version 1 files --- .bochsrc | 749 +++++++++++++++++ .bochsrc-debug | 755 ++++++++++++++++++ .cproject | 216 +++++ .gdbinit | 3 + .gitignore | 5 + .project | 77 ++ .../de.loskutov.anyedit.AnyEditTools.prefs | 18 + .settings/language.settings.xml | 11 + .settings/org.eclipse.cdt.codan.core.prefs | 71 ++ .settings/org.eclipse.cdt.core.prefs | 6 + .../org.eclipse.ltk.core.refactoring.prefs | 2 + BIOS-bochs-latest | Bin 0 -> 131072 bytes BIOS-bochs-latest_2-3 | Bin 0 -> 65536 bytes Credits_and_Thanks.txt | 5 + Debug_Readme.txt | 1 + FOS_Developer_Console.bat | 8 + GNUmakefile | 174 ++++ VGABIOS-lgpl-latest | Bin 0 -> 41472 bytes bochscon.bat | 5 + boot/Makefrag | 32 + boot/boot.S | 98 +++ boot/main.c | 120 +++ boot/sign.pl | 19 + coding | 35 + conf/env.mk | 23 + conf/lab.mk | 2 + grade.sh | 283 +++++++ inc/COPYRIGHT | 229 ++++++ inc/assert.h | 20 + inc/elf.h | 65 ++ inc/environment_definitions.h | 49 ++ inc/error.h | 19 + inc/kbdreg.h | 83 ++ inc/lib.h | 65 ++ inc/malloc.h | 7 + inc/memlayout.h | 181 +++++ inc/mmu.h | 312 ++++++++ inc/queue.h | 219 +++++ inc/stab.h | 52 ++ inc/stdarg.h | 19 + inc/stdio.h | 35 + inc/string.h | 28 + inc/syscall.h | 22 + inc/trap.h | 74 ++ inc/types.h | 72 ++ inc/x86.h | 277 +++++++ kern/COPYRIGHT | 155 ++++ kern/Makefrag | 85 ++ kern/command_prompt.c | 408 ++++++++++ kern/command_prompt.h | 16 + kern/console.c | 456 +++++++++++ kern/console.h | 27 + kern/entry.S | 105 +++ kern/helpers.c | 366 +++++++++ kern/helpers.h | 80 ++ kern/init.c | 116 +++ kern/kclock.c | 26 + kern/kclock.h | 33 + kern/kdebug.c | 228 ++++++ kern/kdebug.h | 20 + kern/kernel.ld | 59 ++ kern/memory_manager.c | 595 ++++++++++++++ kern/memory_manager.h | 71 ++ kern/printf.c | 37 + kern/sched.h | 12 + kern/syscall.c | 269 +++++++ kern/syscall.h | 11 + kern/trap.c | 219 +++++ kern/trap.h | 21 + kern/trapentry.S | 76 ++ kern/user_environment.c | 541 +++++++++++++ kern/user_environment.h | 53 ++ lib/Makefrag | 32 + lib/console.c | 26 + lib/entry.S | 38 + lib/exit.c | 14 + lib/libmain.c | 29 + lib/malloc.c | 107 +++ lib/panic.c | 29 + lib/printf.c | 62 ++ lib/printfmt.c | 301 +++++++ lib/readline.c | 38 + lib/string.c | 255 ++++++ lib/syscall.c | 99 +++ mergedep.pl | 86 ++ snapshot.txt | Bin 0 -> 800 bytes user/Makefrag | 12 + user/fos_add.c | 15 + user/fos_alloc.c | 35 + user/fos_helloWorld.c | 8 + user/fos_input.c | 20 + user/game.c | 24 + user/user.ld | 72 ++ 93 files changed, 9933 insertions(+) create mode 100644 .bochsrc create mode 100644 .bochsrc-debug create mode 100644 .cproject create mode 100644 .gdbinit create mode 100644 .gitignore create mode 100644 .project create mode 100644 .settings/de.loskutov.anyedit.AnyEditTools.prefs create mode 100644 .settings/language.settings.xml create mode 100644 .settings/org.eclipse.cdt.codan.core.prefs create mode 100644 .settings/org.eclipse.cdt.core.prefs create mode 100644 .settings/org.eclipse.ltk.core.refactoring.prefs create mode 100644 BIOS-bochs-latest create mode 100644 BIOS-bochs-latest_2-3 create mode 100644 Credits_and_Thanks.txt create mode 100644 Debug_Readme.txt create mode 100644 FOS_Developer_Console.bat create mode 100644 GNUmakefile create mode 100644 VGABIOS-lgpl-latest create mode 100644 bochscon.bat create mode 100644 boot/Makefrag create mode 100644 boot/boot.S create mode 100644 boot/main.c create mode 100644 boot/sign.pl create mode 100644 coding create mode 100644 conf/env.mk create mode 100644 conf/lab.mk create mode 100644 grade.sh create mode 100644 inc/COPYRIGHT create mode 100644 inc/assert.h create mode 100644 inc/elf.h create mode 100644 inc/environment_definitions.h create mode 100644 inc/error.h create mode 100644 inc/kbdreg.h create mode 100644 inc/lib.h create mode 100644 inc/malloc.h create mode 100644 inc/memlayout.h create mode 100644 inc/mmu.h create mode 100644 inc/queue.h create mode 100644 inc/stab.h create mode 100644 inc/stdarg.h create mode 100644 inc/stdio.h create mode 100644 inc/string.h create mode 100644 inc/syscall.h create mode 100644 inc/trap.h create mode 100644 inc/types.h create mode 100644 inc/x86.h create mode 100644 kern/COPYRIGHT create mode 100644 kern/Makefrag create mode 100644 kern/command_prompt.c create mode 100644 kern/command_prompt.h create mode 100644 kern/console.c create mode 100644 kern/console.h create mode 100644 kern/entry.S create mode 100644 kern/helpers.c create mode 100644 kern/helpers.h create mode 100644 kern/init.c create mode 100644 kern/kclock.c create mode 100644 kern/kclock.h create mode 100644 kern/kdebug.c create mode 100644 kern/kdebug.h create mode 100644 kern/kernel.ld create mode 100644 kern/memory_manager.c create mode 100644 kern/memory_manager.h create mode 100644 kern/printf.c create mode 100644 kern/sched.h create mode 100644 kern/syscall.c create mode 100644 kern/syscall.h create mode 100644 kern/trap.c create mode 100644 kern/trap.h create mode 100644 kern/trapentry.S create mode 100644 kern/user_environment.c create mode 100644 kern/user_environment.h create mode 100644 lib/Makefrag create mode 100644 lib/console.c create mode 100644 lib/entry.S create mode 100644 lib/exit.c create mode 100644 lib/libmain.c create mode 100644 lib/malloc.c create mode 100644 lib/panic.c create mode 100644 lib/printf.c create mode 100644 lib/printfmt.c create mode 100644 lib/readline.c create mode 100644 lib/string.c create mode 100644 lib/syscall.c create mode 100644 mergedep.pl create mode 100644 snapshot.txt create mode 100644 user/Makefrag create mode 100644 user/fos_add.c create mode 100644 user/fos_alloc.c create mode 100644 user/fos_helloWorld.c create mode 100644 user/fos_input.c create mode 100644 user/game.c create mode 100644 user/user.ld 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 0000000000000000000000000000000000000000..742c32226dd7bf2d5926a1bdaa84f09fb6d16004 GIT binary patch literal 131072 zcmeFZdwi2swl}_?ByH2uHlY+OSRr6Qkb(_2sTK`wNkO?piim;*6ygm5At~r6wx)$V zjd3`0bUVH7e*M3q<-A-c?W80VDW5ktu~8a#X$N%s`<~hmR7yA=lw`Z>MD`khS=B&G^`+O)h|9h97*Y*nM z4R1I$_WaveVo3I;>A=~Jwp7M8>rtxz+F0MDPp+?cZysai;@>dh>eD-RDm(?4aD=-HksjXIKvGU`&I&1 zJaXQDm)w6lD^Fp*ZKyDJy&qcB7ps$*0 z&Ww%jI^b`-7ya}0dhB7>d2gb3t`4%*pU@}o=R&7(&cwE@ooU1xWW~clbC6rNb?dpU ze<%H%sjPE#>>#2FAG<)eIvh@9743}anCC9yV~fm33iu$FWIj@Q_;>;R6+R5fd~lL7 z1>-?W^Gg>th%LT<-h?WfTjE_{PWATkmgs06!R!H!U-2Fq`DAuF&WZs(n_IgbXC0IJ zJmpN8U)tdN$1v*esOVl_?!rXRFAbWy!{NEScZ6smCn_7qkIC5CO;V?5cp?ttL#*15hHAJzF* zrqr57q_cokFE}>38=%L#!)W)+3|DjvLxU^iTWfsxCX@g*Y%2}B8-9jn*uhG~deX9lRe+&I3fWqMi3EMZc=EjaCz3ts5-vvK;qKPhh?>X4p2y zy-N@-=DqK_)Oy@A4-zkYu)%UXbV(7UXFibNg8%U2S1o^CxZd@1ac=Sjxz<3268+rzH!qw@#)b3mJ9m~KuL4u`T7JFXYN zi{ah-!-jVY!Xp}7>3J7ir!95p$o&EtPy_UY-n#PJV9DZs4#&DGpU7NoBlb5~>KYsy z@4atsiTlh%2x0d=Yo6m>W}fbrgsM7GXEwYP&|+?6yEJS|s;qO~n?KZfkJuK{Z!B*g z>P!>&8n)R5-&CRUpzB=T$E)uU_l@YdJ=?ra>&-Tk9>jq2x`=$b>pVq$87c4(?5TM~ zwpsYXu+1unA6M2HD$_8-hIfkvcU!KZvQYzv(RQ=%KB2M5tTSQm4VC)<^G)4vX>ngk zUej-*FLfJ8`J7Yt8{X9b4rp1(a@^fE+E8id-IuwNpc>MWZ|a}jS4_TV1jB~DXbPKs z9IuV_3&zdb_U9?yfYFQDWd7B8aXA+C}yoqf3dX7~1F zb9*}Mx*%SJI(#`HP>{rtC8b*`_;h{e6=#!cGYAs8xGK@;u{jjLB+a(Jyfs0moRbA5Bnw~lx}coBRm z_Cf6I&=W6UkoZC|hN~HPeXQ`OJv(_ zHdKvAD;C>4bR@CdjXH0xh&n7em`6R~Z!kFlYj{-f7Z_f~)kJW!BDh(=72AXNKtIr4 z|JEbd=nr~j!Sg_~)CJ$f19o}F=qoatL~>e1=4?FmcxK_L!!uLVnWbPyIPBhSl>JCa z#Tlaxvs!7+!o%H^|eQ>TMB(_v0W}Atwv(meJB&F8ryyGeAt8YpMT8_{>iD4Iq;pd}jHEfuH9<&U=U>5Lc|A4T@oy-c!oaUU7 zPIK1K@STVl8}nM%XvA)6755CK_WH91_qR#zJrB6sg#Kaibj1l8QoMpm$aa5y!u{PS zaFyw3jv0mqW)!P|G~;{#IMDrxP)rcpA|hMggKb&{Kvp~T9K%Qo7l*swP9pdSf1?FrJ zIwwFFkjcW+mb z3x$(PyafX;KX0i+@aW!M#9fkOBW;#?@7+3Y9|}EB7?p4b@h6-C;zl0gFs*YCk2g65 z#FFAJ>`xUZSZ6pK9DtD>8|N$W%DwlAjdR7rB|hD+Y4yTfU{v0CpRD>Bg%UaT2Tqnvis|9IFeM%JUJ6x4k8gnbZICSgV!J{us9~Df?gs) zn!7vEnI|^5_i5bU3a;xoE{Gc5ZrIxCIPczVn#hyXM zu%YrYRtAa!{QUc*-6Zb{ofv>^=Ua}8t)Uqky=hr6hMn{QHjcIK7wTaq`Gda~4U!!* z=kCD7oTsjUj=0tPsLnf442o@$g9ze8cSn+;@(fVo;2nwLM~2EtV8y5VJx#SNJfCeY zD5>VWAKDD#{32_gG;+48&iRHIaGz@avtX!tkW4!*lUSsW;5^j1Kd*S!Y+heZfdlPd z+ne!WIViSCuVCW0UqW270}uv)mjEkK*#TAv@C*T*gn?fIJO%*N;!P5R5vf9E2L>3z zw1z4jac~_;FWKSmf|sBa@-I+f#e4afPMLLniZg6Gg4nP>5B}@Bv|BrUMI*c2OYLug*xVJGOhX6Rdo%iztTjx3XSkZaL zu&r*(a5RGZ*Sy6TMI9yxRJ2xm(*K27mNe#*a}c?%ig^&p9TI&M;I4phCwaw$f1fPhK)U zg-DT?h6v6?2hLKi54?TnK-pCXox3VNq!X$<{}MmNvkQ)q$&GJ33gSAa8l_QWytm3K&c?HQ0FU56?=&#`o===&e#?L z&&PSlUxWhr?>b=;%_D*^=DKhZ!H|3oD&biM!)sgS5uLud^qFSGrxM3BCQwR=el}Cv zP!rb7B>FH^Jq8D}y&EltF)h2{aPLQ*jvDviIoDE$V_2ql{5W*NW<`-SJvnpSKI#N< z7xve@3u_VrMY^O!cbndI8iMJ!({TsVrN&Fws3kZgM69mo;`y0X&lGvD9%3U-uG)Ym zF@ag(Bz6gtm^Fnd^yfwCi-pEF@3+*6C7G6kAVdv@TuU8QvPhaYA8jnm=A0Lr=n-i& zKT3^{H5Lw+8*^eCb4f36KHgY3PHvnS+nE12H9pZ;Xq6j_VjHJEL5<5A3#ZGC_SnWb z%c$|m#zHI@sIqWDY~!LQsd0H@;S#y=(b&di%c*fiW8q4<(J41#nK3Tv+7)QeeXp_b zS>En0rw4uvxqhbSDDFzC6BVJ+?V&QdHo9MwON5w+iG|wS8vzmsG2H0>6*YrEqxgN_PqTY>=KRu)7Zv-z&rfQdyMttbg&EIn zed>%@zjdX5JOEVD?=@7ujWWmEx{^RxVlfDYZF{lpB_FM*ryT?iTTCM(jjZN7W1^~$ zFNVYZ`5?xJ<3lxo5~)5q?t@At`KZ3$_4H;Ug^jtd8P6>yd>H=E{>=K*nQ$0-L^r80 zRNXx>LoCA(a_l9aPk7K39Zu%lq6`tkxsEtbkvR`eh8yH;M#SA4%Or6eVbT&dY`bVV zZg_p4(eQd}7VTDF)t}13Fv%Y!e}#ak-Cf7r2L;Z#EJW~jae0)=f?rZ?%=y`n5TGX)!Be%AzA|kf;~{6nH?z5 zE_D9Py(w79!{2m!+@k{q9gS$J~H#Y<}Zc)BieR6g*g-(#CimOqfaA4fJ`7#qssn8GHm}CI`B_}9Pc26V-Ul4 z-%Xxb!-AtpH+35Ku0&ii)SuS5_gcjRp|51k`*s4C$>;GLzHVV5rco4EA`~>xaWdPm zJ{>{x<~dNPZ><5llga&Evu}l29K}I3xhxzWbpr+ka;AHUIkOHpnZAvdbbvC=zIj%x z`Qg$d2;;DCXW|^fPi~*|L=3)40Wk@scPMv}rI;>AWwp^+&!^i{04~vF9O6uy?LjRuRh`_rkEsKUe|d6nID4er~>8f zxex(SP?osTEUu+v<8X0pj-3^+x}W-qbFDk7!2<9f5}O0Iao-1Q zjJPT`r$mWZGG;B-sB%yPbu3yN8D>UD9?k(u7S87dk1DCV8!yXUePyNI|(iC*t1{zQjdzwmgAnu zlx@q}@dg+Q2tr`8klHvIdq`b(<77QhSzvOiCNMcIB`_HXlMSqKvJty8)OJ7R>CKAI z3jXyJoDkeOZu|4y#dDu;fXX$$o7-B4_`G>V@lcNr>+6G=5aDndG@)Y|ipEY8m00xQ| zTpuW2i02|E&U(U|X6L}g06c`>)rsP)6_)oL;;b_9=!gTp-@ZgsSnR~F3%_fjil;Lj z;+kgy#m}Pt93)+b=kqMEp&XcaRNzw^*zkhv6hxoS_@en^9@kQQ; zfej+T0voF3hnF6!HR6YPd+@o(;hsb`i!h)JX64)P7Ro$QfXg$|zTx{FLxZKoA=0L;eHVTkQ@-~6PPwr1^1C`(V)MSW90!3= ztqh)b(Kqi3&|1aDfb~ml!1@)IKogcg5WlDK`~BpA^@1R;FS^2;8^*Sj*Wf9^{j2Z( zTzA(^@M(>nd0oDzw5t=|xrqdL`vwvO^X#s>DQ};_U5K&7D{wtVpG|;O4#z^uti_QO z$BN#8g7etinhg%|f$x1alyOCJ&Q#x&@-7|R>z_57(#3)n!`s+60tFYffr3l;y$tVF z&`HL=D1bF9^ldU!t%q)Xx@oYIT=AFyBYB6JFtElXhf=+KcR_!TYn1(Q zue`7L?n)ygDCkwoo`+`kT3SZz4-}-puKFM{dLEGxHm3(VVJ6+;p%MF_NMqhnFm!Z8 zdtSZofv-`lN49^s;qCXtEIfwM(5Eu5NSy+=T&dL(61d0cm1I0RcoW4xcpHp_e(5z@Dyuk4%x&p%0p*m~T%tvvSQIg4NbIkEb4nV5*o z;La;pr3YYt!{KF+HbrunR^4sT&$wVGYLR@067K1CP*2pgX#kc6VEs>fm zXi~sXfnM5$Ch0kxAAT%jBJDp1jN=!80YAb*>2jXK$P-x3i4_wIiaOrFzA#Vcv(s6S zhX`4CohKsbAxe9TTwL*niSRkF%op28ui_b-3xQ{C5D|lXR#f zC^l4jsoG%JJ`aq$ziIZ{p$US740J^l zj!L*^-^2VM)G=(+SH9OpppUwdbA|tH>D|1(5pL8kcx5|eu)tSyvA3M!qOtPieLH)vfaBVhRzN> zvr+uGKCBlz=wbAv)L+TMnM3UGJfQL1rS+!KMiPf{myV+(5K1DAi%sfLT#>^E5U2bI z>#oamW6{G8oP!@YkKbneevjV^_`S&T5TieL53D6SV7&xLOK*1=WA=Z~{j~;0?wNPl zGqu&5MtfV;dxok9;BKJ}s3I{&2Lc4w1PT%XPhvqAZ7vrBQ<$)WjxX*#n!uDW^Y
wQ15*T`fzv6Nr73uYXi9?TLEM7);IBP1a8;;x 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 b@R}i=PltaFvj5w#CucQ?Gv1SEtzrKMn3n`V literal 0 HcmV?d00001 diff --git a/BIOS-bochs-latest_2-3 b/BIOS-bochs-latest_2-3 new file mode 100644 index 0000000000000000000000000000000000000000..5fcdfa31fc22529ddde71d54b33ce58fea1d2ddc GIT binary patch literal 65536 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 P&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 0000000000000000000000000000000000000000..175606532e6961523b6b6b7f836e0a0697290ca4 GIT binary patch literal 41472 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.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 0000000000000000000000000000000000000000..80a7777a13ac572805b05dcd703f4b0c05472f10 GIT binary patch literal 800 TcmZSJVi<*^Aut*OI6?pbZio+| literal 0 HcmV?d00001 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) + } +}