From a1aee4b9b4c4f4fbfc5bd6b4ae30e5affec8d79d Mon Sep 17 00:00:00 2001 From: Guanqun Lu Date: Fri, 7 Mar 2008 11:19:58 +0800 Subject: [PATCH] initial commit Signed-off-by: Guanqun Lu --- .bochsrc | 734 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ CODING | 35 +++ GNUmakefile | 165 +++++++++++++ boot/Makefrag | 32 +++ boot/boot.S | 85 +++++++ boot/main.c | 120 +++++++++ boot/sign.pl | 23 ++ conf/env.mk | 15 ++ conf/lab.mk | 2 + grade.sh | 97 ++++++++ inc/COPYRIGHT | 229 ++++++++++++++++++ inc/assert.h | 20 ++ inc/elf.h | 65 +++++ inc/error.h | 18 ++ inc/kbdreg.h | 83 +++++++ inc/malloc.h | 7 + inc/memlayout.h | 181 ++++++++++++++ inc/mmu.h | 312 ++++++++++++++++++++++++ inc/queue.h | 219 +++++++++++++++++ inc/stab.h | 51 ++++ inc/stdarg.h | 19 ++ inc/stdio.h | 35 +++ inc/string.h | 24 ++ inc/types.h | 72 ++++++ inc/x86.h | 277 +++++++++++++++++++++ kern/COPYRIGHT | 155 ++++++++++++ kern/Makefrag | 82 +++++++ kern/console.c | 456 +++++++++++++++++++++++++++++++++++ kern/console.h | 27 +++ kern/entry.S | 104 ++++++++ kern/init.c | 95 ++++++++ kern/kernel.ld | 59 +++++ kern/monitor.c | 137 +++++++++++ kern/monitor.h | 19 ++ kern/printf.c | 37 +++ lib/printfmt.c | 301 +++++++++++++++++++++++ lib/readline.c | 38 +++ lib/string.c | 222 +++++++++++++++++ mergedep.pl | 86 +++++++ user/testpmap.c | 215 +++++++++++++++++ user/user.ld | 72 ++++++ 41 files changed, 5025 insertions(+) create mode 100644 .bochsrc create mode 100644 CODING create mode 100644 GNUmakefile 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 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/error.h create mode 100644 inc/kbdreg.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/types.h create mode 100644 inc/x86.h create mode 100644 kern/COPYRIGHT create mode 100644 kern/Makefrag create mode 100644 kern/console.c create mode 100644 kern/console.h create mode 100644 kern/entry.S create mode 100644 kern/init.c create mode 100644 kern/kernel.ld create mode 100644 kern/monitor.c create mode 100644 kern/monitor.h create mode 100644 kern/printf.c create mode 100644 lib/printfmt.c create mode 100644 lib/readline.c create mode 100644 lib/string.c create mode 100644 mergedep.pl create mode 100644 user/testpmap.c create mode 100644 user/user.ld diff --git a/.bochsrc b/.bochsrc new file mode 100644 index 0000000..e8b184e --- /dev/null +++ b/.bochsrc @@ -0,0 +1,734 @@ +# 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=mybios.bin, address=0xfff80000 # 512k at memory top +#romimage: file=mybios.bin # calculate start address from image size + +#======================================================================= +# CPU: +# This defines cpu-related parameters inside Bochs: +# +# COUNT: +# Set the number of processors when Bochs is compiled for SMP emulation. +# Bochs currently supports up to 8 processors. If Bochs is compiled +# without SMP support, it won't accept values different from 1. +# +# IPS: +# Emulated Instructions Per Second. This is the number of IPS that bochs +# is capable of running on your machine. You can recompile Bochs with +# --enable-show-ips option enabled, to find your workstation's capability. +# Measured IPS value will then be logged into your log file or status bar +# (if supported by the gui). +# +# IPS is used to calibrate many time-dependent events within the bochs +# simulation. For example, changing IPS affects the frequency of VGA +# updates, the duration of time before a key starts to autorepeat, and +# the measurement of BogoMips and other benchmarks. +# +# Examples: +# Machine Mips +# ________________________________________________________________ +# 2.1Ghz Athlon XP with Linux 2.6/g++ 3.4 12 to 15 Mips +# 1.6Ghz Intel P4 with Win2000/g++ 3.3 5 to 7 Mips +# 650Mhz Athlon K-7 with Linux 2.4.4/egcs-2.91.66 2 to 2.5 Mips +# 400Mhz Pentium II with Linux 2.0.36/egcs-1.0.3 1 to 1.8 Mips +#======================================================================= +cpu: count=1, ips=10000000 + +#======================================================================= +# MEGS +# Set the number of Megabytes of physical memory you want to emulate. +# The default is 32MB, most OS's won't need more than that. +# The maximum amount of memory supported is 2048Mb. +#======================================================================= +#megs: 256 +#megs: 128 +#megs: 64 +megs: 32 +#megs: 16 +#megs: 8 + +#======================================================================= +# OPTROMIMAGE[1-4]: +# You may now load up to 4 optional ROM images. Be sure to use a +# read-only area, typically between C8000 and EFFFF. These optional +# ROM images should not overwrite the rombios (located at +# F0000-FFFFF) and the videobios (located at C0000-C7FFF). +# Those ROM images will be initialized by the bios if they contain +# the right signature (0x55AA) and a valid checksum. +# It can also be a convenient way to upload some arbitrary code/data +# in the simulation, that can be retrieved by the boot loader +#======================================================================= +#optromimage1: file=optionalrom.bin, address=0xd0000 +#optromimage2: file=optionalrom.bin, address=0xd1000 +#optromimage3: file=optionalrom.bin, address=0xd2000 +#optromimage4: file=optionalrom.bin, address=0xd3000 + +#optramimage1: file=/path/file1.img, address=0x0010000 +#optramimage2: file=/path/file2.img, address=0x0020000 +#optramimage3: file=/path/file3.img, address=0x0030000 +#optramimage4: file=/path/file4.img, address=0x0040000 + +#======================================================================= +# VGAROMIMAGE +# You now need to load a VGA ROM BIOS into C0000. +#======================================================================= +#vgaromimage: file=bios/VGABIOS-elpin-2.40 +vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest +#vgaromimage: file=bios/VGABIOS-lgpl-latest-cirrus + +#======================================================================= +# VGA: +# Here you can specify the display extension to be used. With the value +# 'none' you can use standard VGA with no extension. Other supported +# values are 'vbe' for Bochs VBE and 'cirrus' for Cirrus SVGA support. +#======================================================================= +#vga: extension=cirrus +#vga: extension=vbe +vga: extension=none + +#======================================================================= +# FLOPPYA: +# Point this to pathname of floppy image file or device +# This should be of a bootable floppy(image/device) if you're +# booting from 'a' (or 'floppy'). +# +# You can set the initial status of the media to 'ejected' or 'inserted'. +# floppya: 2_88=path, status=ejected (2.88M 3.5" floppy) +# floppya: 1_44=path, status=inserted (1.44M 3.5" floppy) +# floppya: 1_2=path, status=ejected (1.2M 5.25" floppy) +# floppya: 720k=path, status=inserted (720K 3.5" floppy) +# floppya: 360k=path, status=inserted (360K 5.25" floppy) +# floppya: 320k=path, status=inserted (320K 5.25" floppy) +# floppya: 180k=path, status=inserted (180K 5.25" floppy) +# floppya: 160k=path, status=inserted (160K 5.25" floppy) +# floppya: image=path, status=inserted (guess type from image size) +# +# The path should be the name of a disk image file. On Unix, you can use a raw +# device name such as /dev/fd0 on Linux. On win32 platforms, use drive letters +# such as a: or b: as the path. The parameter 'image' works with image files +# only. In that case the size must match one of the supported types. +#======================================================================= +#floppya: 1_44=/dev/fd0, status=inserted +#floppya: image=../1.44, status=inserted +#floppya: 1_44=/dev/fd0H1440, status=inserted +#floppya: 1_2=../1_2, status=inserted +#floppya: 1_44=a:, status=inserted +#floppya: 1_44=a.img, status=inserted +#floppya: 1_44=/dev/rfd0a, status=inserted + +#======================================================================= +# FLOPPYB: +# See FLOPPYA above for syntax +#======================================================================= +#floppyb: 1_44=b:, status=inserted +#floppyb: 1_44=b.img, status=inserted + +#======================================================================= +# ATA0, ATA1, ATA2, ATA3 +# ATA controller for hard disks and cdroms +# +# ata[0-3]: enabled=[0|1], ioaddr1=addr, ioaddr2=addr, irq=number +# +# These options enables up to 4 ata channels. For each channel +# the two base io addresses and the irq must be specified. +# +# ata0 and ata1 are enabled by default with the values shown below +# +# Examples: +# ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 +# ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 +# ata2: enabled=1, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11 +# ata3: enabled=1, ioaddr1=0x168, ioaddr2=0x360, irq=9 +#======================================================================= +ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 +#ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 +#ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11 +#ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9 + +#======================================================================= +# ATA[0-3]-MASTER, ATA[0-3]-SLAVE +# +# This defines the type and characteristics of all attached ata devices: +# type= type of attached device [disk|cdrom] +# mode= only valid for disks [flat|concat|external|dll|sparse|vmware3] +# mode= only valid for disks [undoable|growing|volatile] +# path= path of the image +# cylinders= only valid for disks +# heads= only valid for disks +# spt= only valid for disks +# status= only valid for cdroms [inserted|ejected] +# biosdetect= type of biosdetection [none|auto], only for disks on ata0 [cmos] +# translation=type of translation of the bios, only for disks [none|lba|large|rechs|auto] +# model= string returned by identify device command +# journal= optional filename of the redolog for undoable and volatile disks +# +# Point this at a hard disk image file, cdrom iso file, or physical cdrom +# device. To create a hard disk image, try running bximage. It will help you +# choose the size and then suggest a line that works with it. +# +# In UNIX it may be possible to use a raw device as a Bochs hard disk, +# but WE DON'T RECOMMEND IT. In Windows there is no easy way. +# +# In windows, the drive letter + colon notation should be used for cdroms. +# Depending on versions of windows and drivers, you may only be able to +# access the "first" cdrom in the system. On MacOSX, use path="drive" +# to access the physical drive. +# +# The path is always mandatory. For flat hard disk images created with +# bximage geometry autodetection can be used (cylinders=0 -> cylinders are +# calculated using heads=16 and spt=63). For other hard disk images and modes +# the cylinders, heads, and spt are mandatory. +# +# Default values are: +# mode=flat, biosdetect=auto, translation=auto, model="Generic 1234" +# +# The biosdetect option has currently no effect on the bios +# +# Examples: +# ata0-master: type=disk, mode=flat, path=10M.sample, cylinders=306, heads=4, spt=17 +# ata0-slave: type=disk, mode=flat, path=20M.sample, cylinders=615, heads=4, spt=17 +# ata1-master: type=disk, mode=flat, path=30M.sample, cylinders=615, heads=6, spt=17 +# ata1-slave: type=disk, mode=flat, path=46M.sample, cylinders=940, heads=6, spt=17 +# ata2-master: type=disk, mode=flat, path=62M.sample, cylinders=940, heads=8, spt=17 +# ata2-slave: type=disk, mode=flat, path=112M.sample, cylinders=900, heads=15, spt=17 +# ata3-master: type=disk, mode=flat, path=483M.sample, cylinders=1024, heads=15, spt=63 +# ata3-slave: type=cdrom, path=iso.sample, status=inserted +#======================================================================= +ata0-master: type=disk, mode=flat, path="./obj/kern/bochs.img", cylinders=100, heads=10, spt=10 + +#======================================================================= +# BOOT: +# This defines the boot sequence. Now you can specify up to 3 boot drives. +# You can either boot from 'floppy', 'disk' or 'cdrom' +# legacy 'a' and 'c' are also supported +# Examples: +# boot: floppy +# boot: disk +# boot: cdrom +# boot: c +# boot: a +# boot: cdrom, floppy, disk +#======================================================================= +#boot: floppy +boot: disk + +#======================================================================= +# CLOCK: +# This defines the parameters of the clock inside Bochs: +# +# SYNC: +# TO BE COMPLETED (see Greg explanation in feature request #536329) +# +# TIME0: +# Specifies the start (boot) time of the virtual machine. Use a time +# value as returned by the time(2) system call. If no time0 value is +# set or if time0 equal to 1 (special case) or if time0 equal 'local', +# the simulation will be started at the current local host time. +# If time0 equal to 2 (special case) or if time0 equal 'utc', +# the simulation will be started at the current utc time. +# +# Syntax: +# clock: sync=[none|slowdown|realtime|both], time0=[timeValue|local|utc] +# +# Example: +# clock: sync=none, time0=local # Now (localtime) +# clock: sync=slowdown, time0=315529200 # Tue Jan 1 00:00:00 1980 +# clock: sync=none, time0=631148400 # Mon Jan 1 00:00:00 1990 +# clock: sync=realtime, time0=938581955 # Wed Sep 29 07:12:35 1999 +# clock: sync=realtime, time0=946681200 # Sat Jan 1 00:00:00 2000 +# clock: sync=none, time0=1 # Now (localtime) +# clock: sync=none, time0=utc # Now (utc/gmt) +# +# Default value are sync=none, time0=local +#======================================================================= +#clock: sync=none, time0=local +clock: sync=realtime, time0=local + + +#======================================================================= +# FLOPPY_BOOTSIG_CHECK: disabled=[0|1] +# Enables or disables the 0xaa55 signature check on boot floppies +# Defaults to disabled=0 +# Examples: +# floppy_bootsig_check: disabled=0 +# floppy_bootsig_check: disabled=1 +#======================================================================= +#floppy_bootsig_check: disabled=1 +floppy_bootsig_check: disabled=0 + +#======================================================================= +# LOG: +# Give the path of the log file you'd like Bochs debug and misc. verbiage +# to be written to. If you don't use this option or set the filename to +# '-' the output is written to the console. If you really don't want it, +# make it "/dev/null" (Unix) or "nul" (win32). :^( +# +# Examples: +# log: ./bochs.out +# log: /dev/tty +#======================================================================= +#log: /dev/null +log: bochs.log + +#======================================================================= +# LOGPREFIX: +# This handles the format of the string prepended to each log line. +# You may use those special tokens : +# %t : 11 decimal digits timer tick +# %i : 8 hexadecimal digits of cpu current eip (ignored in SMP configuration) +# %e : 1 character event type ('i'nfo, 'd'ebug, 'p'anic, 'e'rror) +# %d : 5 characters string of the device, between brackets +# +# Default : %t%e%d +# Examples: +# logprefix: %t-%e-@%i-%d +# logprefix: %i%e%d +#======================================================================= +#logprefix: %t%e%d + +#======================================================================= +# LOG CONTROLS +# +# Bochs now has four severity levels for event logging. +# panic: cannot proceed. If you choose to continue after a panic, +# don't be surprised if you get strange behavior or crashes. +# error: something went wrong, but it is probably safe to continue the +# simulation. +# info: interesting or useful messages. +# debug: messages useful only when debugging the code. This may +# spit out thousands per second. +# +# For events of each level, you can choose to crash, report, or ignore. +# TODO: allow choice based on the facility: e.g. crash on panics from +# everything except the cdrom, and only report those. +# +# If you are experiencing many panics, it can be helpful to change +# the panic action to report instead of fatal. However, be aware +# that anything executed after a panic is uncharted territory and can +# cause bochs to become unstable. The panic is a "graceful exit," so +# if you disable it you may get a spectacular disaster instead. +#======================================================================= +panic: action=ask +error: action=report +info: action=ignore +debug: action=ignore +#pass: action=fatal + +#======================================================================= +# DEBUGGER_LOG: +# Give the path of the log file you'd like Bochs to log debugger output. +# If you really don't want it, make it /dev/null or '-'. :^( +# +# Examples: +# debugger_log: ./debugger.out +#======================================================================= +#debugger_log: /dev/null +#debugger_log: debugger.out +debugger_log: - + +#======================================================================= +# COM1, COM2, COM3, COM4: +# This defines a serial port (UART type 16550A). In the 'term' you can specify +# a device to use as com1. This can be a real serial line, or a pty. To use +# a pty (under X/Unix), create two windows (xterms, usually). One of them will +# run bochs, and the other will act as com1. Find out the tty the com1 +# window using the `tty' command, and use that as the `dev' parameter. +# Then do `sleep 1000000' in the com1 window to keep the shell from +# messing with things, and run bochs in the other window. Serial I/O to +# com1 (port 0x3f8) will all go to the other window. +# Other serial modes are 'null' (no input/output), 'file' (output to a file +# specified as the 'dev' parameter), 'raw' (use the real serial port - under +# construction for win32), 'mouse' (standard serial mouse - requires +# mouse option setting 'type=serial' or 'type=serial_wheel') and 'socket' +# (connect a networking socket). +# +# Examples: +# com1: enabled=1, mode=null +# com1: enabled=1, mode=mouse +# com2: enabled=1, mode=file, dev=serial.out +# com3: enabled=1, mode=raw, dev=com1 +# com3: enabled=1, mode=socket, dev=localhost:8888 +#======================================================================= +#com1: enabled=1, mode=term, dev=/dev/ttyp9 + + +#======================================================================= +# PARPORT1, PARPORT2: +# This defines a parallel (printer) port. When turned on and an output file is +# defined the emulated printer port sends characters printed by the guest OS +# into the output file. On some platforms a device filename can be used to +# send the data to the real parallel port (e.g. "/dev/lp0" on Linux, "lpt1" on +# win32 platforms). +# +# Examples: +# parport1: enabled=1, file="parport.out" +# parport2: enabled=1, file="/dev/lp0" +# parport1: enabled=0 +#======================================================================= +parport1: enabled=1, file="/dev/stdout" + +#======================================================================= +# SB16: +# This defines the SB16 sound emulation. It can have several of the +# following properties. +# All properties are in the format sb16: property=value +# midi: The filename is where the midi data is sent. This can be a +# device or just a file if you want to record the midi data. +# midimode: +# 0=no data +# 1=output to device (system dependent. midi denotes the device driver) +# 2=SMF file output, including headers +# 3=output the midi data stream to the file (no midi headers and no +# delta times, just command and data bytes) +# wave: This is the device/file where wave output is stored +# wavemode: +# 0=no data +# 1=output to device (system dependent. wave denotes the device driver) +# 2=VOC file output, incl. headers +# 3=output the raw wave stream to the file +# log: The file to write the sb16 emulator messages to. +# loglevel: +# 0=no log +# 1=resource changes, midi program and bank changes +# 2=severe errors +# 3=all errors +# 4=all errors plus all port accesses +# 5=all errors and port accesses plus a lot of extra info +# dmatimer: +# microseconds per second for a DMA cycle. Make it smaller to fix +# non-continuous sound. 750000 is usually a good value. This needs a +# reasonably correct setting for the IPS parameter of the CPU option. +# +# For an example look at the next line: +#======================================================================= + +#sb16: midimode=1, midi=/dev/midi00, wavemode=1, wave=/dev/dsp, loglevel=2, log=sb16.log, dmatimer=600000 + +#======================================================================= +# VGA_UPDATE_INTERVAL: +# Video memory is scanned for updates and screen updated every so many +# virtual seconds. The default is 40000, about 25Hz. Keep in mind that +# you must tweak the 'cpu: ips=N' directive to be as close to the number +# of emulated instructions-per-second your workstation can do, for this +# to be accurate. +# +# Examples: +# vga_update_interval: 250000 +#======================================================================= +vga_update_interval: 300000 + +# using for Winstone '98 tests +#vga_update_interval: 100000 + +#======================================================================= +# KEYBOARD_SERIAL_DELAY: +# Approximate time in microseconds that it takes one character to +# be transfered from the keyboard to controller over the serial path. +# Examples: +# keyboard_serial_delay: 200 +#======================================================================= +keyboard_serial_delay: 250 + +#======================================================================= +# KEYBOARD_PASTE_DELAY: +# Approximate time in microseconds between attempts to paste +# characters to the keyboard controller. This leaves time for the +# guest os to deal with the flow of characters. The ideal setting +# depends on how your operating system processes characters. The +# default of 100000 usec (.1 seconds) was chosen because it works +# consistently in Windows. +# +# If your OS is losing characters during a paste, increase the paste +# delay until it stops losing characters. +# +# Examples: +# keyboard_paste_delay: 100000 +#======================================================================= +keyboard_paste_delay: 100000 + +#======================================================================= +# MOUSE: +# This option prevents Bochs from creating mouse "events" unless a mouse +# is enabled. The hardware emulation itself is not disabled by this. +# You can turn the mouse on by setting enabled to 1, or turn it off by +# setting enabled to 0. Unless you have a particular reason for enabling +# the mouse by default, it is recommended that you leave it off. +# You can also toggle the mouse usage at runtime (control key + middle +# mouse button on X11, SDL, wxWidgets and Win32). +# With the mouse type option you can select the type of mouse to emulate. +# The default value is 'ps2'. The other choices are 'imps2' (wheel mouse +# on PS/2), 'serial', 'serial_wheel' (one com port requires setting +# 'mode=mouse') and 'usb' (3-button mouse - one of the USB ports must be +# connected with the 'mouse' device - requires PCI and USB support). +# +# Examples: +# mouse: enabled=1 +# mouse: enabled=1, type=imps2 +# mouse: enabled=1, type=serial +# mouse: enabled=0 +#======================================================================= +mouse: enabled=0 + +#======================================================================= +# private_colormap: Request that the GUI create and use it's own +# non-shared colormap. This colormap will be used +# when in the bochs window. If not enabled, a +# shared colormap scheme may be used. Not implemented +# on all GUI's. +# +# Examples: +# private_colormap: enabled=1 +# private_colormap: enabled=0 +#======================================================================= +private_colormap: enabled=0 + +#======================================================================= +# fullscreen: ONLY IMPLEMENTED ON AMIGA +# Request that Bochs occupy the entire screen instead of a +# window. +# +# Examples: +# fullscreen: enabled=0 +# fullscreen: enabled=1 +#======================================================================= +#fullscreen: enabled=0 +#screenmode: name="sample" + +#======================================================================= +# ne2k: NE2000 compatible ethernet adapter +# +# Examples: +# ne2k: ioaddr=IOADDR, irq=IRQ, mac=MACADDR, ethmod=MODULE, ethdev=DEVICE, script=SCRIPT +# +# ioaddr, irq: You probably won't need to change ioaddr and irq, unless there +# are IRQ conflicts. +# +# mac: The MAC address MUST NOT match the address of any machine on the net. +# Also, the first byte must be an even number (bit 0 set means a multicast +# address), and you cannot use ff:ff:ff:ff:ff:ff because that's the broadcast +# address. For the ethertap module, you must use fe:fd:00:00:00:01. There may +# be other restrictions too. To be safe, just use the b0:c4... address. +# +# ethdev: The ethdev value is the name of the network interface on your host +# platform. On UNIX machines, you can get the name by running ifconfig. On +# Windows machines, you must run niclist to get the name of the ethdev. +# Niclist source code is in misc/niclist.c and it is included in Windows +# binary releases. +# +# script: The script value is optional, and is the name of a script that +# is executed after bochs initialize the network interface. You can use +# this script to configure this network interface, or enable masquerading. +# This is mainly useful for the tun/tap devices that only exist during +# Bochs execution. The network interface name is supplied to the script +# as first parameter +# +# If you don't want to make connections to any physical networks, +# you can use the following 'ethmod's to simulate a virtual network. +# null: All packets are discarded, but logged to a few files. +# arpback: ARP is simulated. Disabled by default. +# vde: Virtual Distributed Ethernet +# vnet: ARP, ICMP-echo(ping), DHCP and read/write TFTP are simulated. +# The virtual host uses 192.168.10.1. +# DHCP assigns 192.168.10.2 to the guest. +# TFTP uses the ethdev value for the root directory and doesn't +# overwrite files. +# +#======================================================================= +# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=fbsd, ethdev=en0 #macosx +# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=fbsd, ethdev=xl0 +# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:00, ethmod=linux, ethdev=eth0 +# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=win32, ethdev=MYCARD +# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tap, ethdev=tap0 +# ne2k: ioaddr=0x240, irq=9, mac=fe:fd:00:00:00:01, ethmod=tuntap, ethdev=/dev/net/tun0, script=./tunconfig +# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=null, ethdev=eth0 +# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=vde, ethdev="/tmp/vde.ctl" +# ne2k: ioaddr=0x240, irq=9, mac=b0:c4:20:00:00:01, ethmod=vnet, ethdev="c:/temp" + +#======================================================================= +# KEYBOARD_MAPPING: +# This enables a remap of a physical localized keyboard to a +# virtualized us keyboard, as the PC architecture expects. +# If enabled, the keymap file must be specified. +# +# Examples: +# keyboard_mapping: enabled=1, map=gui/keymaps/x11-pc-de.map +#======================================================================= +keyboard_mapping: enabled=0, map= + +#======================================================================= +# KEYBOARD_TYPE: +# Type of keyboard return by a "identify keyboard" command to the +# keyboard controler. It must be one of "xt", "at" or "mf". +# Defaults to "mf". It should be ok for almost everybody. A known +# exception is french macs, that do have a "at"-like keyboard. +# +# Examples: +# keyboard_type: mf +#======================================================================= +#keyboard_type: mf + +#======================================================================= +# USER_SHORTCUT: +# This defines the keyboard shortcut to be sent when you press the "user" +# button in the headerbar. The shortcut string is a combination of maximum +# 3 key names (listed below) separated with a '-' character. The old-style +# syntax (without the '-') still works for the key combinations supported +# in Bochs 2.2.1. +# Valid key names: +# "alt", "bksl", "bksp", "ctrl", "del", "down", "end", "enter", "esc", +# "f1", ... "f12", "home", "ins", "left", "menu", "minus", "pgdwn", "pgup", +# "plus", "right", "shift", "space", "tab", "up", and "win". +# +# Example: +# user_shortcut: keys=ctrl-alt-del +#======================================================================= +#user_shortcut: keys=ctrl-alt-del + +#======================================================================= +# I440FXSUPPORT: +# This option controls the presence of the i440FX PCI chipset. You can +# also specify the devices connected to PCI slots. Up to 5 slots are +# available now. These devices are currently supported: ne2k, pcivga, +# pcidev and pcipnic. If Bochs is compiled with Cirrus SVGA support +# you'll have the additional choice 'cirrus'. +# +# Example: +# i440fxsupport: enabled=1, slot1=pcivga, slot2=ne2k +#======================================================================= +#i440fxsupport: enabled=1 + +#======================================================================= +# USB1: +# This option controls the presence of the USB root hub which is a part +# of the i440FX PCI chipset. With the portX option you can connect devices +# to the hub (currently supported: 'mouse' and 'keypad'). If you connect +# the mouse to one of the ports and use the mouse option 'type=usb' you'll +# have a 3-button USB mouse. +# +# Example: +# usb1: enabled=1, port1=mouse, port2=keypad +#======================================================================= +#usb1: enabled=1 + +#======================================================================= +# CMOSIMAGE: +# This defines image file that can be loaded into the CMOS RAM at startup. +# The rtc_init parameter controls whether initialize the RTC with values stored +# in the image. By default the time0 argument given to the clock option is used. +# With 'rtc_init=image' the image is the source for the initial time. +# +# Example: +# cmosimage: file=cmos.img, rtc_init=image +#======================================================================= +#cmosimage: file=cmos.img, rtc_init=time0 + +#======================================================================= +# other stuff +#======================================================================= +#magic_break: enabled=1 +#load32bitOSImage: os=nullkernel, path=../kernel.img, iolog=../vga_io.log +#load32bitOSImage: os=linux, path=../linux.img, iolog=../vga_io.log, initrd=../initrd.img +#text_snapshot_check: enable + +#------------------------- +# PCI host device mapping +#------------------------- +#pcidev: vendor=0x1234, device=0x5678 + +#======================================================================= +# GDBSTUB: +# Enable GDB stub. See user documentation for details. +# Default value is enabled=0. +#======================================================================= +#gdbstub: enabled=0, port=1234, text_base=0, data_base=0, bss_base=0 + +#======================================================================= +# IPS: +# The IPS directive is DEPRECATED. Use the parameter IPS of the CPU +# directive instead. +#======================================================================= +#ips: 10000000 + +#======================================================================= +# for Macintosh, use the style of pathnames in the following +# examples. +# +# vgaromimage: :bios:VGABIOS-elpin-2.40 +# romimage: file=:bios:BIOS-bochs-latest, address=0xf0000 +# floppya: 1_44=[fd:], status=inserted +#======================================================================= diff --git a/CODING b/CODING new file mode 100644 index 0000000..55d11d7 --- /dev/null +++ b/CODING @@ -0,0 +1,35 @@ +JOS CODING STANDARDS + +It's easier on everyone if all authors working on a shared +code base are consistent in the way they write their programs. +We have the following conventions in our code: + +* No space after the name of a function in a call + For example, printf("hello") not printf ("hello"). + +* One space after keywords "if", "for", "while", "switch". + For example, if (x) not if(x). + +* Space before braces. + For example, if (x) { not if (x){. + +* Function names are all lower-case separated by underscores. + +* Beginning-of-line indentation via tabs, not spaces. + +* Preprocessor macros are always UPPERCASE. + There are a few grandfathered exceptions: assert, panic, + static_assert, offsetof. + +* Pointer types have spaces: (uint16_t *) not (uint16_t*). + +* Multi-word names are lower_case_with_underscores. + +* Comments in imported code are usually C /* ... */ comments. + Comments in new code are C++ style //. + +* In a function definition, the function name starts a new line. + Then you can grep -n '^foo' */*.c to find the definition of foo. + +* Functions that take no arguments are declared f(void) not f(). + diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 0000000..0a745e5 --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,165 @@ +# +# This makefile system follows the structuring conventions +# recommended by Peter Miller in his excellent paper: +# +# Recursive Make Considered Harmful +# http://aegis.sourceforge.net/auug97.pdf +# +OBJDIR := obj + +ifdef LAB +SETTINGLAB := true +else +-include conf/lab.mk +endif + +-include conf/env.mk + +ifndef SOL +SOL := 0 +endif +ifndef LABADJUST +LABADJUST := 0 +endif + +ifndef LABSETUP +LABSETUP := ./ +endif + + +TOP = . + +# Cross-compiler jos toolchain +# +# This Makefile will automatically use the cross-compiler toolchain +# installed as 'i386-jos-elf-*', if one exists. If the host tools ('gcc', +# 'objdump', and so forth) compile for a 32-bit x86 ELF target, that will +# be detected as well. If you have the right compiler toolchain installed +# using a different name, set GCCPREFIX explicitly in conf/env.mk + +# try to infer the correct GCCPREFIX +ifndef GCCPREFIX +GCCPREFIX := $(shell if i386-jos-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; \ + then echo 'i386-jos-elf-'; \ + elif objdump -i 2>&1 | grep 'elf32-i386' >/dev/null 2>&1; \ + then echo ''; \ + else echo "***" 1>&2; \ + echo "*** Error: Couldn't find an i386-*-elf version of GCC/binutils." 1>&2; \ + echo "*** Is the directory with i386-jos-elf-gcc in your PATH?" 1>&2; \ + echo "*** If your i386-*-elf toolchain is installed with a command" 1>&2; \ + echo "*** prefix other than 'i386-jos-elf-', set your GCCPREFIX" 1>&2; \ + echo "*** environment variable to that prefix and run 'make' again." 1>&2; \ + echo "*** To turn off this error, run 'gmake GCCPREFIX= ...'." 1>&2; \ + echo "***" 1>&2; exit 1; fi) +endif + +CC := $(GCCPREFIX)gcc -pipe +AS := $(GCCPREFIX)as +AR := $(GCCPREFIX)ar +LD := $(GCCPREFIX)ld +OBJCOPY := $(GCCPREFIX)objcopy +OBJDUMP := $(GCCPREFIX)objdump +NM := $(GCCPREFIX)nm + +# Native commands +NCC := gcc $(CC_VER) -pipe +TAR := gtar +PERL := perl + +# Compiler flags +# -fno-builtin is required to avoid refs to undefined functions in the kernel. +# Only optimize to -O1 to discourage inlining, which complicates backtraces. +CFLAGS := $(CFLAGS) $(DEFS) $(LABDEFS) -O1 -fno-builtin -I$(TOP) -MD +CFLAGS += -Wall -Wno-format -Wno-unused -Werror -gstabs -m32 + +# Add -fno-stack-protector if the option exists. +CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector) + +# Common linker flags +LDFLAGS := -m elf_i386 + +# Linker flags for JOS user programs +ULDFLAGS := -T user/user.ld + +GCC_LIB := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name) + +# Lists that the */Makefrag makefile fragments will add to +OBJDIRS := + +# Make sure that 'all' is the first target +all: + +# Eliminate default suffix rules +.SUFFIXES: + +# Delete target files if there is an error (or make is interrupted) +.DELETE_ON_ERROR: + +# make it so that no intermediate .o files are ever deleted +.PRECIOUS: %.o $(OBJDIR)/boot/%.o $(OBJDIR)/kern/%.o \ + $(OBJDIR)/lib/%.o $(OBJDIR)/fs/%.o $(OBJDIR)/user/%.o + +KERN_CFLAGS := $(CFLAGS) -DJOS_KERNEL -gstabs +USER_CFLAGS := $(CFLAGS) -DJOS_USER -gstabs + + + + +# Include Makefrags for subdirectories +include boot/Makefrag +include kern/Makefrag + + +IMAGES = $(OBJDIR)/kern/bochs.img + +bochs: $(IMAGES) + bochs 'display_library: nogui' + +# For deleting the build +clean: + rm -rf $(OBJDIR) + +realclean: clean + rm -rf lab$(LAB).tar.gz bochs.out bochs.log + +distclean: realclean + rm -rf conf/gcc.mk + +grade: $(LABSETUP)grade.sh + $(V)$(MAKE) clean >/dev/null 2>/dev/null + $(MAKE) all + sh $(LABSETUP)grade.sh + +handin: tarball + @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/boot/Makefrag b/boot/Makefrag new file mode 100644 index 0000000..c51290b --- /dev/null +++ b/boot/Makefrag @@ -0,0 +1,32 @@ +# +# Makefile fragment for the JOS kernel. +# This is NOT a complete makefile; +# you must run GNU make in the top-level directory +# where the GNUmakefile is located. +# + +OBJDIRS += boot + +BOOT_OBJS := $(OBJDIR)/boot/boot.o $(OBJDIR)/boot/main.o + +$(OBJDIR)/boot/%.o: boot/%.c + @echo + cc -Os $< + @mkdir -p $(@D) + $(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $@ $< + +$(OBJDIR)/boot/%.o: boot/%.S + @echo + as $< + @mkdir -p $(@D) + $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $< + +$(OBJDIR)/boot/main.o: boot/main.c + @echo + cc -Os $< + $(V)$(CC) -nostdinc $(KERN_CFLAGS) -Os -c -o $(OBJDIR)/boot/main.o boot/main.c + +$(OBJDIR)/boot/boot: $(BOOT_OBJS) + @echo + ld boot/boot + $(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 -o $@.out $^ + $(V)$(OBJDUMP) -S $@.out >$@.asm + $(V)$(OBJCOPY) -S -O binary $@.out $@ + $(V)perl boot/sign.pl $(OBJDIR)/boot/boot + diff --git a/boot/boot.S b/boot/boot.S new file mode 100644 index 0000000..7a91ab1 --- /dev/null +++ b/boot/boot.S @@ -0,0 +1,85 @@ +#include + +# Start the CPU: switch to 32-bit protected mode, jump into C. +# The BIOS loads this code from the first sector of the hard disk into +# memory at physical address 0x7c00 and starts executing in real mode +# with %cs=0 %ip=7c00. + +.set PROT_MODE_CSEG, 0x8 # kernel code segment selector +.set PROT_MODE_DSEG, 0x10 # kernel data segment selector +.set CR0_PE_ON, 0x1 # protected mode enable flag + +.globl start +start: + .code16 # Assemble for 16-bit 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 + + # Enable A20: + # For backwards compatibility with the earliest PCs, physical + # address line 20 is tied low, so that addresses higher than + # 1MB wrap around to zero by default. This code undoes this. +seta20.1: + inb $0x64,%al # Wait for not busy + testb $0x2,%al + jnz seta20.1 + + movb $0xd1,%al # 0xd1 -> port 0x64 + outb %al,$0x64 + +seta20.2: + inb $0x64,%al # Wait for not busy + testb $0x2,%al + jnz seta20.2 + + movb $0xdf,%al # 0xdf -> port 0x60 + outb %al,$0x60 + + # Switch from real to protected mode, using a bootstrap GDT + # and segment translation that makes virtual addresses + # identical to their physical addresses, so that the + # effective memory map does not change during the switch. + lgdt gdtdesc + movl %cr0, %eax + orl $CR0_PE_ON, %eax + movl %eax, %cr0 + + # Jump to next instruction, but in 32-bit code segment. + # Switches processor into 32-bit mode. + ljmp $PROT_MODE_CSEG, $protcseg + + .code32 # Assemble for 32-bit mode +protcseg: + # 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 + + # Set up the stack pointer and call into C. + movl $start, %esp + call bootmain + + # If bootmain returns (it shouldn't), loop. +spin: + jmp spin + +# Bootstrap GDT +.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..abdee07 --- /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 bootmain() + * + * * bootmain() in this file takes over, reads in the kernel and jumps to it. + **********************************************************************/ + +#define SECTSIZE 512 +#define ELFHDR ((struct Elf *) 0x10000) // scratch space + +void readsect(void*, uint32_t); +void readseg(uint32_t, uint32_t, uint32_t); + +void +bootmain(void) +{ + struct Proghdr *ph, *eph; + + // read 1st page off disk + readseg((uint32_t) ELFHDR, SECTSIZE*8, 0); + + // is this a valid ELF? + if (ELFHDR->e_magic != ELF_MAGIC) + goto bad; + + // load each program segment (ignores ph flags) + ph = (struct Proghdr *) ((uint8_t *) ELFHDR + ELFHDR->e_phoff); + eph = ph + ELFHDR->e_phnum; + for (; ph < eph; ph++) + readseg(ph->p_va, ph->p_memsz, ph->p_offset); + + // call the entry point from the ELF header + // note: does not return! + ((void (*)(void)) (ELFHDR->e_entry & 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_t va, uint32_t count, uint32_t offset) +{ + uint32_t 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_t*) va, offset); + va += SECTSIZE; + offset++; + } +} + +void +waitdisk(void) +{ + // wait for disk reaady + while ((inb(0x1F7) & 0xC0) != 0x40) + /* do nothing */; +} + +void +readsect(void *dst, uint32_t offset) +{ + // wait for disk to be ready + waitdisk(); + + outb(0x1F2, 1); // count = 1 + outb(0x1F3, offset); + outb(0x1F4, offset >> 8); + outb(0x1F5, offset >> 16); + outb(0x1F6, (offset >> 24) | 0xE0); + outb(0x1F7, 0x20); // cmd 0x20 - read sectors + + // wait for disk to be ready + waitdisk(); + + // read a sector + insl(0x1F0, dst, SECTSIZE/4); +} + diff --git a/boot/sign.pl b/boot/sign.pl new file mode 100644 index 0000000..0bf46cb --- /dev/null +++ b/boot/sign.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl + +open(BB, $ARGV[0]) || die "open $ARGV[0]: $!"; + +binmode BB; +my $buf; +read(BB, $buf, 1000); +$n = length($buf); + +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(BB, ">$ARGV[0]") || die "open >$ARGV[0]: $!"; +binmode BB; +print BB $buf; +close BB; diff --git a/conf/env.mk b/conf/env.mk new file mode 100644 index 0000000..c7cc913 --- /dev/null +++ b/conf/env.mk @@ -0,0 +1,15 @@ +# 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 = @ + +# 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..554a312 --- /dev/null +++ b/conf/lab.mk @@ -0,0 +1,2 @@ +LAB=1 +PACKAGEDATE=Thu Sep 6 21:21:33 EDT 2007 diff --git a/grade.sh b/grade.sh new file mode 100644 index 0000000..aa12f7a --- /dev/null +++ b/grade.sh @@ -0,0 +1,97 @@ +#!/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)" +} + + + +gmake +runbochs + +score=0 + + echo_n "Printf: " + if grep "6828 decimal is 15254 octal!" bochs.out >/dev/null + then + score=`expr 20 + $score` + echo OK $time + else + echo WRONG $time + fi + + echo_n "Backtrace: " + args=`grep "ebp f01.* eip f0100.* args" bochs.out | awk '{ print $6 }'` + cnt=`echo $args | grep '^00000000 00000000 00000001 00000002 00000003 00000004 00000005' | wc -w` + if [ $cnt -eq 8 ] + then + score=`expr 15 + $score` + echo_n "Count OK" + else + echo_n "Count WRONG" + fi + + cnt=`grep "ebp f01.* eip f0100.* args" bochs.out | awk 'BEGIN { FS = ORS = " " } +{ print $6 } +END { printf("\n") }' | grep '^00000000 00000000 00000001 00000002 00000003 00000004 00000005' | wc -w` + if [ $cnt -eq 8 ]; then + score=`expr 15 + $score` + echo , Args OK $time + else + echo , Args WRONG "($args)" $time + fi + +echo "Score: $score/50" + +if [ $score -lt 50 ]; 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..aba04de --- /dev/null +++ b/inc/assert.h @@ -0,0 +1,20 @@ +/* See COPYRIGHT for copyright information. */ + +#ifndef JOS_INC_ASSERT_H +#define JOS_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 /* !JOS_INC_ASSERT_H */ diff --git a/inc/elf.h b/inc/elf.h new file mode 100644 index 0000000..f0ce1e1 --- /dev/null +++ b/inc/elf.h @@ -0,0 +1,65 @@ +#ifndef JOS_INC_ELF_H +#define JOS_INC_ELF_H + +#define ELF_MAGIC 0x464C457FU /* "\x7FELF" in little endian */ + +struct Elf { + uint32_t e_magic; // must equal ELF_MAGIC + uint8_t e_elf[12]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint32_t e_entry; + uint32_t e_phoff; + uint32_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +}; + +struct Proghdr { + uint32_t p_type; + uint32_t p_offset; + uint32_t p_va; + uint32_t p_pa; + uint32_t p_filesz; + uint32_t p_memsz; + uint32_t p_flags; + uint32_t p_align; +}; + +struct Secthdr { + uint32_t sh_name; + uint32_t sh_type; + uint32_t sh_flags; + uint32_t sh_addr; + uint32_t sh_offset; + uint32_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint32_t sh_addralign; + uint32_t sh_entsize; +}; + +// Values for Proghdr::p_type +#define ELF_PROG_LOAD 1 + +// Flag bits for Proghdr::p_flags +#define ELF_PROG_FLAG_EXEC 1 +#define ELF_PROG_FLAG_WRITE 2 +#define ELF_PROG_FLAG_READ 4 + +// Values for Secthdr::sh_type +#define ELF_SHT_NULL 0 +#define ELF_SHT_PROGBITS 1 +#define ELF_SHT_SYMTAB 2 +#define ELF_SHT_STRTAB 3 + +// Values for Secthdr::sh_name +#define ELF_SHN_UNDEF 0 + +#endif /* !JOS_INC_ELF_H */ diff --git a/inc/error.h b/inc/error.h new file mode 100644 index 0000000..6906da5 --- /dev/null +++ b/inc/error.h @@ -0,0 +1,18 @@ +/* See COPYRIGHT for copyright information. */ + +#ifndef JOS_INC_ERROR_H +#define JOS_INC_ERROR_H + +// Kernel error codes -- keep in sync with list in lib/printfmt.c. +#define E_UNSPECIFIED 1 // Unspecified or unknown problem +#define E_BAD_ENV 2 // Environment doesn't exist or otherwise + // cannot be used in requested action +#define E_INVAL 3 // Invalid parameter +#define E_NO_MEM 4 // Request failed due to memory shortage +#define E_NO_FREE_ENV 5 // Attempt to create a new environment beyond + // the maximum allowed +#define E_FAULT 6 // Memory fault + +#define MAXERROR 6 + +#endif // !JOS_INC_ERROR_H */ diff --git a/inc/kbdreg.h b/inc/kbdreg.h new file mode 100644 index 0000000..7c6d740 --- /dev/null +++ b/inc/kbdreg.h @@ -0,0 +1,83 @@ +#ifndef JOS_KBDREG_H +#define JOS_KBDREG_H + +// Special keycodes +#define KEY_HOME 0xE0 +#define KEY_END 0xE1 +#define KEY_UP 0xE2 +#define KEY_DN 0xE3 +#define KEY_LF 0xE4 +#define KEY_RT 0xE5 +#define KEY_PGUP 0xE6 +#define KEY_PGDN 0xE7 +#define KEY_INS 0xE8 +#define KEY_DEL 0xE9 + + +/* This is i8042reg.h + kbdreg.h from NetBSD. */ + +#define KBSTATP 0x64 /* kbd controller status port(I) */ +#define KBS_DIB 0x01 /* kbd data in buffer */ +#define KBS_IBF 0x02 /* kbd input buffer low */ +#define KBS_WARM 0x04 /* kbd input buffer low */ +#define KBS_OCMD 0x08 /* kbd output buffer has command */ +#define KBS_NOSEC 0x10 /* kbd security lock not engaged */ +#define KBS_TERR 0x20 /* kbd transmission error */ +#define KBS_RERR 0x40 /* kbd receive error */ +#define KBS_PERR 0x80 /* kbd parity error */ + +#define KBCMDP 0x64 /* kbd controller port(O) */ +#define KBC_RAMREAD 0x20 /* read from RAM */ +#define KBC_RAMWRITE 0x60 /* write to RAM */ +#define KBC_AUXDISABLE 0xa7 /* disable auxiliary port */ +#define KBC_AUXENABLE 0xa8 /* enable auxiliary port */ +#define KBC_AUXTEST 0xa9 /* test auxiliary port */ +#define KBC_KBDECHO 0xd2 /* echo to keyboard port */ +#define KBC_AUXECHO 0xd3 /* echo to auxiliary port */ +#define KBC_AUXWRITE 0xd4 /* write to auxiliary port */ +#define KBC_SELFTEST 0xaa /* start self-test */ +#define KBC_KBDTEST 0xab /* test keyboard port */ +#define KBC_KBDDISABLE 0xad /* disable keyboard port */ +#define KBC_KBDENABLE 0xae /* enable keyboard port */ +#define KBC_PULSE0 0xfe /* pulse output bit 0 */ +#define KBC_PULSE1 0xfd /* pulse output bit 1 */ +#define KBC_PULSE2 0xfb /* pulse output bit 2 */ +#define KBC_PULSE3 0xf7 /* pulse output bit 3 */ + +#define KBDATAP 0x60 /* kbd data port(I) */ +#define KBOUTP 0x60 /* kbd data port(O) */ + +#define K_RDCMDBYTE 0x20 +#define K_LDCMDBYTE 0x60 + +#define KC8_TRANS 0x40 /* convert to old scan codes */ +#define KC8_MDISABLE 0x20 /* disable mouse */ +#define KC8_KDISABLE 0x10 /* disable keyboard */ +#define KC8_IGNSEC 0x08 /* ignore security lock */ +#define KC8_CPU 0x04 /* exit from protected mode reset */ +#define KC8_MENABLE 0x02 /* enable mouse interrupt */ +#define KC8_KENABLE 0x01 /* enable keyboard interrupt */ +#define CMDBYTE (KC8_TRANS|KC8_CPU|KC8_MENABLE|KC8_KENABLE) + +/* keyboard commands */ +#define KBC_RESET 0xFF /* reset the keyboard */ +#define KBC_RESEND 0xFE /* request the keyboard resend the last byte */ +#define KBC_SETDEFAULT 0xF6 /* resets keyboard to its power-on defaults */ +#define KBC_DISABLE 0xF5 /* as per KBC_SETDEFAULT, but also disable key scanning */ +#define KBC_ENABLE 0xF4 /* enable key scanning */ +#define KBC_TYPEMATIC 0xF3 /* set typematic rate and delay */ +#define KBC_SETTABLE 0xF0 /* set scancode translation table */ +#define KBC_MODEIND 0xED /* set mode indicators(i.e. LEDs) */ +#define KBC_ECHO 0xEE /* request an echo from the keyboard */ + +/* keyboard responses */ +#define KBR_EXTENDED 0xE0 /* extended key sequence */ +#define KBR_RESEND 0xFE /* needs resend of command */ +#define KBR_ACK 0xFA /* received a valid command */ +#define KBR_OVERRUN 0x00 /* flooded */ +#define KBR_FAILURE 0xFD /* diagnosic failure */ +#define KBR_BREAK 0xF0 /* break code prefix - sent on key release */ +#define KBR_RSTDONE 0xAA /* reset complete */ +#define KBR_ECHO 0xEE /* echo response */ + +#endif /* !JOS_KBDREG_H */ diff --git a/inc/malloc.h b/inc/malloc.h new file mode 100644 index 0000000..bef7267 --- /dev/null +++ b/inc/malloc.h @@ -0,0 +1,7 @@ +#ifndef JOS_INC_MALLOC_H +#define JOS_INC_MALLOC_H 1 + +void *malloc(size_t size); +void free(void *addr); + +#endif diff --git a/inc/memlayout.h b/inc/memlayout.h new file mode 100644 index 0000000..d39c587 --- /dev/null +++ b/inc/memlayout.h @@ -0,0 +1,181 @@ +#ifndef JOS_INC_MEMLAYOUT_H +#define JOS_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/-- + * KERNBASE -----> +------------------------------+ 0xf0000000 + * | Cur. Page Table (Kern. RW) | RW/-- PTSIZE + * VPT,KSTACKTOP--> +------------------------------+ 0xefc00000 --+ + * | Kernel Stack | RW/-- KSTKSIZE | + * | - - - - - - - - - - - - - - -| PTSIZE + * | Invalid Memory (*) | --/-- | + * ULIM ------> +------------------------------+ 0xef800000 --+ + * | Cur. Page Table (User R-) | R-/R- PTSIZE + * UVPT ----> +------------------------------+ 0xef400000 + * | RO PAGES | R-/R- PTSIZE + * UPAGES ----> +------------------------------+ 0xef000000 + * | RO ENVS | R-/R- PTSIZE + * UTOP,UENVS ------> +------------------------------+ 0xeec00000 + * UXSTACKTOP -/ | User Exception Stack | RW/RW PGSIZE + * +------------------------------+ 0xeebff000 + * | Empty Memory (*) | --/-- PGSIZE + * USTACKTOP ---> +------------------------------+ 0xeebfe000 + * | Normal User Stack | RW/RW PGSIZE + * +------------------------------+ 0xeebfd000 + * | | + * | | + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * . . + * . . + * . . + * |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| + * | Program Data & Heap | + * UTEXT --------> +------------------------------+ 0x00800000 + * PFTEMP -------> | Empty Memory (*) | PTSIZE + * | | + * UTEMP --------> +------------------------------+ 0x00400000 --+ + * | Empty Memory (*) | | + * | - - - - - - - - - - - - - - -| | + * | User STAB Data (optional) | PTSIZE + * USTABDATA ----> +------------------------------+ 0x00200000 | + * | Empty Memory (*) | | + * 0 ------------> +------------------------------+ --+ + * + * (*) Note: The kernel ensures that "Invalid Memory" (ULIM) is *never* + * mapped. "Empty Memory" is normally unmapped, but user programs may + * map pages there if desired. JOS user programs map pages temporarily + * at UTEMP. + */ + + +// All physical memory mapped at this address +#define KERNBASE 0xF0000000 + +// At IOPHYSMEM (640K) there is a 384K hole for I/O. From the kernel, +// IOPHYSMEM can be addressed at KERNBASE + IOPHYSMEM. The hole ends +// at physical address EXTPHYSMEM. +#define IOPHYSMEM 0x0A0000 +#define EXTPHYSMEM 0x100000 + +// Virtual page table. Entry PDX[VPT] in the PD contains a pointer to +// the page directory itself, thereby turning the PD into a page table, +// which maps all the PTEs containing the page mappings for the entire +// virtual address space into that 4 Meg region starting at VPT. +#define VPT (KERNBASE - PTSIZE) +#define KSTACKTOP VPT +#define KSTKSIZE (8*PGSIZE) // size of a kernel stack +#define ULIM (KSTACKTOP - PTSIZE) + +/* + * User read-only mappings! Anything below here til UTOP are readonly to user. + * They are global pages mapped in at env allocation time. + */ + +// Same as VPT but read-only for users +#define UVPT (ULIM - PTSIZE) +// Read-only copies of the Page structures +#define UPAGES (UVPT - PTSIZE) +// Read-only copies of the global env structures +#define UENVS (UPAGES - PTSIZE) + +/* + * Top of user VM. User can manipulate VA from UTOP-1 and down! + */ + +// Top of user-accessible VM +#define UTOP UENVS +// Top of one-page user exception stack +#define UXSTACKTOP UTOP +// Next page left invalid to guard against exception stack overflow; then: +// Top of normal user stack +#define USTACKTOP (UTOP - 2*PGSIZE) + +// Where user programs generally begin +#define UTEXT (2*PTSIZE) + +// Used for temporary page mappings. Typed 'void*' for convenience +#define UTEMP ((void*) PTSIZE) +// Used for temporary page mappings for the user page-fault handler +// (should not conflict with other temporary page mappings) +#define PFTEMP (UTEMP + PTSIZE - PGSIZE) +// The location of the user-level STABS data structure +#define USTABDATA (PTSIZE / 2) + + +#ifndef __ASSEMBLER__ + +/* + * The page directory entry corresponding to the virtual address range + * [VPT, VPT + PTSIZE) points to the page directory itself. Thus, the page + * directory is treated as a page table as well as a page directory. + * + * One result of treating the page directory as a page table is that all PTEs + * can be accessed through a "virtual page table" at virtual address VPT (to + * which vpt is set in entry.S). The PTE for page number N is stored in + * vpt[N]. (It's worth drawing a diagram of this!) + * + * A second consequence is that the contents of the current page directory + * will always be available at virtual address (VPT + (VPT >> PGSHIFT)), to + * which vpd is set in entry.S. + */ +typedef uint32_t pte_t; +typedef uint32_t pde_t; + +extern volatile pte_t vpt[]; // VA of "virtual page table" +extern volatile pde_t vpd[]; // VA of current page directory + + +/* + * Page descriptor structures, mapped at UPAGES. + * Read/write to the kernel, read-only to user programs. + * + * Each Page describes one physical page. + * You can map a Page * to the corresponding physical address + * with page2pa() in kern/pmap.h. + */ +LIST_HEAD(Page_list, Page); +typedef LIST_ENTRY(Page) Page_LIST_entry_t; + +struct Page { + Page_LIST_entry_t pp_link; /* free list link */ + + // pp_ref is the count of pointers (usually in page table entries) + // to this page, for pages allocated using page_alloc. + // Pages allocated at boot time using pmap.c's + // boot_alloc do not have valid reference count fields. + + uint16_t pp_ref; +}; + +#endif /* !__ASSEMBLER__ */ +#endif /* !JOS_INC_MEMLAYOUT_H */ diff --git a/inc/mmu.h b/inc/mmu.h new file mode 100644 index 0000000..29e21a7 --- /dev/null +++ b/inc/mmu.h @@ -0,0 +1,312 @@ +#ifndef JOS_INC_MMU_H +#define JOS_INC_MMU_H + +/* + * This file contains definitions for the x86 memory management unit (MMU), + * including paging- and segmentation-related data structures and constants, + * the %cr0, %cr4, and %eflags registers, and traps. + */ + +/* + * + * Part 1. Paging data structures and constants. + * + */ + +// A linear address 'la' has a three-part structure as follows: +// +// +--------10------+-------10-------+---------12----------+ +// | Page Directory | Page Table | Offset within Page | +// | Index | Index | | +// +----------------+----------------+---------------------+ +// \--- PDX(la) --/ \--- PTX(la) --/ \---- PGOFF(la) ----/ +// \----------- PPN(la) -----------/ +// +// The PDX, PTX, PGOFF, and PPN macros decompose linear addresses as shown. +// To construct a linear address la from PDX(la), PTX(la), and PGOFF(la), +// use PGADDR(PDX(la), PTX(la), PGOFF(la)). + +// page number field of address +#define PPN(la) (((uintptr_t) (la)) >> PTXSHIFT) +#define VPN(la) PPN(la) // used to index into vpt[] + +// page directory index +#define PDX(la) ((((uintptr_t) (la)) >> PDXSHIFT) & 0x3FF) +#define VPD(la) PDX(la) // used to index into vpd[] + +// page table index +#define PTX(la) ((((uintptr_t) (la)) >> PTXSHIFT) & 0x3FF) + +// offset in page +#define PGOFF(la) (((uintptr_t) (la)) & 0xFFF) + +// construct linear address from indexes and offset +#define PGADDR(d, t, o) ((void*) ((d) << PDXSHIFT | (t) << PTXSHIFT | (o))) + +// Page directory and page table constants. +#define NPDENTRIES 1024 // page directory entries per page directory +#define NPTENTRIES 1024 // page table entries per page table + +#define PGSIZE 4096 // bytes mapped by a page +#define PGSHIFT 12 // log2(PGSIZE) + +#define PTSIZE (PGSIZE*NPTENTRIES) // bytes mapped by a page directory entry +#define PTSHIFT 22 // log2(PTSIZE) + +#define PTXSHIFT 12 // offset of PTX in a linear address +#define PDXSHIFT 22 // offset of PDX in a linear address + +// Page table/directory entry flags. +#define PTE_P 0x001 // Present +#define PTE_W 0x002 // Writeable +#define PTE_U 0x004 // User +#define PTE_PWT 0x008 // Write-Through +#define PTE_PCD 0x010 // Cache-Disable +#define PTE_A 0x020 // Accessed +#define PTE_D 0x040 // Dirty +#define PTE_PS 0x080 // Page Size +#define PTE_MBZ 0x180 // Bits must be zero + +// The PTE_AVAIL bits aren't used by the kernel or interpreted by the +// hardware, so user processes are allowed to set them arbitrarily. +#define PTE_AVAIL 0xE00 // Available for software use + +// Only flags in PTE_USER may be used in system calls. +#define PTE_USER (PTE_AVAIL | PTE_P | PTE_W | PTE_U) + +// address in page table entry +#define PTE_ADDR(pte) ((physaddr_t) (pte) & ~0xFFF) + +// Control Register flags +#define CR0_PE 0x00000001 // Protection Enable +#define CR0_MP 0x00000002 // Monitor coProcessor +#define CR0_EM 0x00000004 // Emulation +#define CR0_TS 0x00000008 // Task Switched +#define CR0_ET 0x00000010 // Extension Type +#define CR0_NE 0x00000020 // Numeric Errror +#define CR0_WP 0x00010000 // Write Protect +#define CR0_AM 0x00040000 // Alignment Mask +#define CR0_NW 0x20000000 // Not Writethrough +#define CR0_CD 0x40000000 // Cache Disable +#define CR0_PG 0x80000000 // Paging + +#define CR4_PCE 0x00000100 // Performance counter enable +#define CR4_MCE 0x00000040 // Machine Check Enable +#define CR4_PSE 0x00000010 // Page Size Extensions +#define CR4_DE 0x00000008 // Debugging Extensions +#define CR4_TSD 0x00000004 // Time Stamp Disable +#define CR4_PVI 0x00000002 // Protected-Mode Virtual Interrupts +#define CR4_VME 0x00000001 // V86 Mode Extensions + +// Eflags register +#define FL_CF 0x00000001 // Carry Flag +#define FL_PF 0x00000004 // Parity Flag +#define FL_AF 0x00000010 // Auxiliary carry Flag +#define FL_ZF 0x00000040 // Zero Flag +#define FL_SF 0x00000080 // Sign Flag +#define FL_TF 0x00000100 // Trap Flag +#define FL_IF 0x00000200 // Interrupt Flag +#define FL_DF 0x00000400 // Direction Flag +#define FL_OF 0x00000800 // Overflow Flag +#define FL_IOPL_MASK 0x00003000 // I/O Privilege Level bitmask +#define FL_IOPL_0 0x00000000 // IOPL == 0 +#define FL_IOPL_1 0x00001000 // IOPL == 1 +#define FL_IOPL_2 0x00002000 // IOPL == 2 +#define FL_IOPL_3 0x00003000 // IOPL == 3 +#define FL_NT 0x00004000 // Nested Task +#define FL_RF 0x00010000 // Resume Flag +#define FL_VM 0x00020000 // Virtual 8086 mode +#define FL_AC 0x00040000 // Alignment Check +#define FL_VIF 0x00080000 // Virtual Interrupt Flag +#define FL_VIP 0x00100000 // Virtual Interrupt Pending +#define FL_ID 0x00200000 // ID flag + +// Page fault error codes +#define FEC_PR 0x1 // Page fault caused by protection violation +#define FEC_WR 0x2 // Page fault caused by a write +#define FEC_U 0x4 // Page fault occured while in user mode + + +/* + * + * Part 2. Segmentation data structures and constants. + * + */ + +#ifdef __ASSEMBLER__ + +/* + * Macros to build GDT entries in assembly. + */ +#define SEG_NULL \ + .word 0, 0; \ + .byte 0, 0, 0, 0 +#define SEG(type,base,lim) \ + .word (((lim) >> 12) & 0xffff), ((base) & 0xffff); \ + .byte (((base) >> 16) & 0xff), (0x90 | (type)), \ + (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff) + +#else // not __ASSEMBLER__ + +#include + +// Segment Descriptors +struct Segdesc { + unsigned sd_lim_15_0 : 16; // Low bits of segment limit + unsigned sd_base_15_0 : 16; // Low bits of segment base address + unsigned sd_base_23_16 : 8; // Middle bits of segment base address + unsigned sd_type : 4; // Segment type (see STS_ constants) + unsigned sd_s : 1; // 0 = system, 1 = application + unsigned sd_dpl : 2; // Descriptor Privilege Level + unsigned sd_p : 1; // Present + unsigned sd_lim_19_16 : 4; // High bits of segment limit + unsigned sd_avl : 1; // Unused (available for software use) + unsigned sd_rsv1 : 1; // Reserved + unsigned sd_db : 1; // 0 = 16-bit segment, 1 = 32-bit segment + unsigned sd_g : 1; // Granularity: limit scaled by 4K when set + unsigned sd_base_31_24 : 8; // High bits of segment base address +}; +// Null segment +#define SEG_NULL (struct Segdesc){ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } +// Segment that is loadable but faults when used +#define SEG_FAULT (struct Segdesc){ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 } +// Normal segment +#define SEG(type, base, lim, dpl) (struct Segdesc) \ +{ ((lim) >> 12) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff, \ + type, 1, dpl, 1, (unsigned) (lim) >> 28, 0, 0, 1, 1, \ + (unsigned) (base) >> 24 } +#define SEG16(type, base, lim, dpl) (struct Segdesc) \ +{ (lim) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff, \ + type, 1, dpl, 1, (unsigned) (lim) >> 16, 0, 0, 1, 0, \ + (unsigned) (base) >> 24 } + +#endif /* !__ASSEMBLER__ */ + +// Application segment type bits +#define STA_X 0x8 // Executable segment +#define STA_E 0x4 // Expand down (non-executable segments) +#define STA_C 0x4 // Conforming code segment (executable only) +#define STA_W 0x2 // Writeable (non-executable segments) +#define STA_R 0x2 // Readable (executable segments) +#define STA_A 0x1 // Accessed + +// System segment type bits +#define STS_T16A 0x1 // Available 16-bit TSS +#define STS_LDT 0x2 // Local Descriptor Table +#define STS_T16B 0x3 // Busy 16-bit TSS +#define STS_CG16 0x4 // 16-bit Call Gate +#define STS_TG 0x5 // Task Gate / Coum Transmitions +#define STS_IG16 0x6 // 16-bit Interrupt Gate +#define STS_TG16 0x7 // 16-bit Trap Gate +#define STS_T32A 0x9 // Available 32-bit TSS +#define STS_T32B 0xB // Busy 32-bit TSS +#define STS_CG32 0xC // 32-bit Call Gate +#define STS_IG32 0xE // 32-bit Interrupt Gate +#define STS_TG32 0xF // 32-bit Trap Gate + + +/* + * + * Part 3. Traps. + * + */ + +#ifndef __ASSEMBLER__ + +// Task state segment format (as described by the Pentium architecture book) +struct Taskstate { + uint32_t ts_link; // Old ts selector + uintptr_t ts_esp0; // Stack pointers and segment selectors + uint16_t ts_ss0; // after an increase in privilege level + uint16_t ts_padding1; + uintptr_t ts_esp1; + uint16_t ts_ss1; + uint16_t ts_padding2; + uintptr_t ts_esp2; + uint16_t ts_ss2; + uint16_t ts_padding3; + physaddr_t ts_cr3; // Page directory base + uintptr_t ts_eip; // Saved state from last task switch + uint32_t ts_eflags; + uint32_t ts_eax; // More saved state (registers) + uint32_t ts_ecx; + uint32_t ts_edx; + uint32_t ts_ebx; + uintptr_t ts_esp; + uintptr_t ts_ebp; + uint32_t ts_esi; + uint32_t ts_edi; + uint16_t ts_es; // Even more saved state (segment selectors) + uint16_t ts_padding4; + uint16_t ts_cs; + uint16_t ts_padding5; + uint16_t ts_ss; + uint16_t ts_padding6; + uint16_t ts_ds; + uint16_t ts_padding7; + uint16_t ts_fs; + uint16_t ts_padding8; + uint16_t ts_gs; + uint16_t ts_padding9; + uint16_t ts_ldt; + uint16_t ts_padding10; + uint16_t ts_t; // Trap on task switch + uint16_t ts_iomb; // I/O map base address +}; + +// Gate descriptors for interrupts and traps +struct Gatedesc { + unsigned gd_off_15_0 : 16; // low 16 bits of offset in segment + unsigned gd_ss : 16; // segment selector + unsigned gd_args : 5; // # args, 0 for interrupt/trap gates + unsigned gd_rsv1 : 3; // reserved(should be zero I guess) + unsigned gd_type : 4; // type(STS_{TG,IG32,TG32}) + unsigned gd_s : 1; // must be 0 (system) + unsigned gd_dpl : 2; // descriptor(meaning new) privilege level + unsigned gd_p : 1; // Present + unsigned gd_off_31_16 : 16; // high bits of offset in segment +}; + +// Set up a normal interrupt/trap gate descriptor. +// - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate. +// - sel: Code segment selector for interrupt/trap handler +// - off: Offset in code segment for interrupt/trap handler +// - dpl: Descriptor Privilege Level - +// the privilege level required for software to invoke +// this interrupt/trap gate explicitly using an int instruction. +#define SETGATE(gate, istrap, sel, off, dpl) \ +{ \ + (gate).gd_off_15_0 = (uint32_t) (off) & 0xffff; \ + (gate).gd_ss = (sel); \ + (gate).gd_args = 0; \ + (gate).gd_rsv1 = 0; \ + (gate).gd_type = (istrap) ? STS_TG32 : STS_IG32; \ + (gate).gd_s = 0; \ + (gate).gd_dpl = (dpl); \ + (gate).gd_p = 1; \ + (gate).gd_off_31_16 = (uint32_t) (off) >> 16; \ +} + +// Set up a call gate descriptor. +#define SETCALLGATE(gate, ss, off, dpl) \ +{ \ + (gate).gd_off_15_0 = (uint32_t) (off) & 0xffff; \ + (gate).gd_ss = (ss); \ + (gate).gd_args = 0; \ + (gate).gd_rsv1 = 0; \ + (gate).gd_type = STS_CG32; \ + (gate).gd_s = 0; \ + (gate).gd_dpl = (dpl); \ + (gate).gd_p = 1; \ + (gate).gd_off_31_16 = (uint32_t) (off) >> 16; \ +} + +// Pseudo-descriptors used for LGDT, LLDT and LIDT instructions. +struct Pseudodesc { + uint16_t pd_lim; // Limit + uint32_t pd_base; // Base address +} __attribute__ ((packed)); + +#endif /* !__ASSEMBLER__ */ + +#endif /* !JOS_INC_MMU_H */ diff --git a/inc/queue.h b/inc/queue.h new file mode 100644 index 0000000..7680415 --- /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 Jos, extra comments have been added to this file, and the original + * TAILQ and CIRCLEQ definitions have been removed. - August 9, 2005 + */ + +#ifndef JOS_INC_QUEUE_H +#define JOS_INC_QUEUE_H + +/* + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + */ + +/* + * An example using the below functions. + */ +#if 0 + +struct Frob +{ + int frobozz; + LIST_ENTRY(Frob) frob_link; /* this contains the list element pointers */ +}; + +LIST_HEAD(Frob_list, Frob) /* defines struct Frob_list as a list of Frob */ + +struct Frob_list flist; /* declare a Frob list */ + +LIST_INIT(&flist); /* clear flist (globals are cleared anyway) */ +flist = LIST_HEAD_INITIALIZER(&flist); /* alternate way to clear flist */ + +if(LIST_EMPTY(&flist)) /* check whether list is empty */ + printf("list is empty\n"); + +struct Frob *f = LIST_FIRST(&flist); /* f is first element in list */ +f = LIST_NEXT(f, frob_link); /* now f is next (second) element in list */ +f = LIST_NEXT(f, frob_link); /* now f is next (third) element in list */ + +for(f=LIST_FIRST(&flist); f != 0; /* iterate over elements in flist */ + f = LIST_NEXT(f, frob_link)) + printf("f %d\n", f->frobozz); + +LIST_FOREACH(f, &flist, frob_link) /* alternate way to say that */ + printf("f %d\n", f->frobozz); + +f = LIST_NEXT(LIST_FIRST(&flist)); /* f is second element in list */ +LIST_INSERT_AFTER(f, g, frob_link); /* add g right after f in list */ +LIST_REMOVE(g, frob_link); /* remove g from list (can't insert twice!) */ +LIST_INSERT_BEFORE(f, g, frob_link); /* add g right before f */ +LIST_REMOVE(g, frob_link); /* remove g again */ +LIST_INSERT_HEAD(&flist, g, frob_link); /* add g as first element in list */ + +#endif + +/* + * List declarations. + */ + +/* + * A list is headed by a structure defined by the LIST_HEAD macro. This structure con‐ + * tains a single pointer to the first element on the list. The elements are doubly + * linked so that an arbitrary element can be removed without traversing the list. New + * elements can be added to the list after an existing element or at the head of the list. + * A LIST_HEAD structure is declared as follows: + * + * LIST_HEAD(HEADNAME, TYPE) head; + * + * where HEADNAME is the name of the structure to be defined, and TYPE is the type of the + * elements to be linked into the list. A pointer to the head of the list can later be + * declared as: + * + * struct HEADNAME *headp; + * + * (The names head and headp are user selectable.) + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +/* + * Set a list head variable to LIST_HEAD_INITIALIZER(head) + * to reset it to the empty list. + */ +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +/* + * Use this inside a structure "LIST_ENTRY(type) field" to use + * x as the list piece. + * + * The le_prev points at the pointer to the structure containing + * this very LIST_ENTRY, so that if we want to remove this list entry, + * we can do *le_prev = le_next to update the structure pointing at us. + */ +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* ptr to ptr to this element */ \ +} + +/* + * List functions. + */ + +/* + * Is the list named "head" empty? + */ +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +/* + * Return the first element in the list named "head". + */ +#define LIST_FIRST(head) ((head)->lh_first) + +/* + * Return the element after "elm" in the list. + * The "field" name is the link element as above. + */ +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +/* + * Iterate over the elements in the list named "head". + * During the loop, assign the list elements to the variable "var" + * and use the LIST_ENTRY structure member "field" as the link field. + */ +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +/* + * Reset the list named "head" to the empty list. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +/* + * Insert the element "elm" *after* the element "listelm" which is + * already in the list. The "field" name is the link element + * as above. + */ +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +/* + * Insert the element "elm" *before* the element "listelm" which is + * already in the list. The "field" name is the link element + * as above. + */ +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +/* + * Insert the element "elm" at the head of the list named "head". + * The "field" name is the link element as above. + */ +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +/* + * Remove the element "elm" from the list. + * The "field" name is the link element as above. + */ +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/inc/stab.h b/inc/stab.h new file mode 100644 index 0000000..9b022bb --- /dev/null +++ b/inc/stab.h @@ -0,0 +1,51 @@ +#ifndef JOS_STAB_H +#define JOS_STAB_H +#include + +// +// STABS debugging info + +// The JOS kernel debugger can understand some debugging information +// in the STABS format. For more information on this format, see +// http://sources.redhat.com/gdb/onlinedocs/stabs_toc.html + +// The constants below define some symbol types used by various debuggers +// and compilers. JOS uses the N_SO, N_SOL, N_FUN, and N_SLINE types. + +#define N_GSYM 0x20 // global symbol +#define N_FNAME 0x22 // F77 function name +#define N_FUN 0x24 // procedure name +#define N_STSYM 0x26 // data segment variable +#define N_LCSYM 0x28 // bss segment variable +#define N_MAIN 0x2a // main function name +#define N_PC 0x30 // global Pascal symbol +#define N_RSYM 0x40 // register variable +#define N_SLINE 0x44 // text segment line number +#define N_DSLINE 0x46 // data segment line number +#define N_BSLINE 0x48 // bss segment line number +#define N_SSYM 0x60 // structure/union element +#define N_SO 0x64 // main source file name +#define N_LSYM 0x80 // stack variable +#define N_BINCL 0x82 // include file beginning +#define N_SOL 0x84 // included source file name +#define N_PSYM 0xa0 // parameter variable +#define N_EINCL 0xa2 // include file end +#define N_ENTRY 0xa4 // alternate entry point +#define N_LBRAC 0xc0 // left bracket +#define N_EXCL 0xc2 // deleted include file +#define N_RBRAC 0xe0 // right bracket +#define N_BCOMM 0xe2 // begin common +#define N_ECOMM 0xe4 // end common +#define N_ECOML 0xe8 // end common (local name) +#define N_LENG 0xfe // length of preceding entry + +// Entries in the STABS table are formatted as follows. +struct Stab { + uint32_t n_strx; // index into string table of name + uint8_t n_type; // type of symbol + uint8_t n_other; // misc info (usually empty) + uint16_t n_desc; // description field + uintptr_t n_value; // value of symbol +}; + +#endif /* !JOS_STAB_H */ diff --git a/inc/stdarg.h b/inc/stdarg.h new file mode 100644 index 0000000..9fc067e --- /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 JOS_INC_STDARG_H +#define JOS_INC_STDARG_H + +typedef char *va_list; + +#define __va_size(type) \ + (((sizeof(type) + sizeof(long) - 1) / sizeof(long)) * sizeof(long)) + +#define va_start(ap, last) \ + ((ap) = (va_list)&(last) + __va_size(last)) + +#define va_arg(ap, type) \ + (*(type *)((ap) += __va_size(type), (ap) - __va_size(type))) + +#define va_end(ap) ((void)0) + +#endif /* !JOS_INC_STDARG_H */ diff --git a/inc/stdio.h b/inc/stdio.h new file mode 100644 index 0000000..e7b4a35 --- /dev/null +++ b/inc/stdio.h @@ -0,0 +1,35 @@ +#ifndef JOS_INC_STDIO_H +#define JOS_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 +char* readline(const char *prompt); + +#endif /* !JOS_INC_STDIO_H */ diff --git a/inc/string.h b/inc/string.h new file mode 100644 index 0000000..617cd28 --- /dev/null +++ b/inc/string.h @@ -0,0 +1,24 @@ +#ifndef JOS_INC_STRING_H +#define JOS_INC_STRING_H + +#include + +int strlen(const char *s); +int strnlen(const char *s, size_t size); +char * strcpy(char *dst, const char *src); +char * strncpy(char *dst, const char *src, size_t size); +size_t strlcpy(char *dst, const char *src, size_t size); +int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t size); +char * strchr(const char *s, char c); +char * strfind(const char *s, char c); + +void * memset(void *dst, int c, size_t len); +/* no memcpy - use memmove instead */ +void * memmove(void *dst, const void *src, size_t len); +int memcmp(const void *s1, const void *s2, size_t len); +void * memfind(const void *s, int c, size_t len); + +long strtol(const char *s, char **endptr, int base); + +#endif /* not JOS_INC_STRING_H */ diff --git a/inc/types.h b/inc/types.h new file mode 100644 index 0000000..4627178 --- /dev/null +++ b/inc/types.h @@ -0,0 +1,72 @@ +#ifndef JOS_INC_TYPES_H +#define JOS_INC_TYPES_H + +#ifndef NULL +#define NULL ((void*) 0) +#endif + +// Represents true-or-false values +typedef int bool; + +// Explicitly-sized versions of integer types +typedef __signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; + +// Pointers and addresses are 32 bits long. +// We use pointer types to represent virtual addresses, +// uintptr_t to represent the numerical values of virtual addresses, +// and physaddr_t to represent physical addresses. +typedef int32_t intptr_t; +typedef uint32_t uintptr_t; +typedef uint32_t physaddr_t; + +// Page numbers are 32 bits long. +typedef uint32_t ppn_t; + +// size_t is used for memory object sizes. +typedef uint32_t size_t; +// ssize_t is a signed version of ssize_t, used in case there might be an +// error return. +typedef int32_t ssize_t; + +// off_t is used for file offsets and lengths. +typedef int32_t off_t; + +// Efficient min and max operations +#define MIN(_a, _b) \ +({ \ + typeof(_a) __a = (_a); \ + typeof(_b) __b = (_b); \ + __a <= __b ? __a : __b; \ +}) +#define MAX(_a, _b) \ +({ \ + typeof(_a) __a = (_a); \ + typeof(_b) __b = (_b); \ + __a >= __b ? __a : __b; \ +}) + +// Rounding operations (efficient when n is a power of 2) +// Round down to the nearest multiple of n +#define ROUNDDOWN(a, n) \ +({ \ + uint32_t __a = (uint32_t) (a); \ + (typeof(a)) (__a - __a % (n)); \ +}) +// Round up to the nearest multiple of n +#define ROUNDUP(a, n) \ +({ \ + uint32_t __n = (uint32_t) (n); \ + (typeof(a)) (ROUNDDOWN((uint32_t) (a) + __n - 1, __n)); \ +}) + +// Return the offset of 'member' relative to the beginning of a struct type +#define offsetof(type, member) ((size_t) (&((type*)0)->member)) + +#endif /* !JOS_INC_TYPES_H */ diff --git a/inc/x86.h b/inc/x86.h new file mode 100644 index 0000000..67ad5c9 --- /dev/null +++ b/inc/x86.h @@ -0,0 +1,277 @@ +#ifndef JOS_INC_X86_H +#define JOS_INC_X86_H + +#include + +static __inline void breakpoint(void) __attribute__((always_inline)); +static __inline uint8_t inb(int port) __attribute__((always_inline)); +static __inline void insb(int port, void *addr, int cnt) __attribute__((always_inline)); +static __inline uint16_t inw(int port) __attribute__((always_inline)); +static __inline void insw(int port, void *addr, int cnt) __attribute__((always_inline)); +static __inline uint32_t inl(int port) __attribute__((always_inline)); +static __inline void insl(int port, void *addr, int cnt) __attribute__((always_inline)); +static __inline void outb(int port, uint8_t data) __attribute__((always_inline)); +static __inline void outsb(int port, const void *addr, int cnt) __attribute__((always_inline)); +static __inline void outw(int port, uint16_t data) __attribute__((always_inline)); +static __inline void outsw(int port, const void *addr, int cnt) __attribute__((always_inline)); +static __inline void outsl(int port, const void *addr, int cnt) __attribute__((always_inline)); +static __inline void outl(int port, uint32_t data) __attribute__((always_inline)); +static __inline void invlpg(void *addr) __attribute__((always_inline)); +static __inline void lidt(void *p) __attribute__((always_inline)); +static __inline void lldt(uint16_t sel) __attribute__((always_inline)); +static __inline void ltr(uint16_t sel) __attribute__((always_inline)); +static __inline void lcr0(uint32_t val) __attribute__((always_inline)); +static __inline uint32_t rcr0(void) __attribute__((always_inline)); +static __inline uint32_t rcr2(void) __attribute__((always_inline)); +static __inline void lcr3(uint32_t val) __attribute__((always_inline)); +static __inline uint32_t rcr3(void) __attribute__((always_inline)); +static __inline void lcr4(uint32_t val) __attribute__((always_inline)); +static __inline uint32_t rcr4(void) __attribute__((always_inline)); +static __inline void tlbflush(void) __attribute__((always_inline)); +static __inline uint32_t read_eflags(void) __attribute__((always_inline)); +static __inline void write_eflags(uint32_t eflags) __attribute__((always_inline)); +static __inline uint32_t read_ebp(void) __attribute__((always_inline)); +static __inline uint32_t read_esp(void) __attribute__((always_inline)); +static __inline void cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp); +static __inline uint64_t read_tsc(void) __attribute__((always_inline)); + +static __inline void +breakpoint(void) +{ + __asm __volatile("int3"); +} + +static __inline uint8_t +inb(int port) +{ + uint8_t data; + __asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static __inline void +insb(int port, void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\tinsb" : + "=D" (addr), "=c" (cnt) : + "d" (port), "0" (addr), "1" (cnt) : + "memory", "cc"); +} + +static __inline uint16_t +inw(int port) +{ + uint16_t data; + __asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static __inline void +insw(int port, void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\tinsw" : + "=D" (addr), "=c" (cnt) : + "d" (port), "0" (addr), "1" (cnt) : + "memory", "cc"); +} + +static __inline uint32_t +inl(int port) +{ + uint32_t data; + __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static __inline void +insl(int port, void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\tinsl" : + "=D" (addr), "=c" (cnt) : + "d" (port), "0" (addr), "1" (cnt) : + "memory", "cc"); +} + +static __inline void +outb(int port, uint8_t data) +{ + __asm __volatile("outb %0,%w1" : : "a" (data), "d" (port)); +} + +static __inline void +outsb(int port, const void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\toutsb" : + "=S" (addr), "=c" (cnt) : + "d" (port), "0" (addr), "1" (cnt) : + "cc"); +} + +static __inline void +outw(int port, uint16_t data) +{ + __asm __volatile("outw %0,%w1" : : "a" (data), "d" (port)); +} + +static __inline void +outsw(int port, const void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\toutsw" : + "=S" (addr), "=c" (cnt) : + "d" (port), "0" (addr), "1" (cnt) : + "cc"); +} + +static __inline void +outsl(int port, const void *addr, int cnt) +{ + __asm __volatile("cld\n\trepne\n\toutsl" : + "=S" (addr), "=c" (cnt) : + "d" (port), "0" (addr), "1" (cnt) : + "cc"); +} + +static __inline void +outl(int port, uint32_t data) +{ + __asm __volatile("outl %0,%w1" : : "a" (data), "d" (port)); +} + +static __inline void +invlpg(void *addr) +{ + __asm __volatile("invlpg (%0)" : : "r" (addr) : "memory"); +} + +static __inline void +lidt(void *p) +{ + __asm __volatile("lidt (%0)" : : "r" (p)); +} + +static __inline void +lldt(uint16_t sel) +{ + __asm __volatile("lldt %0" : : "r" (sel)); +} + +static __inline void +ltr(uint16_t sel) +{ + __asm __volatile("ltr %0" : : "r" (sel)); +} + +static __inline void +lcr0(uint32_t val) +{ + __asm __volatile("movl %0,%%cr0" : : "r" (val)); +} + +static __inline uint32_t +rcr0(void) +{ + uint32_t val; + __asm __volatile("movl %%cr0,%0" : "=r" (val)); + return val; +} + +static __inline uint32_t +rcr2(void) +{ + uint32_t val; + __asm __volatile("movl %%cr2,%0" : "=r" (val)); + return val; +} + +static __inline void +lcr3(uint32_t val) +{ + __asm __volatile("movl %0,%%cr3" : : "r" (val)); +} + +static __inline uint32_t +rcr3(void) +{ + uint32_t val; + __asm __volatile("movl %%cr3,%0" : "=r" (val)); + return val; +} + +static __inline void +lcr4(uint32_t val) +{ + __asm __volatile("movl %0,%%cr4" : : "r" (val)); +} + +static __inline uint32_t +rcr4(void) +{ + uint32_t cr4; + __asm __volatile("movl %%cr4,%0" : "=r" (cr4)); + return cr4; +} + +static __inline void +tlbflush(void) +{ + uint32_t cr3; + __asm __volatile("movl %%cr3,%0" : "=r" (cr3)); + __asm __volatile("movl %0,%%cr3" : : "r" (cr3)); +} + +static __inline uint32_t +read_eflags(void) +{ + uint32_t eflags; + __asm __volatile("pushfl; popl %0" : "=r" (eflags)); + return eflags; +} + +static __inline void +write_eflags(uint32_t eflags) +{ + __asm __volatile("pushl %0; popfl" : : "r" (eflags)); +} + +static __inline uint32_t +read_ebp(void) +{ + uint32_t ebp; + __asm __volatile("movl %%ebp,%0" : "=r" (ebp)); + return ebp; +} + +static __inline uint32_t +read_esp(void) +{ + uint32_t esp; + __asm __volatile("movl %%esp,%0" : "=r" (esp)); + return esp; +} + +static __inline void +cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp) +{ + uint32_t eax, ebx, ecx, edx; + asm volatile("cpuid" + : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) + : "a" (info)); + if (eaxp) + *eaxp = eax; + if (ebxp) + *ebxp = ebx; + if (ecxp) + *ecxp = ecx; + if (edxp) + *edxp = edx; +} + +static __inline uint64_t +read_tsc(void) +{ + uint64_t tsc; + __asm __volatile("rdtsc" : "=A" (tsc)); + return tsc; +} + +#endif /* !JOS_INC_X86_H */ diff --git a/kern/COPYRIGHT b/kern/COPYRIGHT new file mode 100644 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..6447953 --- /dev/null +++ b/kern/Makefrag @@ -0,0 +1,82 @@ +# +# Makefile fragment for JOS kernel. +# This is NOT a complete makefile; +# you must run GNU make in the top-level directory +# where the GNUmakefile is located. +# + +OBJDIRS += kern + +KERN_LDFLAGS := $(LDFLAGS) -T kern/kernel.ld -nostdlib + +# entry.S must be first, so that it's the first code in the text segment!!! +# +# We also snatch the use of a couple handy source files +# from the lib directory, to avoid gratuitous code duplication. +KERN_SRCFILES := kern/entry.S \ + kern/init.c \ + kern/console.c \ + kern/monitor.c \ + kern/pmap.c \ + kern/env.c \ + kern/kclock.c \ + kern/picirq.c \ + kern/printf.c \ + kern/trap.c \ + kern/trapentry.S \ + kern/sched.c \ + kern/syscall.c \ + kern/kdebug.c \ + lib/printfmt.c \ + lib/readline.c \ + lib/string.c + +# Only build files if they exist. +KERN_SRCFILES := $(wildcard $(KERN_SRCFILES)) + +KERN_BINFILES := + +KERN_OBJFILES := $(patsubst %.c, $(OBJDIR)/%.o, $(KERN_SRCFILES)) +KERN_OBJFILES := $(patsubst %.S, $(OBJDIR)/%.o, $(KERN_OBJFILES)) +KERN_OBJFILES := $(patsubst $(OBJDIR)/lib/%, $(OBJDIR)/kern/%, $(KERN_OBJFILES)) + +KERN_BINFILES := $(patsubst %, $(OBJDIR)/%, $(KERN_BINFILES)) + +# How to build kernel object files +$(OBJDIR)/kern/%.o: kern/%.c + @echo + cc $< + @mkdir -p $(@D) + $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $< + +$(OBJDIR)/kern/%.o: kern/%.S + @echo + as $< + @mkdir -p $(@D) + $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $< + +$(OBJDIR)/kern/%.o: lib/%.c + @echo + cc $< + @mkdir -p $(@D) + $(V)$(CC) -nostdinc $(KERN_CFLAGS) -c -o $@ $< + +# How to build the kernel itself +$(OBJDIR)/kern/kernel: $(KERN_OBJFILES) $(KERN_BINFILES) kern/kernel.ld + @echo + ld $@ + $(V)$(LD) -o $@ $(KERN_LDFLAGS) $(KERN_OBJFILES) $(GCC_LIB) -b binary $(KERN_BINFILES) + $(V)$(OBJDUMP) -S $@ > $@.asm + $(V)$(NM) -n $@ > $@.sym + +# How to build the Bochs disk image +$(OBJDIR)/kern/bochs.img: $(OBJDIR)/kern/kernel $(OBJDIR)/boot/boot + @echo + mk $@ + $(V)dd if=/dev/zero of=$(OBJDIR)/kern/bochs.img~ count=10000 2>/dev/null + $(V)dd if=$(OBJDIR)/boot/boot of=$(OBJDIR)/kern/bochs.img~ conv=notrunc 2>/dev/null + $(V)dd if=$(OBJDIR)/kern/kernel of=$(OBJDIR)/kern/bochs.img~ seek=1 conv=notrunc 2>/dev/null + $(V)mv $(OBJDIR)/kern/bochs.img~ $(OBJDIR)/kern/bochs.img + +all: $(OBJDIR)/kern/bochs.img + +grub: $(OBJDIR)/jos-grub + +$(OBJDIR)/jos-grub: $(OBJDIR)/kern/kernel + @echo + oc $@ + $(V)$(OBJCOPY) --adjust-vma=0x10000000 $^ $@ diff --git a/kern/console.c b/kern/console.c new file mode 100644 index 0000000..150fe16 --- /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_t) (115200 / 9600)); + outb(COM1+COM_DLM, 0); + + // 8 data bits, 1 stop bit, parity off; turn off DLAB latch + outb(COM1+COM_LCR, COM_LCR_WLEN8 & ~COM_LCR_DLAB); + + // No modem controls + outb(COM1+COM_MCR, 0); + // Enable rcv interrupts + outb(COM1+COM_IER, COM_IER_RDI); + + // Clear any preexisting overrun indications and interrupts + // Serial port doesn't exist if COM_LSR returns 0xFF + serial_exists = (inb(COM1+COM_LSR) != 0xFF); + (void) inb(COM1+COM_IIR); + (void) inb(COM1+COM_RX); + +} + + + +/***** Parallel port output code *****/ +// For information on PC parallel port programming, see the class References +// page. + +// Stupid I/O delay routine necessitated by historical PC design flaws +static void +delay(void) +{ + inb(0x84); + inb(0x84); + inb(0x84); + inb(0x84); +} + +static void +lpt_putc(int c) +{ + int i; + + for (i = 0; !(inb(0x378+1) & 0x80) && i < 12800; i++) + delay(); + outb(0x378+0, c); + outb(0x378+2, 0x08|0x04|0x01); + outb(0x378+2, 0x08); +} + + + + +/***** Text-mode CGA/VGA display output *****/ + +static unsigned addr_6845; +static uint16_t *crt_buf; +static uint16_t crt_pos; + +void +cga_init(void) +{ + volatile uint16_t *cp; + uint16_t was; + unsigned pos; + + cp = (uint16_t*) (KERNBASE + CGA_BUF); + was = *cp; + *cp = (uint16_t) 0xA55A; + if (*cp != 0xA55A) { + cp = (uint16_t*) (KERNBASE + MONO_BUF); + addr_6845 = MONO_BASE; + } else { + *cp = was; + addr_6845 = CGA_BASE; + } + + /* Extract cursor location */ + outb(addr_6845, 14); + pos = inb(addr_6845 + 1) << 8; + outb(addr_6845, 15); + pos |= inb(addr_6845 + 1); + + crt_buf = (uint16_t*) cp; + crt_pos = pos; +} + + + +void +cga_putc(int c) +{ + // if no attribute given, then use black on white + if (!(c & ~0xFF)) + c |= 0x0700; + + switch (c & 0xff) { + case '\b': + if (crt_pos > 0) { + crt_pos--; + crt_buf[crt_pos] = (c & ~0xff) | ' '; + } + break; + case '\n': + crt_pos += CRT_COLS; + /* fallthru */ + case '\r': + crt_pos -= (crt_pos % CRT_COLS); + break; + case '\t': + cons_putc(' '); + cons_putc(' '); + cons_putc(' '); + cons_putc(' '); + cons_putc(' '); + break; + default: + crt_buf[crt_pos++] = c; /* write the character */ + break; + } + + // What is the purpose of this? + if (crt_pos >= CRT_SIZE) { + int i; + + memmove(crt_buf, crt_buf + CRT_COLS, (CRT_SIZE - CRT_COLS) * sizeof(uint16_t)); + for (i = CRT_SIZE - CRT_COLS; i < CRT_SIZE; i++) + crt_buf[i] = 0x0700 | ' '; + crt_pos -= CRT_COLS; + } + + /* move that little blinky thing */ + outb(addr_6845, 14); + outb(addr_6845 + 1, crt_pos >> 8); + outb(addr_6845, 15); + outb(addr_6845 + 1, crt_pos); +} + + +/***** Keyboard input code *****/ + +#define NO 0 + +#define SHIFT (1<<0) +#define CTL (1<<1) +#define ALT (1<<2) + +#define CAPSLOCK (1<<3) +#define NUMLOCK (1<<4) +#define SCROLLLOCK (1<<5) + +#define E0ESC (1<<6) + +static uint8_t shiftcode[256] = +{ + [0x1D] CTL, + [0x2A] SHIFT, + [0x36] SHIFT, + [0x38] ALT, + [0x9D] CTL, + [0xB8] ALT +}; + +static uint8_t togglecode[256] = +{ + [0x3A] CAPSLOCK, + [0x45] NUMLOCK, + [0x46] SCROLLLOCK +}; + +static uint8_t normalmap[256] = +{ + NO, 0x1B, '1', '2', '3', '4', '5', '6', // 0x00 + '7', '8', '9', '0', '-', '=', '\b', '\t', + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', // 0x10 + 'o', 'p', '[', ']', '\n', NO, 'a', 's', + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', // 0x20 + '\'', '`', NO, '\\', 'z', 'x', 'c', 'v', + 'b', 'n', 'm', ',', '.', '/', NO, '*', // 0x30 + NO, ' ', NO, NO, NO, NO, NO, NO, + NO, NO, NO, NO, NO, NO, NO, '7', // 0x40 + '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', NO, NO, NO, NO, // 0x50 + [0xC7] KEY_HOME, [0x9C] '\n' /*KP_Enter*/, + [0xB5] '/' /*KP_Div*/, [0xC8] KEY_UP, + [0xC9] KEY_PGUP, [0xCB] KEY_LF, + [0xCD] KEY_RT, [0xCF] KEY_END, + [0xD0] KEY_DN, [0xD1] KEY_PGDN, + [0xD2] KEY_INS, [0xD3] KEY_DEL +}; + +static uint8_t shiftmap[256] = +{ + NO, 033, '!', '@', '#', '$', '%', '^', // 0x00 + '&', '*', '(', ')', '_', '+', '\b', '\t', + 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', // 0x10 + 'O', 'P', '{', '}', '\n', NO, 'A', 'S', + 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', // 0x20 + '"', '~', NO, '|', 'Z', 'X', 'C', 'V', + 'B', 'N', 'M', '<', '>', '?', NO, '*', // 0x30 + NO, ' ', NO, NO, NO, NO, NO, NO, + NO, NO, NO, NO, NO, NO, NO, '7', // 0x40 + '8', '9', '-', '4', '5', '6', '+', '1', + '2', '3', '0', '.', NO, NO, NO, NO, // 0x50 + [0xC7] KEY_HOME, [0x9C] '\n' /*KP_Enter*/, + [0xB5] '/' /*KP_Div*/, [0xC8] KEY_UP, + [0xC9] KEY_PGUP, [0xCB] KEY_LF, + [0xCD] KEY_RT, [0xCF] KEY_END, + [0xD0] KEY_DN, [0xD1] KEY_PGDN, + [0xD2] KEY_INS, [0xD3] KEY_DEL +}; + +#define C(x) (x - '@') + +static uint8_t ctlmap[256] = +{ + NO, NO, NO, NO, NO, NO, NO, NO, + NO, NO, NO, NO, NO, NO, NO, NO, + C('Q'), C('W'), C('E'), C('R'), C('T'), C('Y'), C('U'), C('I'), + C('O'), C('P'), NO, NO, '\r', NO, C('A'), C('S'), + C('D'), C('F'), C('G'), C('H'), C('J'), C('K'), C('L'), NO, + NO, NO, NO, C('\\'), C('Z'), C('X'), C('C'), C('V'), + C('B'), C('N'), C('M'), NO, NO, C('/'), NO, NO, + [0x97] KEY_HOME, + [0xB5] C('/'), [0xC8] KEY_UP, + [0xC9] KEY_PGUP, [0xCB] KEY_LF, + [0xCD] KEY_RT, [0xCF] KEY_END, + [0xD0] KEY_DN, [0xD1] KEY_PGDN, + [0xD2] KEY_INS, [0xD3] KEY_DEL +}; + +static uint8_t *charcode[4] = { + normalmap, + shiftmap, + ctlmap, + ctlmap +}; + +/* + * Get data from the keyboard. If we finish a character, return it. Else 0. + * Return -1 if no data. + */ +static int +kbd_proc_data(void) +{ + int c; + uint8_t data; + static uint32_t shift; + + if ((inb(KBSTATP) & KBS_DIB) == 0) + return -1; + + data = inb(KBDATAP); + + if (data == 0xE0) { + // E0 escape character + shift |= E0ESC; + return 0; + } else if (data & 0x80) { + // Key released + data = (shift & E0ESC ? data : data & 0x7F); + shift &= ~(shiftcode[data] | E0ESC); + return 0; + } else if (shift & E0ESC) { + // Last character was an E0 escape; or with 0x80 + data |= 0x80; + shift &= ~E0ESC; + } + + shift |= shiftcode[data]; + shift ^= togglecode[data]; + + c = charcode[shift & (CTL | SHIFT)][data]; + if (shift & CAPSLOCK) { + if ('a' <= c && c <= 'z') + c += 'A' - 'a'; + else if ('A' <= c && c <= 'Z') + c += 'a' - 'A'; + } + + // Process special keys + // Ctrl-Alt-Del: reboot + if (!(~shift & (CTL | ALT)) && c == KEY_DEL) { + cprintf("Rebooting!\n"); + outb(0x92, 0x3); // courtesy of Chris Frost + } + + return c; +} + +void +kbd_intr(void) +{ + cons_intr(kbd_proc_data); +} + +void +kbd_init(void) +{ +} + + + +/***** General device-independent console code *****/ +// Here we manage the console input buffer, +// where we stash characters received from the keyboard or serial port +// whenever the corresponding interrupt occurs. + +#define CONSBUFSIZE 512 + +static struct { + uint8_t buf[CONSBUFSIZE]; + uint32_t rpos; + uint32_t wpos; +} cons; + +// called by device interrupt routines to feed input characters +// into the circular console input buffer. +void +cons_intr(int (*proc)(void)) +{ + int c; + + while ((c = (*proc)()) != -1) { + if (c == 0) + continue; + cons.buf[cons.wpos++] = c; + if (cons.wpos == CONSBUFSIZE) + cons.wpos = 0; + } +} + +// return the next input character from the console, or 0 if none waiting +int +cons_getc(void) +{ + int c; + + // poll for any pending input characters, + // so that this function works even when interrupts are disabled + // (e.g., when called from the kernel monitor). + serial_intr(); + kbd_intr(); + + // grab the next character from the input buffer. + if (cons.rpos != cons.wpos) { + c = cons.buf[cons.rpos++]; + if (cons.rpos == CONSBUFSIZE) + cons.rpos = 0; + return c; + } + return 0; +} + +// output a character to the console +void +cons_putc(int c) +{ + lpt_putc(c); + cga_putc(c); +} + +// initialize the console devices +void +cons_init(void) +{ + cga_init(); + kbd_init(); + serial_init(); + + if (!serial_exists) + cprintf("Serial port does not exist!\n"); +} + + +// `High'-level console I/O. Used by readline and cprintf. + +void +cputchar(int c) +{ + cons_putc(c); +} + +int +getchar(void) +{ + int c; + + while ((c = cons_getc()) == 0) + /* do nothing */; + return c; +} + +int +iscons(int fdnum) +{ + // used by readline + return 1; +} diff --git a/kern/console.h b/kern/console.h new file mode 100644 index 0000000..d78a6e0 --- /dev/null +++ b/kern/console.h @@ -0,0 +1,27 @@ +/* See COPYRIGHT for copyright information. */ + +#ifndef _CONSOLE_H_ +#define _CONSOLE_H_ +#ifndef JOS_KERNEL +# error "This is a JOS kernel header; user programs should not #include it" +#endif + +#include + +#define MONO_BASE 0x3B4 +#define MONO_BUF 0xB0000 +#define CGA_BASE 0x3D4 +#define CGA_BUF 0xB8000 + +#define CRT_ROWS 25 +#define CRT_COLS 80 +#define CRT_SIZE (CRT_ROWS * CRT_COLS) + +void cons_init(void); +void cons_putc(int c); +int cons_getc(void); + +void kbd_intr(void); // irq 1 +void serial_intr(void); // irq 4 + +#endif /* _CONSOLE_H_ */ diff --git a/kern/entry.S b/kern/entry.S new file mode 100644 index 0000000..841564a --- /dev/null +++ b/kern/entry.S @@ -0,0 +1,104 @@ +/* See COPYRIGHT for copyright information. */ + +#include +#include + +# Shift Right Logical +#define SRL(val, shamt) (((val) >> (shamt)) & ~(-1 << (32 - (shamt)))) + + +################################################################### +# The kernel (this code) is linked at address ~(KERNBASE + 1 Meg), +# but the bootloader loads it at address ~1 Meg. +# +# RELOC(x) maps a symbol x from its link address to its actual +# location in physical memory (its load address). +################################################################### + +#define RELOC(x) ((x) - KERNBASE) + + +.set CODE_SEL,0x8 # index of code seg within mygdt +.set DATA_SEL,0x10 # index of data seg within mygdt + +#define MULTIBOOT_PAGE_ALIGN (1<<0) +#define MULTIBOOT_MEMORY_INFO (1<<1) +#define MULTIBOOT_HEADER_MAGIC (0x1BADB002) +#define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN) +#define CHECKSUM (-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)) + +################################################################### +# entry point +################################################################### + +.text + +# The Multiboot header +.align 4 +.long MULTIBOOT_HEADER_MAGIC +.long MULTIBOOT_HEADER_FLAGS +.long CHECKSUM + +.globl _start +_start: + movw $0x1234,0x472 # warm boot + + # Establish our own GDT in place of the boot loader's temporary GDT. + lgdt RELOC(mygdtdesc) # load descriptor table + + # Immediately reload all segment registers (including CS!) + # with segment selectors from the new GDT. + movl $DATA_SEL, %eax # Data segment selector + movw %ax,%ds # -> DS: Data Segment + movw %ax,%es # -> ES: Extra Segment + movw %ax,%ss # -> SS: Stack Segment + ljmp $CODE_SEL,$relocated # reload CS by jumping +relocated: + + # Clear the frame pointer register (EBP) + # so that once we get into debugging C code, + # stack backtraces will be terminated properly. + movl $0x0,%ebp # nuke frame pointer + + # Set the stack pointer + movl $(bootstacktop),%esp + + # now to C code + call i386_init + + # 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 bootstack +bootstack: + .space KSTKSIZE + .globl bootstacktop +bootstacktop: + +################################################################### +# setup the GDT +################################################################### + .p2align 2 # force 4 byte alignment +mygdt: + SEG_NULL # null seg + SEG(STA_X|STA_R, -KERNBASE, 0xffffffff) # code seg + SEG(STA_W, -KERNBASE, 0xffffffff) # data seg +mygdtdesc: + .word 0x17 # sizeof(mygdt) - 1 + .long RELOC(mygdt) # address mygdt + diff --git a/kern/init.c b/kern/init.c new file mode 100644 index 0000000..7ed1510 --- /dev/null +++ b/kern/init.c @@ -0,0 +1,95 @@ +/* See COPYRIGHT for copyright information. */ + +#include +#include +#include + +#include +#include + +// Test the stack backtrace function (lab 1 only) +void +test_backtrace(int x) +{ + cprintf("entering test_backtrace %d\n", x); + if (x > 0) + test_backtrace(x-1); + else + mon_backtrace(0, 0, 0); + cprintf("leaving test_backtrace %d\n", x); +} + +void +i386_init(void) +{ + extern char edata[], end[]; + + // Before doing anything else, complete the ELF loading process. + // Clear the uninitialized global data (BSS) section of our program. + // This ensures that all static/global variables start out zero. + memset(edata, 0, end - edata); + + // Initialize the console. + // Can't call cprintf until after we do this! + cons_init(); + + cprintf("6828 decimal is %o octal!\n", 6828); + + + + + + + + // Test the stack backtrace function (lab 1 only) + test_backtrace(5); + + // Drop into the kernel monitor. + while (1) + monitor(NULL); +} + + +/* + * Variable panicstr contains argument to first call to panic; used as flag + * to indicate that the kernel has already called panic. + */ +static const char *panicstr; + +/* + * Panic is called on unresolvable fatal errors. + * It prints "panic: mesg", and then enters the kernel monitor. + */ +void +_panic(const char *file, int line, const char *fmt,...) +{ + va_list ap; + + if (panicstr) + goto dead; + panicstr = fmt; + + va_start(ap, fmt); + cprintf("kernel panic at %s:%d: ", file, line); + vcprintf(fmt, ap); + cprintf("\n"); + va_end(ap); + +dead: + /* break into the kernel monitor */ + while (1) + monitor(NULL); +} + +/* like panic, but don't */ +void +_warn(const char *file, int line, const char *fmt,...) +{ + va_list ap; + + va_start(ap, fmt); + cprintf("kernel warning at %s:%d: ", file, line); + vcprintf(fmt, ap); + cprintf("\n"); + va_end(ap); +} diff --git a/kern/kernel.ld b/kern/kernel.ld new file mode 100644 index 0000000..16a4505 --- /dev/null +++ b/kern/kernel.ld @@ -0,0 +1,59 @@ +/* Simple linker script for the JOS kernel. + See the GNU ld 'info' manual ("info ld") to learn the syntax. */ + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + /* Load the kernel at this address: "." means the current address */ + . = 0xF0100000; + + .text : { + *(.text .stub .text.* .gnu.linkonce.t.*) + } + + PROVIDE(etext = .); /* Define the 'etext' symbol to this value */ + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + /* Include debugging information in kernel memory */ + .stab : { + PROVIDE(__STAB_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(edata = .); + + .bss : { + *(.bss) + } + + PROVIDE(end = .); + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack) + } +} diff --git a/kern/monitor.c b/kern/monitor.c new file mode 100644 index 0000000..374eae8 --- /dev/null +++ b/kern/monitor.c @@ -0,0 +1,137 @@ +// Simple command-line kernel monitor useful for +// controlling the kernel and exploring the system interactively. + +#include +#include +#include +#include +#include + +#include +#include + +#define CMDBUF_SIZE 80 // enough for one VGA text line + + +struct Command { + const char *name; + const char *desc; + // return -1 to force monitor to exit + int (*func)(int argc, char** argv, struct Trapframe* tf); +}; + +static struct Command commands[] = { + { "help", "Display this list of commands", mon_help }, + { "kerninfo", "Display information about the kernel", mon_kerninfo }, +}; +#define NCOMMANDS (sizeof(commands)/sizeof(commands[0])) + +unsigned read_eip(); + +/***** Implementations of basic kernel monitor commands *****/ + +int +mon_help(int argc, char **argv, struct Trapframe *tf) +{ + int i; + + for (i = 0; i < NCOMMANDS; i++) + cprintf("%s - %s\n", commands[i].name, commands[i].desc); + return 0; +} + +int +mon_kerninfo(int argc, char **argv, struct Trapframe *tf) +{ + extern char _start[], etext[], edata[], end[]; + + cprintf("Special kernel symbols:\n"); + cprintf(" _start %08x (virt) %08x (phys)\n", _start, _start - KERNBASE); + cprintf(" etext %08x (virt) %08x (phys)\n", etext, etext - KERNBASE); + cprintf(" edata %08x (virt) %08x (phys)\n", edata, edata - KERNBASE); + cprintf(" end %08x (virt) %08x (phys)\n", end, end - KERNBASE); + cprintf("Kernel executable memory footprint: %dKB\n", + (end-_start+1023)/1024); + return 0; +} + +int +mon_backtrace(int argc, char **argv, struct Trapframe *tf) +{ + // Your code here. + return 0; +} + + + +/***** Kernel monitor command interpreter *****/ + +#define WHITESPACE "\t\r\n " +#define MAXARGS 16 + +static int +runcmd(char *buf, struct Trapframe *tf) +{ + int argc; + char *argv[MAXARGS]; + int i; + + // Parse the command buffer into whitespace-separated arguments + argc = 0; + argv[argc] = 0; + while (1) { + // gobble whitespace + while (*buf && strchr(WHITESPACE, *buf)) + *buf++ = 0; + if (*buf == 0) + break; + + // save and scan past next arg + if (argc == MAXARGS-1) { + cprintf("Too many arguments (max %d)\n", MAXARGS); + return 0; + } + argv[argc++] = buf; + while (*buf && !strchr(WHITESPACE, *buf)) + buf++; + } + argv[argc] = 0; + + // Lookup and invoke the command + if (argc == 0) + return 0; + for (i = 0; i < NCOMMANDS; i++) { + if (strcmp(argv[0], commands[i].name) == 0) + return commands[i].func(argc, argv, tf); + } + cprintf("Unknown command '%s'\n", argv[0]); + return 0; +} + +void +monitor(struct Trapframe *tf) +{ + char *buf; + + cprintf("Welcome to the JOS kernel monitor!\n"); + cprintf("Type 'help' for a list of commands.\n"); + + + while (1) { + buf = readline("K> "); + if (buf != NULL) + if (runcmd(buf, tf) < 0) + break; + } +} + +// return EIP of caller. +// does not work if inlined. +// putting at the end of the file seems to prevent inlining. +unsigned +read_eip() +{ + uint32_t callerpc; + __asm __volatile("movl 4(%%ebp), %0" : "=r" (callerpc)); + return callerpc; +} diff --git a/kern/monitor.h b/kern/monitor.h new file mode 100644 index 0000000..0aa0f26 --- /dev/null +++ b/kern/monitor.h @@ -0,0 +1,19 @@ +#ifndef JOS_KERN_MONITOR_H +#define JOS_KERN_MONITOR_H +#ifndef JOS_KERNEL +# error "This is a JOS kernel header; user programs should not #include it" +#endif + +struct Trapframe; + +// Activate the kernel monitor, +// optionally providing a trap frame indicating the current state +// (NULL if none). +void monitor(struct Trapframe *tf); + +// Functions implementing monitor commands. +int mon_help(int argc, char **argv, struct Trapframe *tf); +int mon_kerninfo(int argc, char **argv, struct Trapframe *tf); +int mon_backtrace(int argc, char **argv, struct Trapframe *tf); + +#endif // !JOS_KERN_MONITOR_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/lib/printfmt.c b/lib/printfmt.c new file mode 100644 index 0000000..6aa8cc3 --- /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) + (uintptr_t) va_arg(ap, void *); + base = 16; + goto number; + + // (unsigned) hexadecimal + case 'x': + num = getuint(&ap, lflag); + base = 16; + number: + printnum(putch, putdat, num, base, width, padc); + break; + + // escaped '%' character + case '%': + putch(ch, putdat); + break; + + // unrecognized escape sequence - just print it literally + default: + putch('%', putdat); + for (fmt--; fmt[-1] != '%'; fmt--) + /* do nothing */; + break; + } + } +} + +void +printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vprintfmt(putch, putdat, fmt, ap); + va_end(ap); +} + +struct sprintbuf { + char *buf; + char *ebuf; + int cnt; +}; + +static void +sprintputch(int ch, struct sprintbuf *b) +{ + b->cnt++; + if (b->buf < b->ebuf) + *b->buf++ = ch; +} + +int +vsnprintf(char *buf, int n, const char *fmt, va_list ap) +{ + struct sprintbuf b = {buf, buf+n-1, 0}; + + if (buf == NULL || n < 1) + return -E_INVAL; + + // print the string to the buffer + vprintfmt((void*)sprintputch, &b, fmt, ap); + + // null terminate the buffer + *b.buf = '\0'; + + return b.cnt; +} + +int +snprintf(char *buf, int n, const char *fmt, ...) +{ + va_list ap; + int rc; + + va_start(ap, fmt); + rc = vsnprintf(buf, n, fmt, ap); + va_end(ap); + + return rc; +} + + diff --git a/lib/readline.c b/lib/readline.c new file mode 100644 index 0000000..7c631bd --- /dev/null +++ b/lib/readline.c @@ -0,0 +1,38 @@ +#include +#include + +#define BUFLEN 1024 +static char buf[BUFLEN]; + +char * +readline(const char *prompt) +{ + int i, c, echoing; + + if (prompt != NULL) + cprintf("%s", prompt); + + i = 0; + echoing = iscons(0); + while (1) { + c = getchar(); + if (c < 0) { + cprintf("read error: %e\n", c); + return NULL; + } else if (c >= ' ' && i < BUFLEN-1) { + if (echoing) + cputchar(c); + buf[i++] = c; + } else if (c == '\b' && i > 0) { + if (echoing) + cputchar(c); + i--; + } else if (c == '\n' || c == '\r') { + if (echoing) + cputchar(c); + buf[i] = 0; + return buf; + } + } +} + diff --git a/lib/string.c b/lib/string.c new file mode 100644 index 0000000..ebc7b63 --- /dev/null +++ b/lib/string.c @@ -0,0 +1,222 @@ +// 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, size_t size) +{ + int n; + + for (n = 0; size > 0 && *s != '\0'; s++, size--) + n++; + return n; +} + +char * +strcpy(char *dst, const char *src) +{ + char *ret; + + ret = dst; + while ((*dst++ = *src++) != '\0') + /* do nothing */; + return ret; +} + +char * +strncpy(char *dst, const char *src, size_t size) { + size_t i; + char *ret; + + ret = dst; + for (i = 0; i < size; i++) { + *dst++ = *src; + // If strlen(src) < size, null-pad 'dst' out to 'size' chars + if (*src != '\0') + src++; + } + return ret; +} + +size_t +strlcpy(char *dst, const char *src, size_t size) +{ + char *dst_in; + + dst_in = dst; + if (size > 0) { + while (--size > 0 && *src != '\0') + *dst++ = *src++; + *dst = '\0'; + } + return dst - dst_in; +} + +int +strcmp(const char *p, const char *q) +{ + while (*p && *p == *q) + p++, q++; + return (int) ((unsigned char) *p - (unsigned char) *q); +} + +int +strncmp(const char *p, const char *q, size_t n) +{ + while (n > 0 && *p && *p == *q) + n--, p++, q++; + if (n == 0) + return 0; + else + return (int) ((unsigned char) *p - (unsigned char) *q); +} + +// Return a pointer to the first occurrence of 'c' in 's', +// or a null pointer if the string has no 'c'. +char * +strchr(const char *s, char c) +{ + for (; *s; s++) + if (*s == c) + return (char *) s; + return 0; +} + +// Return a pointer to the first occurrence of 'c' in 's', +// or a pointer to the string-ending null character if the string has no 'c'. +char * +strfind(const char *s, char c) +{ + for (; *s; s++) + if (*s == c) + break; + return (char *) s; +} + + +void * +memset(void *v, int c, size_t n) +{ + char *p; + int m; + + p = v; + m = n; + while (--m >= 0) + *p++ = c; + + return v; +} + +/* no memcpy - use memmove instead */ + +void * +memmove(void *dst, const void *src, size_t n) +{ + const char *s; + char *d; + + s = src; + d = dst; + if (s < d && s + n > d) { + s += n; + d += n; + while (n-- > 0) + *--d = *--s; + } else + while (n-- > 0) + *d++ = *s++; + + return dst; +} + +/* sigh - gcc emits references to this for structure assignments! */ +/* it is *not* prototyped in inc/string.h - do not use directly. */ +void * +memcpy(void *dst, void *src, size_t n) +{ + return memmove(dst, src, n); +} + +int +memcmp(const void *v1, const void *v2, size_t n) +{ + const uint8_t *s1 = (const uint8_t *) v1; + const uint8_t *s2 = (const uint8_t *) v2; + + while (n-- > 0) { + if (*s1 != *s2) + return (int) *s1 - (int) *s2; + s1++, s2++; + } + + return 0; +} + +void * +memfind(const void *s, int c, size_t n) +{ + const void *ends = (const char *) s + n; + for (; s < ends; s++) + if (*(const unsigned char *) s == (unsigned char) c) + break; + return (void *) s; +} + +long +strtol(const char *s, char **endptr, int base) +{ + int neg = 0; + long val = 0; + + // gobble initial whitespace + while (*s == ' ' || *s == '\t') + s++; + + // plus/minus sign + if (*s == '+') + s++; + else if (*s == '-') + s++, neg = 1; + + // hex or octal base prefix + if ((base == 0 || base == 16) && (s[0] == '0' && s[1] == 'x')) + s += 2, base = 16; + else if (base == 0 && s[0] == '0') + s++, base = 8; + else if (base == 0) + base = 10; + + // digits + while (1) { + int dig; + + if (*s >= '0' && *s <= '9') + dig = *s - '0'; + else if (*s >= 'a' && *s <= 'z') + dig = *s - 'a' + 10; + else if (*s >= 'A' && *s <= 'Z') + dig = *s - 'A' + 10; + else + break; + if (dig >= base) + break; + s++, val = (val * base) + dig; + // we don't properly detect overflow! + } + + if (endptr) + *endptr = (char *) s; + return (neg ? -val : val); +} + diff --git a/mergedep.pl b/mergedep.pl new file mode 100644 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/user/testpmap.c b/user/testpmap.c new file mode 100644 index 0000000..f38cff5 --- /dev/null +++ b/user/testpmap.c @@ -0,0 +1,215 @@ +//#ifdef LAB >= 4 + +#include + +int sequence_length = 16; +int sequence[] = { 0, 1, 1, 2, 3, + 5, 8, 13, 21, 34, + 55, 89, 144, 233, 377, 610}; + +void +mark_page(int* pg, int i) { + memset(pg, 0, PGSIZE); + + // now dump a non-random sequence into the page + // offset by i + int j; + for (j = 0; j < sequence_length; j++) + pg[j] = i + sequence[j]; +} + +int +test_page(int* pg, int i) { + int j; + for (j = 0; j < sequence_length; j++) + if (pg[j] != i + sequence[j]) + return 1; + + return 0; +} + +void +print_marked_page(int* pg) { + int j; + for (j = 0; j < (sequence_length-1); j++) + cprintf("%d, ", pg[j]); + + cprintf("%d", pg[j]); +} + +void +print_expected_mark(int i) { + int j; + for (j = 0; j < (sequence_length-1); j++) + cprintf("%d, ", sequence[j]+i); + + cprintf("%d", sequence[j]+i); +} + +int n, va, r, initva, maxpa, maxva, maxnum, failures; +int *page_id; + +int +alloc_range(int initaddr, int maxpa, int startn) { + n = startn; + maxnum = maxpa / PGSIZE; + initva = initaddr; + maxva = initva + maxpa; + + cprintf ("[%08x] trying to alloc pages in range [%08x, %08x]\n", env->env_id, initva, maxva); + + // how many pages can I alloc? + // - limit to 256 M worth of pages + for (va = initva; va < maxva; va += PGSIZE, n++) { + // alloc a page + if ((r = sys_mem_alloc(0, va, PTE_P | PTE_U | PTE_W | PTE_AVAIL)) < 0) { + //cprintf("\nsys_mem_alloc failed: %e", r); + break; + } + + //page_id = (int*)va; + //*page_id = n; // mark this page... + //memset((int*)va, n, PGSIZE / sizeof(int)); + mark_page((int*)va, n); + + if ( (((va - initva) / PGSIZE) % 128) == 0) cprintf("."); + } + cprintf("\n"); + + cprintf("[%08x] able to allocate [%d] pages of requested [%d] pages\n", env->env_id, n, maxnum); + + maxva = va; + return n; +} + +int +test_range(int startva, int endva, int startn) { + int c; + cprintf("[%08x] testing pages in [%08x, %08x] to see if they look okay\n", env->env_id, startva, endva); + n = startn; + failures = 0; + for (va = startva, c = 0; va < endva; va += PGSIZE, n++, c++) { + page_id = (int*)va; + + if (test_page((int*)va, n)) { + cprintf("\n[%08x] unexpected value at [%08x]:\n {", env->env_id, va); + print_marked_page((int*)va); + cprintf("} should be\n {"); + print_expected_mark(n); + cprintf("}"); + + failures++; + } else { + Pte pte = vpt[VPN(va)]; + int perm = (PTE_U | PTE_P | PTE_W | PTE_AVAIL); + + if ((pte & perm) != perm) { + cprintf("\n[%08x] unexpected PTE permissions [04x] for address [%08x]\n {", env->env_id, pte & perm, va); + failures++; + } + + // cprintf("\n value at [%08x]: {", va); + //print_marked_page((int*)va); + //cprintf("} should be {"); + //print_expected_mark(n); + //cprintf("}"); + } + + if ( (((va - startva) / PGSIZE) % 128) == 0) cprintf("."); + //if ((va % PDMAP) == 0) cprintf("."); + } + cprintf("\n"); + + cprintf("[%08x] tested %d pages: %d failed assertions.\n", env->env_id, c, failures); + + return failures; +} + +void +unmap_range(int startva, int endva) { + cprintf("[%08x] unmapping range [%08x, %08x].\n", env->env_id, startva, endva); + int xva, z; + for (z=0, xva = startva; xva < endva; xva += PGSIZE, z++) { + sys_mem_unmap(0, xva); + } + cprintf("[%08x] unmapped %d pages.\n", env->env_id, z); +} + +int +duplicate_range(int startva, int dupeva, int nbytes) { + cprintf("[%08x] duplicating range [%08x, %08x] at [%08x, %08x]\n", + env->env_id, startva, startva+nbytes, dupeva, dupeva+nbytes); + int xva, r, k; + for (xva = 0, k = 0; xva < nbytes; xva += PGSIZE, k+=PGSIZE) { + if ((r = sys_mem_map(0, startva+xva, 0, dupeva+xva, PTE_P | PTE_U | PTE_W | PTE_USER)) < 0) { + cprintf ("[%08x] duplicate_range FAILURE: %e\n", env->env_id, r); + return r; + } + } + + return k; +} + +// This tries to stress test the pmap code... +// Not the most intelligent testing strategy, +// just hammer at it and see if it breaks. +void +umain(int argc, char **argv) +{ + int max, max2, k, j, i, dupesize, dupen; + + for (i = 0; i < 2; i++) { // might as well do this multiple times to stress the system... + cprintf("PMAPTEST[%08x] starting ROUND %d.\n", env->env_id, i); + + // Try to allocate as many pages as possible... + k = alloc_range(UTEXT+PDMAP, (256 * 1024 * 1024), 0); // alloc as many as possible + max = maxva; // save maximum memory size + test_range(UTEXT+PDMAP, max, 0); // test if all are unique pages + + // If we've corrupted kernel memory, a yield might expose a problem. + cprintf("PMAPTEST[%08x] yielding...\n", env->env_id); + sys_yield(); + cprintf("PMAPTEST[%08x] back.\n", env->env_id); + + // Free a couple of pages for use by page tables and other envs... + unmap_range(max-16 * PGSIZE, max); // free some pages so we have wiggle room, if extra + max -= 16 * PGSIZE; // pages are needed for page tables... + + // Unmap last 1024 pages and then try to reallocate them in the same place + unmap_range(max - PDMAP, max); // unmap last 1024 pages + j = alloc_range(max - PDMAP, PDMAP, 0); // try to realloc them (<1024 if other envs alloc'd) + max2 = maxva; // max2 <= max && max2 >= (max - PDMAP) + test_range(max - PDMAP, max2, 0); // test if new pages are unique + + // Create duplicate mappings of the last 1024 + dupesize = duplicate_range(max2-PDMAP, max+PDMAP, j*PGSIZE); // create duplicate mappings + test_range(max2-PDMAP, max2-PDMAP+dupesize, 0); // test lower mapping + test_range(max+PDMAP, max + PDMAP + dupesize, 0); // test upper mapping + dupen = *((int*)(max+PDMAP)); + + // Remove one of the duplicate mappings and then unmap and realloc the last 1024 pages + unmap_range(max2-PDMAP, max2-PDMAP+dupesize); // unmap lower mapping + j = alloc_range(max2-PDMAP, PDMAP, 0); // try to alloc something, should be below 1024 (really? other envs?) + unmap_range(max2-2*PDMAP, max2 - PDMAP); // free 1024 pages + j = alloc_range(max2-2*PDMAP, PDMAP, 0); // alloc new pages for free'd 1024 + //max2 = maxva; // max2 <= old_max2 - PDMAP + + // Test ranges... + test_range(UTEXT+PDMAP, max2-2*PDMAP, 0); // test entire lower range of pages + test_range(max2-2*PDMAP, maxva, 0); // test entire lower range of pages + test_range(max+PDMAP, max + PDMAP + dupesize, dupen); // test upper range + + // Free everything + unmap_range(UTEXT+PDMAP, maxva); + unmap_range(max+PDMAP, max+PDMAP+dupesize); + + //unmap_range(UTEXT+PDMAP, max); + } + +} + +//#endif + + + + diff --git a/user/user.ld b/user/user.ld new file mode 100644 index 0000000..18d949c --- /dev/null +++ b/user/user.ld @@ -0,0 +1,72 @@ +/* Simple linker script for JOS user-level programs. + See the GNU ld 'info' manual ("info ld") to learn the syntax. */ + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + /* Load programs at this address: "." means the current address */ + . = 0x800020; + + .text : { + *(.text .stub .text.* .gnu.linkonce.t.*) + } + + PROVIDE(etext = .); /* Define the 'etext' symbol to this value */ + + .rodata : { + *(.rodata .rodata.* .gnu.linkonce.r.*) + } + + /* Adjust the address for the data segment to the next page */ + . = ALIGN(0x1000); + + .data : { + *(.data) + } + + PROVIDE(edata = .); + + .bss : { + *(.bss) + } + + PROVIDE(end = .); + + + /* Place debugging symbols so that they can be found by + * the kernel debugger. + * Specifically, the four words at 0x200000 mark the beginning of + * the stabs, the end of the stabs, the beginning of the stabs + * string table, and the end of the stabs string table, respectively. + */ + + .stab_info 0x200000 : { + LONG(__STAB_BEGIN__); + LONG(__STAB_END__); + LONG(__STABSTR_BEGIN__); + LONG(__STABSTR_END__); + } + + .stab : { + __STAB_BEGIN__ = DEFINED(__STAB_BEGIN__) ? __STAB_BEGIN__ : .; + *(.stab); + __STAB_END__ = DEFINED(__STAB_END__) ? __STAB_END__ : .; + BYTE(0) /* Force the linker to allocate space + for this section */ + } + + .stabstr : { + __STABSTR_BEGIN__ = DEFINED(__STABSTR_BEGIN__) ? __STABSTR_BEGIN__ : .; + *(.stabstr); + __STABSTR_END__ = DEFINED(__STABSTR_END__) ? __STABSTR_END__ : .; + BYTE(0) /* Force the linker to allocate space + for this section */ + } + + /DISCARD/ : { + *(.eh_frame .note.GNU-stack) + } +} -- 2.11.4.GIT