Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

lab1

  • Loading branch information...
commit 52e7e6a514352acfd4746e8167ad305426086235 0 parents
@aclements aclements authored
Showing with 5,524 additions and 0 deletions.
  1. +30 −0 .gdbinit.tmpl
  2. +37 −0 CODING
  3. +199 −0 GNUmakefile
  4. +32 −0 boot/Makefrag
  5. +85 −0 boot/boot.S
  6. +125 −0 boot/main.c
  7. +23 −0 boot/sign.pl
  8. +20 −0 conf/env.mk
  9. +2 −0  conf/lab.mk
  10. +124 −0 grade-functions.sh
  11. +54 −0 grade-lab1.sh
  12. +229 −0 inc/COPYRIGHT
  13. +20 −0 inc/assert.h
  14. +65 −0 inc/elf.h
  15. +20 −0 inc/error.h
  16. +83 −0 inc/kbdreg.h
  17. +7 −0 inc/malloc.h
  18. +183 −0 inc/memlayout.h
  19. +319 −0 inc/mmu.h
  20. +219 −0 inc/queue.h
  21. +51 −0 inc/stab.h
  22. +14 −0 inc/stdarg.h
  23. +33 −0 inc/stdio.h
  24. +24 −0 inc/string.h
  25. +72 −0 inc/types.h
  26. +277 −0 inc/x86.h
  27. +155 −0 kern/COPYRIGHT
  28. +83 −0 kern/Makefrag
  29. +472 −0 kern/console.c
  30. +26 −0 kern/console.h
  31. +104 −0 kern/entry.S
  32. +1,059 −0 kern/entrypgdir.c
  33. +92 −0 kern/init.c
  34. +206 −0 kern/kdebug.c
  35. +20 −0 kern/kdebug.h
  36. +61 −0 kern/kernel.ld
  37. +138 −0 kern/monitor.c
  38. +19 −0 kern/monitor.h
  39. +37 −0 kern/printf.c
  40. +300 −0 lib/printfmt.c
  41. +38 −0 lib/readline.c
  42. +281 −0 lib/string.c
  43. +86 −0 mergedep.pl
30 .gdbinit.tmpl
@@ -0,0 +1,30 @@
+set $lastcs = -1
+
+define hook-stop
+ # There doesn't seem to be a good way to detect if we're in 16- or
+ # 32-bit mode, but we always run with CS == 8 in 32-bit mode.
+ if $cs == 8 || $cs == 27
+ if $lastcs != 8 && $lastcs != 27
+ set architecture i386
+ end
+ x/i $pc
+ else
+ if $lastcs == -1 || $lastcs == 8 || $lastcs == 27
+ set architecture i8086
+ end
+ # Translate the segment:offset into a physical address
+ printf "[%4x:%4x] ", $cs, $eip
+ x/i $cs*16+$eip
+ end
+ set $lastcs = $cs
+end
+
+echo + target remote localhost:1234\n
+target remote localhost:1234
+
+# If this fails, it's probably because your GDB doesn't support ELF.
+# Look at the tools page at
+# http://pdos.csail.mit.edu/6.828/2009/tools.html
+# for instructions on building GDB with ELF support.
+echo + symbol-file obj/kern/kernel\n
+symbol-file obj/kern/kernel
37 CODING
@@ -0,0 +1,37 @@
+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().
+
+The included .dir-locals.el file will automatically set up the basic
+indentation style in Emacs.
199 GNUmakefile
@@ -0,0 +1,199 @@
+#
+# 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
+
+-include conf/lab.mk
+
+-include conf/env.mk
+
+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
+
+# try to infer the correct QEMU
+ifndef QEMU
+QEMU := $(shell if which qemu > /dev/null; \
+ then echo qemu; exit; \
+ else \
+ qemu=/Applications/Q.app/Contents/MacOS/i386-softmmu.app/Contents/MacOS/i386-softmmu; \
+ if test -x $$qemu; then echo $$qemu; exit; fi; fi; \
+ echo "***" 1>&2; \
+ echo "*** Error: Couldn't find a working QEMU executable." 1>&2; \
+ echo "*** Is the directory containing the qemu binary in your PATH" 1>&2; \
+ echo "*** or have you tried setting the QEMU variable in conf/env.mk?" 1>&2; \
+ echo "***" 1>&2; exit 1)
+endif
+
+# try to generate a unique GDB port
+GDBPORT := $(shell expr `id -u` % 5000 + 25000)
+# QEMU's gdb stub command line changed in 0.11
+QEMUGDB = $(shell if $(QEMU) -nographic -help | grep -q '^-gdb'; \
+ then echo "-gdb tcp::$(GDBPORT)"; \
+ else echo "-s -p $(GDBPORT)"; fi)
+
+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 += -fno-omit-frame-pointer
+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)/net/%.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/kernel.img
+QEMUOPTS = -hda $(OBJDIR)/kern/kernel.img -serial mon:stdio $(QEMUEXTRA)
+
+.gdbinit: .gdbinit.tmpl
+ sed "s/localhost:1234/localhost:$(GDBPORT)/" < $^ > $@
+
+qemu: $(IMAGES)
+ $(QEMU) $(QEMUOPTS)
+
+qemu-nox: $(IMAGES)
+ @echo "***"
+ @echo "*** Use Ctrl-a x to exit qemu"
+ @echo "***"
+ $(QEMU) -nographic $(QEMUOPTS)
+
+qemu-gdb: $(IMAGES) .gdbinit
+ @echo "***"
+ @echo "*** Now run 'gdb'." 1>&2
+ @echo "***"
+ $(QEMU) $(QEMUOPTS) -S $(QEMUGDB)
+
+qemu-nox-gdb: $(IMAGES) .gdbinit
+ @echo "***"
+ @echo "*** Now run 'gdb'." 1>&2
+ @echo "***"
+ $(QEMU) -nographic $(QEMUOPTS) -S $(QEMUGDB)
+
+print-qemu:
+ @echo $(QEMU)
+
+print-gdbport:
+ @echo $(GDBPORT)
+
+print-qemugdb:
+ @echo $(QEMUGDB)
+
+# For deleting the build
+clean:
+ rm -rf $(OBJDIR) .gdbinit jos.in
+
+realclean: clean
+ rm -rf lab$(LAB).tar.gz jos.out
+
+distclean: realclean
+ rm -rf conf/gcc.mk
+
+grade: $(LABSETUP)grade-lab$(LAB).sh
+ @echo $(MAKE) clean
+ @$(MAKE) clean || \
+ (echo "'make clean' failed. HINT: Do you have another running instance of JOS?" && exit 1)
+ $(MAKE) all
+ sh $(LABSETUP)grade-lab$(LAB).sh
+
+handin: tarball
+ @echo Please visit http://pdos.csail.mit.edu/6.828/submit/
+ @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 '/\.git/' | grep -v 'lab[0-9].*\.tar\.gz'` | gzip > lab$(LAB)-handin.tar.gz
+
+
+# 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 distclean grade
32 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 -j .text $@.out $@
+ $(V)perl boot/sign.pl $(OBJDIR)/boot/boot
+
85 boot/boot.S
@@ -0,0 +1,85 @@
+#include <inc/mmu.h>
+
+# 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
+
125 boot/main.c
@@ -0,0 +1,125 @@
+#include <inc/x86.h>
+#include <inc/elf.h>
+
+/**********************************************************************
+ * This a dirt simple boot loader, whose sole job is to boot
+ * an ELF kernel image from the first IDE hard disk.
+ *
+ * DISK LAYOUT
+ * * This program(boot.S and main.c) is the bootloader. It should
+ * be stored in the first sector of the disk.
+ *
+ * * The 2nd sector onward holds the kernel image.
+ *
+ * * The kernel image must be in ELF format.
+ *
+ * BOOT UP STEPS
+ * * when the CPU boots it loads the BIOS into memory and executes it
+ *
+ * * the BIOS intializes devices, sets of the interrupt routines, and
+ * reads the first sector of the boot device(e.g., hard-drive)
+ * into memory and jumps to it.
+ *
+ * * Assuming this boot loader is stored in the first sector of the
+ * hard-drive, this code takes over...
+ *
+ * * control starts in boot.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++)
+ // p_pa is the load address of this segment (as well
+ // as the physical address)
+ readseg(ph->p_pa, ph->p_memsz, ph->p_offset);
+
+ // call the entry point from the ELF header
+ // note: does not return!
+ ((void (*)(void)) (ELFHDR->e_entry))();
+
+bad:
+ outw(0x8A00, 0x8A00);
+ outw(0x8A00, 0x8E00);
+ while (1)
+ /* do nothing */;
+}
+
+// Read 'count' bytes at 'offset' from kernel into physical address 'pa'.
+// Might copy more than asked
+void
+readseg(uint32_t pa, uint32_t count, uint32_t offset)
+{
+ uint32_t end_pa;
+
+ end_pa = pa + count;
+
+ // round down to sector boundary
+ pa &= ~(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 (pa < end_pa) {
+ // Since we haven't enabled paging yet and we're using
+ // an identity segment mapping (see boot.S), we can
+ // use physical addresses directly. This won't be the
+ // case once JOS enables the MMU.
+ readsect((uint8_t*) pa, offset);
+ pa += 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);
+}
+
23 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;
20 conf/env.mk
@@ -0,0 +1,20 @@
+# 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=''
+
+# If the makefile cannot find your QEMU binary, uncomment the
+# following line and set it to the full path to QEMU.
+#
+# QEMU=
2  conf/lab.mk
@@ -0,0 +1,2 @@
+LAB=1
+PACKAGEDATE=Tue Sep 6 13:28:58 EDT 2011
124 grade-functions.sh
@@ -0,0 +1,124 @@
+verbose=false
+
+if [ "x$1" = "x-v" ]
+then
+ verbose=true
+ out=/dev/stdout
+ err=/dev/stderr
+else
+ out=/dev/null
+ err=/dev/null
+fi
+
+if gmake --version >/dev/null 2>&1; then make=gmake; else make=make; fi
+
+#
+# QEMU
+#
+
+timeout=30
+preservefs=n
+qemu=`$make -s --no-print-directory print-qemu`
+gdbport=`$make -s --no-print-directory print-gdbport`
+qemugdb=`$make -s --no-print-directory print-qemugdb`
+brkfn=readline
+
+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
+}
+
+# Run QEMU with serial output redirected to jos.out. If $brkfn is
+# non-empty, wait until $brkfn is reached or $timeout expires, then
+# kill QEMU.
+run () {
+ qemuextra=
+ if [ "$brkfn" ]; then
+ qemuextra="-S $qemugdb"
+ fi
+
+ t0=`date +%s.%N 2>/dev/null`
+ (
+ ulimit -t $timeout
+ exec $qemu -nographic $qemuopts -serial file:jos.out -monitor null -no-reboot $qemuextra
+ ) >$out 2>$err &
+ PID=$!
+
+ # Wait for QEMU to start
+ sleep 1
+
+ if [ "$brkfn" ]; then
+ # Find the address of the kernel $brkfn function,
+ # which is typically what the kernel monitor uses to
+ # read commands interactively.
+ brkaddr=`grep " $brkfn\$" obj/kern/kernel.sym | sed -e's/ .*$//g'`
+
+ (
+ echo "target remote localhost:$gdbport"
+ echo "br *0x$brkaddr"
+ echo c
+ ) > jos.in
+ gdb -batch -nx -x jos.in > /dev/null 2>&1
+
+ # Make sure QEMU is dead. On OS X, exiting gdb
+ # doesn't always exit QEMU.
+ kill $PID > /dev/null 2>&1
+ fi
+}
+
+#
+# Scoring
+#
+
+pts=5
+part=0
+partpos=0
+total=0
+totalpos=0
+
+showpart () {
+ echo "Part $1 score: $part/$partpos"
+ echo
+ total=`expr $total + $part`
+ totalpos=`expr $totalpos + $partpos`
+ part=0
+ partpos=0
+}
+
+showfinal () {
+ total=`expr $total + $part`
+ totalpos=`expr $totalpos + $partpos`
+ echo "Score: $total/$totalpos"
+ if [ $total -lt $totalpos ]; then
+ exit 1
+ fi
+}
+
+passfailmsg () {
+ msg="$1"
+ shift
+ if [ $# -gt 0 ]; then
+ msg="$msg,"
+ fi
+
+ t1=`date +%s.%N 2>/dev/null`
+ time=`echo "scale=1; ($t1-$t0)/1" | sed 's/.N/.0/g' | bc 2>/dev/null`
+
+ echo $msg "$@" "(${time}s)"
+}
+
+pass () {
+ passfailmsg OK "$@"
+ part=`expr $part + $pts`
+ partpos=`expr $partpos + $pts`
+}
+
+fail () {
+ passfailmsg WRONG "$@"
+ partpos=`expr $partpos + $pts`
+ if $verbose; then
+ exit 1
+ fi
+}
+
54 grade-lab1.sh
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+qemuopts="-hda obj/kern/kernel.img"
+. ./grade-functions.sh
+
+
+$make
+
+check () {
+ pts=20
+ echo_n "Printf: "
+ if grep "6828 decimal is 15254 octal!" jos.out >/dev/null
+ then
+ pass
+ else
+ fail
+ fi
+
+ pts=10
+ echo "Backtrace:"
+ args=`grep "ebp f01.* eip f0100.* args" jos.out | awk '{ print $6 }'`
+ cnt=`echo $args | grep '^00000000 00000000 00000001 00000002 00000003 00000004 00000005' | wc -w`
+ echo_n " Count "
+ if [ $cnt -eq 8 ]
+ then
+ pass
+ else
+ fail
+ fi
+
+ cnt=`grep "ebp f01.* eip f0100.* args" jos.out | awk 'BEGIN { FS = ORS = " " }
+{ print $6 }
+END { printf("\n") }' | grep '^00000000 00000000 00000001 00000002 00000003 00000004 00000005' | wc -w`
+ echo_n " Args "
+ if [ $cnt -eq 8 ]; then
+ pass
+ else
+ fail "($args)"
+ fi
+
+ syms=`grep "kern/init.c:[0-9]*: *test_backtrace[+]" jos.out`
+ symcnt=`grep "kern/init.c:[0-9]*: *test_backtrace[+]" jos.out | wc -l`
+ echo_n " Symbols "
+ if [ $symcnt -eq 6 ]; then
+ pass
+ else
+ fail "($syms)"
+ fi
+}
+
+run
+check
+
+showfinal
229 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
+ */
+
20 inc/assert.h
@@ -0,0 +1,20 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifndef JOS_INC_ASSERT_H
+#define JOS_INC_ASSERT_H
+
+#include <inc/stdio.h>
+
+void _warn(const char*, int, const char*, ...);
+void _panic(const char*, int, const char*, ...) __attribute__((noreturn));
+
+#define warn(...) _warn(__FILE__, __LINE__, __VA_ARGS__)
+#define panic(...) _panic(__FILE__, __LINE__, __VA_ARGS__)
+
+#define assert(x) \
+ do { if (!(x)) panic("assertion failed: %s", #x); } while (0)
+
+// static_assert(x) will generate a compile-time error if 'x' is false.
+#define static_assert(x) switch (x) case 0: case (x):
+
+#endif /* !JOS_INC_ASSERT_H */
65 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 */
20 inc/error.h
@@ -0,0 +1,20 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifndef JOS_INC_ERROR_H
+#define JOS_INC_ERROR_H
+
+enum {
+ // Kernel error codes -- keep in sync with list in lib/printfmt.c.
+ E_UNSPECIFIED = 1, // Unspecified or unknown problem
+ E_BAD_ENV = 2, // Environment doesn't exist or otherwise
+ // cannot be used in requested action
+ E_INVAL = 3, // Invalid parameter
+ E_NO_MEM = 4, // Request failed due to memory shortage
+ E_NO_FREE_ENV = 5, // Attempt to create a new environment beyond
+ // the maximum allowed
+ E_FAULT = 6, // Memory fault
+
+ MAXERROR
+};
+
+#endif // !JOS_INC_ERROR_H */
83 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 */
7 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
183 inc/memlayout.h
@@ -0,0 +1,183 @@
+#ifndef JOS_INC_MEMLAYOUT_H
+#define JOS_INC_MEMLAYOUT_H
+
+#ifndef __ASSEMBLER__
+#include <inc/types.h>
+#include <inc/queue.h>
+#include <inc/mmu.h>
+#endif /* not __ASSEMBLER__ */
+
+/*
+ * This file contains definitions for memory management in our OS,
+ * which are relevant to both the kernel and user-mode software.
+ */
+
+// Global descriptor numbers
+#define GD_KT 0x08 // kernel text
+#define GD_KD 0x10 // kernel data
+#define GD_UT 0x18 // user text
+#define GD_UD 0x20 // user data
+#define GD_TSS 0x28 // Task segment selector
+
+/*
+ * Virtual memory map: Permissions
+ * kernel/user
+ *
+ * 4 Gig --------> +------------------------------+
+ * | | RW/--
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * : . :
+ * : . :
+ * : . :
+ * |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| RW/--
+ * | | RW/--
+ * | Remapped Physical Memory | RW/--
+ * | | RW/--
+ * KERNBASE -----> +------------------------------+ 0xf0000000
+ * | Cur. Page Table (Kern. RW) | RW/-- PTSIZE
+ * VPT,KSTACKTOP--> +------------------------------+ 0xefc00000 --+
+ * | Kernel Stack | RW/-- KSTKSIZE |
+ * | - - - - - - - - - - - - - - -| PTSIZE
+ * | Invalid Memory (*) | --/-- |
+ * ULIM ------> +------------------------------+ 0xef800000 --+
+ * | Cur. Page Table (User R-) | R-/R- PTSIZE
+ * UVPT ----> +------------------------------+ 0xef400000
+ * | RO PAGES | R-/R- PTSIZE
+ * UPAGES ----> +------------------------------+ 0xef000000
+ * | RO ENVS | R-/R- PTSIZE
+ * UTOP,UENVS ------> +------------------------------+ 0xeec00000
+ * UXSTACKTOP -/ | User Exception Stack | RW/RW PGSIZE
+ * +------------------------------+ 0xeebff000
+ * | Empty Memory (*) | --/-- PGSIZE
+ * USTACKTOP ---> +------------------------------+ 0xeebfe000
+ * | Normal User Stack | RW/RW PGSIZE
+ * +------------------------------+ 0xeebfd000
+ * | |
+ * | |
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * . .
+ * . .
+ * . .
+ * |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
+ * | Program Data & Heap |
+ * UTEXT --------> +------------------------------+ 0x00800000
+ * PFTEMP -------> | Empty Memory (*) | PTSIZE
+ * | |
+ * UTEMP --------> +------------------------------+ 0x00400000 --+
+ * | Empty Memory (*) | |
+ * | - - - - - - - - - - - - - - -| |
+ * | User STAB Data (optional) | PTSIZE
+ * USTABDATA ----> +------------------------------+ 0x00200000 |
+ * | Empty Memory (*) | |
+ * 0 ------------> +------------------------------+ --+
+ *
+ * (*) Note: The kernel ensures that "Invalid Memory" (ULIM) is *never*
+ * mapped. "Empty Memory" is normally unmapped, but user programs may
+ * map pages there if desired. JOS user programs map pages temporarily
+ * at UTEMP.
+ */
+
+
+// All physical memory mapped at this address
+#define KERNBASE 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 struct Page stores metadata for one physical page.
+ * Is it NOT the physical page itself, but there is a one-to-one
+ * correspondence between physical pages and struct Page's.
+ * 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 */
319 inc/mmu.h
@@ -0,0 +1,319 @@
+#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) ----/
+// \----------- VPN(la) -----------/
+//
+// The PDX, PTX, PGOFF, and VPN 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(pa) (((uintptr_t) (pa)) >> 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_G 0x100 // Global
+
+// 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_ALLOWED may be used in system calls.
+#define PTE_ALLOWED (PTE_AVAIL | PTE_P | PTE_W | PTE_U)
+
+// Address in page table or page directory entry
+#define PTE_ADDR(pte) ((physaddr_t) (pte) & ~0xFFF)
+
+// Control Register flags
+#define CR0_PE 0x00000001 // Protection Enable
+#define CR0_MP 0x00000002 // Monitor coProcessor
+#define CR0_EM 0x00000004 // Emulation
+#define CR0_TS 0x00000008 // Task Switched
+#define CR0_ET 0x00000010 // Extension Type
+#define CR0_NE 0x00000020 // Numeric Errror
+#define CR0_WP 0x00010000 // Write Protect
+#define CR0_AM 0x00040000 // Alignment Mask
+#define CR0_NW 0x20000000 // Not Writethrough
+#define CR0_CD 0x40000000 // Cache Disable
+#define CR0_PG 0x80000000 // Paging
+
+#define CR4_PCE 0x00000100 // Performance counter enable
+#define CR4_MCE 0x00000040 // Machine Check Enable
+#define CR4_PSE 0x00000010 // Page Size Extensions
+#define CR4_DE 0x00000008 // Debugging Extensions
+#define CR4_TSD 0x00000004 // Time Stamp Disable
+#define CR4_PVI 0x00000002 // Protected-Mode Virtual Interrupts
+#define CR4_VME 0x00000001 // V86 Mode Extensions
+
+// Eflags register
+#define FL_CF 0x00000001 // Carry Flag
+#define FL_PF 0x00000004 // Parity Flag
+#define FL_AF 0x00000010 // Auxiliary carry Flag
+#define FL_ZF 0x00000040 // Zero Flag
+#define FL_SF 0x00000080 // Sign Flag
+#define FL_TF 0x00000100 // Trap Flag
+#define FL_IF 0x00000200 // Interrupt Flag
+#define FL_DF 0x00000400 // Direction Flag
+#define FL_OF 0x00000800 // Overflow Flag
+#define FL_IOPL_MASK 0x00003000 // I/O Privilege Level bitmask
+#define FL_IOPL_0 0x00000000 // IOPL == 0
+#define FL_IOPL_1 0x00001000 // IOPL == 1
+#define FL_IOPL_2 0x00002000 // IOPL == 2
+#define FL_IOPL_3 0x00003000 // IOPL == 3
+#define FL_NT 0x00004000 // Nested Task
+#define FL_RF 0x00010000 // Resume Flag
+#define FL_VM 0x00020000 // Virtual 8086 mode
+#define FL_AC 0x00040000 // Alignment Check
+#define FL_VIF 0x00080000 // Virtual Interrupt Flag
+#define FL_VIP 0x00100000 // Virtual Interrupt Pending
+#define FL_ID 0x00200000 // ID flag
+
+// Page fault error codes
+#define FEC_PR 0x1 // Page fault caused by protection violation
+#define FEC_WR 0x2 // Page fault caused by a write
+#define FEC_U 0x4 // Page fault occured while in user mode
+
+
+/*
+ *
+ * Part 2. Segmentation data structures and constants.
+ *
+ */
+
+#ifdef __ASSEMBLER__
+
+/*
+ * Macros to build GDT entries in assembly.
+ */
+#define SEG_NULL \
+ .word 0, 0; \
+ .byte 0, 0, 0, 0
+#define SEG(type,base,lim) \
+ .word (((lim) >> 12) & 0xffff), ((base) & 0xffff); \
+ .byte (((base) >> 16) & 0xff), (0x90 | (type)), \
+ (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff)
+
+#else // not __ASSEMBLER__
+
+#include <inc/types.h>
+
+// Segment Descriptors
+struct Segdesc {
+ unsigned sd_lim_15_0 : 16; // Low bits of segment limit
+ unsigned sd_base_15_0 : 16; // Low bits of segment base address
+ unsigned sd_base_23_16 : 8; // Middle bits of segment base address
+ unsigned sd_type : 4; // Segment type (see STS_ constants)
+ unsigned sd_s : 1; // 0 = system, 1 = application
+ unsigned sd_dpl : 2; // Descriptor Privilege Level
+ unsigned sd_p : 1; // Present
+ unsigned sd_lim_19_16 : 4; // High bits of segment limit
+ unsigned sd_avl : 1; // Unused (available for software use)
+ unsigned sd_rsv1 : 1; // Reserved
+ unsigned sd_db : 1; // 0 = 16-bit segment, 1 = 32-bit segment
+ unsigned sd_g : 1; // Granularity: limit scaled by 4K when set
+ unsigned sd_base_31_24 : 8; // High bits of segment base address
+};
+// Null segment
+#define SEG_NULL (struct Segdesc){ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+// Segment that is loadable but faults when used
+#define SEG_FAULT (struct Segdesc){ 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 }
+// Normal segment
+#define SEG(type, base, lim, dpl) (struct Segdesc) \
+{ ((lim) >> 12) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff, \
+ type, 1, dpl, 1, (unsigned) (lim) >> 28, 0, 0, 1, 1, \
+ (unsigned) (base) >> 24 }
+#define SEG16(type, base, lim, dpl) (struct Segdesc) \
+{ (lim) & 0xffff, (base) & 0xffff, ((base) >> 16) & 0xff, \
+ type, 1, dpl, 1, (unsigned) (lim) >> 16, 0, 0, 1, 0, \
+ (unsigned) (base) >> 24 }
+
+#endif /* !__ASSEMBLER__ */
+
+// Application segment type bits
+#define STA_X 0x8 // Executable segment
+#define STA_E 0x4 // Expand down (non-executable segments)
+#define STA_C 0x4 // Conforming code segment (executable only)
+#define STA_W 0x2 // Writeable (non-executable segments)
+#define STA_R 0x2 // Readable (executable segments)
+#define STA_A 0x1 // Accessed
+
+// System segment type bits
+#define STS_T16A 0x1 // Available 16-bit TSS
+#define STS_LDT 0x2 // Local Descriptor Table
+#define STS_T16B 0x3 // Busy 16-bit TSS
+#define STS_CG16 0x4 // 16-bit Call Gate
+#define STS_TG 0x5 // Task Gate / Coum Transmitions
+#define STS_IG16 0x6 // 16-bit Interrupt Gate
+#define STS_TG16 0x7 // 16-bit Trap Gate
+#define STS_T32A 0x9 // Available 32-bit TSS
+#define STS_T32B 0xB // Busy 32-bit TSS
+#define STS_CG32 0xC // 32-bit Call Gate
+#define STS_IG32 0xE // 32-bit Interrupt Gate
+#define STS_TG32 0xF // 32-bit Trap Gate
+
+
+/*
+ *
+ * Part 3. Traps.
+ *
+ */
+
+#ifndef __ASSEMBLER__
+
+// Task state segment format (as described by the Pentium architecture book)
+struct Taskstate {
+ uint32_t ts_link; // Old ts selector
+ uintptr_t ts_esp0; // Stack pointers and segment selectors
+ uint16_t ts_ss0; // after an increase in privilege level
+ uint16_t ts_padding1;
+ uintptr_t ts_esp1;
+ uint16_t ts_ss1;
+ uint16_t ts_padding2;
+ uintptr_t ts_esp2;
+ uint16_t ts_ss2;
+ uint16_t ts_padding3;
+ physaddr_t ts_cr3; // Page directory base
+ uintptr_t ts_eip; // Saved state from last task switch
+ uint32_t ts_eflags;
+ uint32_t ts_eax; // More saved state (registers)
+ uint32_t ts_ecx;
+ uint32_t ts_edx;
+ uint32_t ts_ebx;
+ uintptr_t ts_esp;
+ uintptr_t ts_ebp;
+ uint32_t ts_esi;
+ uint32_t ts_edi;
+ uint16_t ts_es; // Even more saved state (segment selectors)
+ uint16_t ts_padding4;
+ uint16_t ts_cs;
+ uint16_t ts_padding5;
+ uint16_t ts_ss;
+ uint16_t ts_padding6;
+ uint16_t ts_ds;
+ uint16_t ts_padding7;
+ uint16_t ts_fs;
+ uint16_t ts_padding8;
+ uint16_t ts_gs;
+ uint16_t ts_padding9;
+ uint16_t ts_ldt;
+ uint16_t ts_padding10;
+ uint16_t ts_t; // Trap on task switch
+ uint16_t ts_iomb; // I/O map base address
+};
+
+// Gate descriptors for interrupts and traps
+struct Gatedesc {
+ unsigned gd_off_15_0 : 16; // low 16 bits of offset in segment
+ unsigned gd_ss : 16; // segment selector
+ unsigned gd_args : 5; // # args, 0 for interrupt/trap gates
+ unsigned gd_rsv1 : 3; // reserved(should be zero I guess)
+ unsigned gd_type : 4; // type(STS_{TG,IG32,TG32})
+ unsigned gd_s : 1; // must be 0 (system)
+ unsigned gd_dpl : 2; // descriptor(meaning new) privilege level
+ unsigned gd_p : 1; // Present
+ unsigned gd_off_31_16 : 16; // high bits of offset in segment
+};
+
+// Set up a normal interrupt/trap gate descriptor.
+// - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate.
+ // see section 9.6.1.3 of the i386 reference: "The difference between
+ // an interrupt gate and a trap gate is in the effect on IF (the
+ // interrupt-enable flag). An interrupt that vectors through an
+ // interrupt gate resets IF, thereby preventing other interrupts from
+ // interfering with the current interrupt handler. A subsequent IRET
+ // instruction restores IF to the value in the EFLAGS image on the
+ // stack. An interrupt through a trap gate does not change IF."
+// - 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 */
219 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_ */
51 inc/stab.h
@@ -0,0 +1,51 @@
+#ifndef JOS_STAB_H
+#define JOS_STAB_H
+#include <inc/types.h>
+
+// <inc/stab.h>
+// STABS debugging info
+
+// The JOS kernel debugger can understand some debugging information
+// in the STABS format. For more information on this format, see
+// http://sourceware.org/gdb/onlinedocs/stabs.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 */
14 inc/stdarg.h
@@ -0,0 +1,14 @@
+/* $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 __builtin_va_list va_list;
+
+#define va_start(ap, last) __builtin_va_start(ap, last)
+
+#define va_arg(ap, type) __builtin_va_arg(ap, type)
+
+#define va_end(ap) __builtin_va_end(ap)
+
+#endif /* !JOS_INC_STDARG_H */
33 inc/stdio.h
@@ -0,0 +1,33 @@
+#ifndef JOS_INC_STDIO_H
+#define JOS_INC_STDIO_H
+
+#include <inc/stdarg.h>
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif /* !NULL */
+
+// lib/stdio.c
+void cputchar(int c);
+int getchar(void);
+int iscons(int fd);
+
+// lib/printfmt.c
+void printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...);
+void vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list);
+int snprintf(char *str, int size, const char *fmt, ...);
+int vsnprintf(char *str, int size, const char *fmt, va_list);
+
+// lib/printf.c
+int cprintf(const char *fmt, ...);
+int vcprintf(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 */
24 inc/string.h
@@ -0,0 +1,24 @@
+#ifndef JOS_INC_STRING_H
+#define JOS_INC_STRING_H
+
+#include <inc/types.h>
+
+int strlen(const char *s);
+int strnlen(const char *s, size_t size);
+char * strcpy(char *dst, const char *src);
+char * strncpy(char *dst, const char *src, size_t size);
+size_t strlcpy(char *dst, const char *src, size_t size);
+int strcmp(const char *s1, const char *s2);
+int strncmp(const char *s1, const char *s2, size_t size);
+char * strchr(const char *s, char c);
+char * strfind(const char *s, char c);
+
+void * memset(void *dst, int c, size_t len);
+/* 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 */
72 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 */
277 inc/x86.h
@@ -0,0 +1,277 @@
+#ifndef JOS_INC_X86_H
+#define JOS_INC_X86_H
+
+#include <inc/types.h>
+
+static __inline void breakpoint(void) __attribute__((always_inline));
+static __inline uint8_t inb(int port) __attribute__((always_inline));
+static __inline void insb(int port, void *addr, int cnt) __attribute__((always_inline));
+static __inline uint16_t inw(int port) __attribute__((always_inline));
+static __inline void insw(int port, void *addr, int cnt) __attribute__((always_inline));
+static __inline uint32_t inl(int port) __attribute__((always_inline));
+static __inline void insl(int port, void *addr, int cnt) __attribute__((always_inline));
+static __inline void outb(int port, uint8_t data) __attribute__((always_inline));
+static __inline void outsb(int port, const void *addr, int cnt) __attribute__((always_inline));
+static __inline void outw(int port, uint16_t data) __attribute__((always_inline));
+static __inline void outsw(int port, const void *addr, int cnt) __attribute__((always_inline));
+static __inline void outsl(int port, const void *addr, int cnt) __attribute__((always_inline));
+static __inline void outl(int port, uint32_t data) __attribute__((always_inline));
+static __inline void invlpg(void *addr) __attribute__((always_inline));
+static __inline void lidt(void *p) __attribute__((always_inline));
+static __inline void lldt(uint16_t sel) __attribute__((always_inline));
+static __inline void ltr(uint16_t sel) __attribute__((always_inline));
+static __inline void lcr0(uint32_t val) __attribute__((always_inline));
+static __inline uint32_t rcr0(void) __attribute__((always_inline));
+static __inline uint32_t rcr2(void) __attribute__((always_inline));
+static __inline void lcr3(uint32_t val) __attribute__((always_inline));
+static __inline uint32_t rcr3(void) __attribute__((always_inline));
+static __inline void lcr4(uint32_t val) __attribute__((always_inline));
+static __inline uint32_t rcr4(void) __attribute__((always_inline));
+static __inline void tlbflush(void) __attribute__((always_inline));
+static __inline uint32_t read_eflags(void) __attribute__((always_inline));
+static __inline void write_eflags(uint32_t eflags) __attribute__((always_inline));
+static __inline uint32_t read_ebp(void) __attribute__((always_inline));
+static __inline uint32_t read_esp(void) __attribute__((always_inline));
+static __inline void cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp);
+static __inline uint64_t read_tsc(void) __attribute__((always_inline));
+
+static __inline void
+breakpoint(void)
+{
+ __asm __volatile("int3");
+}
+
+static __inline uint8_t
+inb(int port)
+{
+ uint8_t data;
+ __asm __volatile("inb %w1,%0" : "=a" (data) : "d" (port));
+ return data;
+}
+
+static __inline void
+insb(int port, void *addr, int cnt)
+{
+ __asm __volatile("cld\n\trepne\n\tinsb" :
+ "=D" (addr), "=c" (cnt) :
+ "d" (port), "0" (addr), "1" (cnt) :
+ "memory", "cc");
+}
+
+static __inline uint16_t
+inw(int port)
+{
+ uint16_t data;
+ __asm __volatile("inw %w1,%0" : "=a" (data) : "d" (port));
+ return data;
+}
+
+static __inline void
+insw(int port, void *addr, int cnt)
+{
+ __asm __volatile("cld\n\trepne\n\tinsw" :
+ "=D" (addr), "=c" (cnt) :
+ "d" (port), "0" (addr), "1" (cnt) :
+ "memory", "cc");
+}
+
+static __inline uint32_t
+inl(int port)
+{
+ uint32_t data;
+ __asm __volatile("inl %w1,%0" : "=a" (data) : "d" (port));
+ return data;
+}
+
+static __inline void
+insl(int port, void *addr, int cnt)
+{
+ __asm __volatile("cld\n\trepne\n\tinsl" :
+ "=D" (addr), "=c" (cnt) :
+ "d" (port), "0" (addr), "1" (cnt) :
+ "memory", "cc");
+}
+
+static __inline void
+outb(int port, uint8_t data)
+{
+ __asm __volatile("outb %0,%w1" : : "a" (data), "d" (port));
+}
+
+static __inline void
+outsb(int port, const void *addr, int cnt)
+{
+ __asm __volatile("cld\n\trepne\n\toutsb" :
+ "=S" (addr), "=c" (cnt) :
+ "d" (port), "0" (addr), "1" (cnt) :
+ "cc");
+}
+
+static __inline void
+outw(int port, uint16_t data)
+{
+ __asm __volatile("outw %0,%w1" : : "a" (data), "d" (port));
+}
+
+static __inline void
+outsw(int port, const void *addr, int cnt)
+{
+ __asm __volatile("cld\n\trepne\n\toutsw" :
+ "=S" (addr), "=c" (cnt) :
+ "d" (port), "0" (addr), "1" (cnt) :
+ "cc");
+}
+
+static __inline void
+outsl(int port, const void *addr, int cnt)
+{
+ __asm __volatile("cld\n\trepne\n\toutsl" :
+ "=S" (addr), "=c" (cnt) :
+ "d" (port), "0" (addr), "1" (cnt) :
+ "cc");
+}
+
+static __inline void
+outl(int port, uint32_t data)
+{
+ __asm __volatile("outl %0,%w1" : : "a" (data), "d" (port));
+}
+
+static __inline void
+invlpg(void *addr)
+{
+ __asm __volatile("invlpg (%0)" : : "r" (addr) : "memory");
+}
+
+static __inline void
+lidt(void *p)
+{
+ __asm __volatile("lidt (%0)" : : "r" (p));
+}
+
+static __inline void
+lldt(uint16_t sel)
+{
+ __asm __volatile("lldt %0" : : "r" (sel));
+}
+
+static __inline void
+ltr(uint16_t sel)
+{
+ __asm __volatile("ltr %0" : : "r" (sel));
+}
+
+static __inline void
+lcr0(uint32_t val)
+{
+ __asm __volatile("movl %0,%%cr0" : : "r" (val));
+}
+
+static __inline uint32_t
+rcr0(void)
+{
+ uint32_t val;
+ __asm __volatile("movl %%cr0,%0" : "=r" (val));
+ return val;
+}
+
+static __inline uint32_t
+rcr2(void)
+{
+ uint32_t val;
+ __asm __volatile("movl %%cr2,%0" : "=r" (val));
+ return val;
+}
+
+static __inline void
+lcr3(uint32_t val)
+{
+ __asm __volatile("movl %0,%%cr3" : : "r" (val));
+}
+
+static __inline uint32_t
+rcr3(void)
+{
+ uint32_t val;
+ __asm __volatile("movl %%cr3,%0" : "=r" (val));
+ return val;
+}
+
+static __inline void
+lcr4(uint32_t val)
+{
+ __asm __volatile("movl %0,%%cr4" : : "r" (val));
+}
+
+static __inline uint32_t
+rcr4(void)
+{
+ uint32_t cr4;
+ __asm __volatile("movl %%cr4,%0" : "=r" (cr4));
+ return cr4;
+}
+
+static __inline void
+tlbflush(void)
+{
+ uint32_t cr3;
+ __asm __volatile("movl %%cr3,%0" : "=r" (cr3));
+ __asm __volatile("movl %0,%%cr3" : : "r" (cr3));
+}
+
+static __inline uint32_t
+read_eflags(void)
+{
+ uint32_t eflags;
+ __asm __volatile("pushfl; popl %0" : "=r" (eflags));
+ return eflags;
+}
+
+static __inline void
+write_eflags(uint32_t eflags)
+{
+ __asm __volatile("pushl %0; popfl" : : "r" (eflags));
+}
+
+static __inline uint32_t
+read_ebp(void)
+{
+ uint32_t ebp;
+ __asm __volatile("movl %%ebp,%0" : "=r" (ebp));
+ return ebp;
+}
+
+static __inline uint32_t
+read_esp(void)
+{
+ uint32_t esp;
+ __asm __volatile("movl %%esp,%0" : "=r" (esp));
+ return esp;
+}
+
+static __inline void
+cpuid(uint32_t info, uint32_t *eaxp, uint32_t *ebxp, uint32_t *ecxp, uint32_t *edxp)
+{
+ uint32_t eax, ebx, ecx, edx;
+ asm volatile("cpuid"
+ : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+ : "a" (info));
+ if (eaxp)
+ *eaxp = eax;
+ if (ebxp)
+ *ebxp = ebx;
+ if (ecxp)
+ *ecxp = ecx;
+ if (edxp)
+ *edxp = edx;
+}
+
+static __inline uint64_t
+read_tsc(void)
+{
+ uint64_t tsc;
+ __asm __volatile("rdtsc" : "=A" (tsc));
+ return tsc;
+}
+
+#endif /* !JOS_INC_X86_H */
155 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