summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/bootstrap.h120
-rw-r--r--include/cio.h287
-rw-r--r--include/clock.h55
-rw-r--r--include/common.h31
-rw-r--r--include/compat.h131
-rw-r--r--include/debug.h324
-rw-r--r--include/defs.h129
-rw-r--r--include/elf.h235
-rw-r--r--include/kdefs.h146
-rw-r--r--include/klib.h57
-rw-r--r--include/kmem.h138
-rw-r--r--include/lib.h287
-rw-r--r--include/list.h68
-rw-r--r--include/params.h31
-rw-r--r--include/procs.h452
-rw-r--r--include/sio.h168
-rw-r--r--include/support.h87
-rw-r--r--include/syscalls.h80
-rw-r--r--include/types.h58
-rw-r--r--include/udefs.h113
-rw-r--r--include/ulib.h315
-rw-r--r--include/user.h138
-rw-r--r--include/userids.h33
-rw-r--r--include/vm.h433
-rw-r--r--include/vmtables.h43
-rw-r--r--include/x86/arch.h303
-rw-r--r--include/x86/bios.h73
-rw-r--r--include/x86/ops.h443
-rw-r--r--include/x86/pic.h139
-rw-r--r--include/x86/pit.h82
-rw-r--r--include/x86/uart.h349
31 files changed, 5348 insertions, 0 deletions
diff --git a/include/bootstrap.h b/include/bootstrap.h
new file mode 100644
index 0000000..ade778a
--- /dev/null
+++ b/include/bootstrap.h
@@ -0,0 +1,120 @@
+/*
+** SCCS ID: @(#)bootstrap.h 2.4 1/22/25
+**
+** @file bootstrap.h
+**
+** @author K. Reek
+** @author Warren R. Carithers, Garrett C. Smith
+**
+** Addresses where various stuff goes in memory.
+*/
+
+#ifndef BOOTSTRAP_H_
+#define BOOTSTRAP_H_
+
+/*
+** The boot device
+*/
+#define BDEV_FLOPPY 0x00
+#define BDEV_USB 0x80 /* hard drive */
+
+#define BDEV BDEV_USB /* default */
+
+/*
+** Bootstrap definitions
+*/
+#define BOOT_SEG 0x07c0 /* 07c0:0000 */
+#define BOOT_DISP 0x0000
+#define BOOT_ADDR ((BOOT_SEG << 4) + BOOT_DISP)
+
+#define PART2_DISP 0x0200 /* 07c0:0200 */
+#define PART2_ADDR ((BOOT_SEG << 4) + PART2_DISP)
+
+#define SECTOR_SIZE 0x200 /* 512 bytes */
+
+/* Note: this assumes the bootstrap is two sectors long! */
+#define BOOT_SIZE (SECTOR_SIZE + SECTOR_SIZE)
+
+#define OFFSET_LIMIT (0x10000 - SECTOR_SIZE)
+
+#define BOOT_SP_DISP 0x4000 /* stack pointer 07c0:4000, or 0xbc00 */
+#define BOOT_SP_ADDR ((BOOT_SEG << 4) + BOOT_SP_DISP)
+
+#define SECTOR1_END (BOOT_ADDR + SECTOR_SIZE)
+#define SECTOR2_END (BOOT_ADDR + BOOT_SIZE)
+
+// location of the user blob data
+// (three halfwords of data)
+#define USER_BLOB_DATA (SECTOR2_END - 12)
+
+/*
+** The target program itself
+*/
+#define TARGET_SEG 0x00001000 /* 1000:0000 */
+#define TARGET_ADDR 0x00010000 /* and upward */
+#define TARGET_STACK 0x00010000 /* and downward */
+
+/*
+** The Global Descriptor Table (0000:0500 - 0000:2500)
+*/
+#define GDT_SEG 0x00000050
+#define GDT_ADDR 0x00000500
+
+ /* segment register values */
+#define GDT_LINEAR 0x0008 /* All of memory, R/W */
+#define GDT_CODE 0x0010 /* All of memory, R/E */
+#define GDT_DATA 0x0018 /* All of memory, R/W */
+#define GDT_STACK 0x0020 /* All of memory, R/W */
+
+/*
+** The Interrupt Descriptor Table (0000:2500 - 0000:2D00)
+*/
+#define IDT_SEG 0x00000250
+#define IDT_ADDR 0x00002500
+
+/*
+** Additional I/O ports used by the bootstrap code
+*/
+
+// keyboard controller
+#define KBD_DATA 0x60
+#define KBD_CMD 0x64
+#define KBD_STAT 0x64
+
+// status register bits
+#define KBD_OBSTAT 0x01
+#define KBD_IBSTAT 0x02
+#define KBD_SYSFLAG 0x04
+#define KBD_CMDDAT 0x08
+
+// commands
+#define KBD_P1_DISABLE 0xad
+#define KBD_P1_ENABLE 0xae
+#define KBD_RD_OPORT 0xd0
+#define KBD_WT_OPORT 0xd1
+
+#ifdef ASM_SRC
+
+// segment descriptor macros for use in assembly source files
+// layout:
+// .word lower 16 bits of limit
+// .word lower 16 bits of base
+// .byte middle 8 bits of base
+// .byte type byte
+// .byte granularity byte
+// .byte upper 8 bits of base
+// we use 4K units, so we ignore the lower 12 bits of the limit
+#define SEGNULL \
+ .word 0, 0, 0, 0
+
+#define SEGMENT(base,limit,dpl,type) \
+ .word (((limit) >> 12) & 0xffff); \
+ .word ((base) & 0xffff) ; \
+ .byte (((base) >> 16) & 0xff) ; \
+ .byte (SEG_PRESENT | (dpl) | SEG_NON_SYSTEM | (type)) ; \
+ .byte (SEG_GRAN_4KBYTE | SEG_DB_32BIT | (((limit) >> 28) & 0xf)) ; \
+ .byte (((base) >> 24) & 0xff)
+
+#endif /* ASM_SRC */
+
+#endif
diff --git a/include/cio.h b/include/cio.h
new file mode 100644
index 0000000..1854f6e
--- /dev/null
+++ b/include/cio.h
@@ -0,0 +1,287 @@
+/**
+** SCCS ID: @(#)cio.h 2.7 1/22/25
+**
+** @file cio.h
+**
+** @author Warren R. Carithers
+** @authors K. Reek, Jon Coles
+**
+** Based on: c_io.c 1.13 (Ken Reek, Jon Coles, Warren R. Carithers)
+**
+** Declarations and descriptions of console I/O routines
+**
+** These routines provide a rudimentary capability for printing to
+** the screen and reading from the keyboard.
+**
+** Screen output:
+** There are two families of functions. The first provides a window
+** that behaves in the usual manner: writes extending beyond the right
+** edge of the window wrap around to the next line, the top line
+** scrolls off the window to make room for new lines at the bottom.
+** However, you may choose what part of the screen contains this
+** scrolling window. This allows you to print some text at fixed
+** locations on the screen while the rest of the screen scrolls.
+**
+** The second family allows for printing at fixed locations on the
+** screen. No scrolling or line wrapping are done for these functions.
+** It is not intended that these functions be used to write in the
+** scrolling area of the screen.
+**
+** In both sets of functions, the (x,y) coordinates are interpreted
+** as (column,row), with the upper left corner of the screen being
+** (0,0) and the lower right corner being (79,24).
+**
+** The printf provided in both sets of functions has the same
+** conversion capabilities. Format codes are of the form:
+**
+** %-0WC
+**
+** where "-", "0", and "W" are all optional:
+** "-" is the left-adjust flag (default is right-adjust)
+** "0" is the zero-fill flag (default is space-fill)
+** "W" is a number specifying the minimum field width (default: 1 )
+** and "C" is the conversion type, which must be one of these:
+** "c" print a single character
+** "s" print a null-terminated string
+** "d" print an integer as a decimal value
+** "x" print an integer as a hexadecimal value
+** "o" print an integer as a octal value
+**
+** Keyboard input:
+** Two functions are provided: getting a single character and getting
+** a newline-terminated line. A third function returns a count of
+** the number of characters available for immediate reading.
+** No conversions are provided (yet).
+*/
+
+#ifndef CIO_H_
+#define CIO_H_
+
+#ifndef ASM_SRC
+
+// EOT indicator (control-D)
+#define EOT '\04'
+
+/*****************************************************************************
+**
+** INITIALIZATION ROUTINES
+**
+** Initializes the I/O system.
+*/
+
+/**
+** cio_init
+**
+** Initializes the I/O routines. Must be called before
+** any CIO functions can be used.
+**
+** @param notify pointer to an input notification function, or NULL
+*/
+void cio_init( void (*notify)(int) );
+
+/*****************************************************************************
+**
+** SCROLLING OUTPUT ROUTINES
+**
+** Each operation begins at the current cursor position and advances
+** it. If a newline is output, the reminder of that line is cleared.
+** Output extending past the end of the line is wrapped. If the
+** cursor is moved below the scrolling region's bottom edge, scrolling
+** is delayed until the next output is produced.
+*/
+
+/**
+** cio_setscroll
+**
+** This sets the scrolling region to be the area defined by the arguments.
+** The remainder of the screen does not scroll and may be used to display
+** data you do not want to move. By default, the scrolling region is the
+** entire screen. X and Y coordinates begin at 0 in the upper left corner
+** of the screen.
+**
+** @param min_x,min_y upper-left corner of the region
+** @param max_x,max_y lower-right corner of the region
+*/
+void cio_setscroll( unsigned int min_x, unsigned int min_y,
+ unsigned int max_x, unsigned int max_y );
+
+/**
+** cio_moveto
+**
+** Moves the cursor to the specified position. (0,0) indicates
+** the upper left corner of the scrolling region. Subsequent
+** output will begin at the cursor position.
+**
+** @param x,y desired coordinate position
+*/
+void cio_moveto( unsigned int x, unsigned int y );
+
+/**
+** cio_putchar
+**
+** Prints a single character.
+**
+** @param c the character to be printed
+*/
+void cio_putchar( unsigned int c );
+
+/**
+** cio_puts
+**
+** Prints the characters in the string up to but not including
+** the terminating null byte.
+**
+** @param str pointer to a NUL-terminated string to be printed
+*/
+void cio_puts( const char *str );
+
+/**
+** cio_write
+**
+** Prints "length" characters from the buffer.
+**
+** @param buf the buffer of characters
+** @param length the number of characters to print
+*/
+void cio_write( const char *buf, int length );
+
+/**
+** cio_printf
+**
+** Limited form of printf (see the beginning of this file for
+** a list of what is implemented).
+**
+** @param fmt a printf-style format control string
+** @param ... optional additional values to be printed
+*/
+void cio_printf( char *fmt, ... );
+
+/**
+** cio_scroll
+**
+** Scroll the scrolling region up by the given number of lines.
+** The output routines scroll automatically so normally you
+** do not need to call this routine yourself.
+**
+** @param lines the number of lines to scroll
+*/
+void cio_scroll( unsigned int lines );
+
+/**
+** cio_clearscroll
+**
+** Clears the entire scrolling region to blank spaces, and
+** moves the cursor to (0,0).
+*/
+void cio_clearscroll( void );
+
+/*****************************************************************************
+**
+** NON-SCROLLING OUTPUT ROUTINES
+**
+** Coordinates are relative to the entire screen: (0,0) is the upper
+** left corner. There is no line wrap or scrolling.
+*/
+
+/**
+** cio_putchar_at
+**
+** Prints the given character. If a newline is printed,
+** the rest of the line is cleared. If this happens to the
+** left of the scrolling region, the clearing stops when the
+** region is reached. If this happens inside the scrolling
+** region, the clearing stops when the edge of the region
+** is reached.
+**
+** @param x,y desired coordinate position
+** @param c the character to be printed
+*/
+void cio_putchar_at( unsigned int x, unsigned int y, unsigned int c );
+
+/**
+** cio_puts_at
+**
+** Prints the given string. cio_putchar_at is used to print
+** the individual characters; see that description for details.
+**
+** @param x,y desired coordinate position
+** @param str pointer to a NUL-terminated string to be printed
+*/
+void cio_puts_at( unsigned int x, unsigned int y, const char *str );
+
+/**
+** cio_printf_at
+**
+** Limited form of printf (see the beginning of this file for
+** a list of what is implemented).
+**
+** @param x,y desired coordinate position
+** @param fmt a printf-style format control string
+** @param ... optional additional values to be printed
+*/
+void cio_printf_at( unsigned int x, unsigned int y, char *fmt, ... );
+
+/**
+** cio_clearscreen
+**
+** This function clears the entire screen, including the scrolling region.
+*/
+void cio_clearscreen( void );
+
+/*****************************************************************************
+**
+** INPUT ROUTINES
+**
+** When interrupts are enabled, a keyboard ISR collects keystrokes
+** and saves them until the program calls for them. If the input
+** queue fills, additional characters are silently discarded.
+** When interrupts are not enabled, keystrokes made when no input
+** routines have been ** called are lost. This can cause errors in
+** the input translation because the states of the Shift and Ctrl keys
+** may not be tracked accurately. If interrupts are disabled, the user
+** is advised to refrain from typing anything except when the program is
+** waiting for input.
+*/
+
+/**
+** cio_getchar
+**
+** If the character is not immediately available, the function
+** waits until the character arrives.
+**
+** @return the next character from the keyboard input buffer
+*/
+int cio_getchar( void );
+
+/**
+** cio_gets
+**
+** This function reads a newline-terminated line from the
+** keyboard. cio_getchar is used to obtain the characters;
+** see that description for more details. The function
+** returns when:
+** a newline is entered (this is stored in the buffer)
+** ctrl-D is entered (not stored in the buffer)
+** the buffer becomes full.
+** The buffer is null-terminated in all cases.
+**
+** @param buffer destination buffer for the input character sequence
+** @param size the buffer length
+**
+** @return count of the number of characters read into the buffer
+*/
+int cio_gets( char *buffer, unsigned int size );
+
+/**
+** cio_input_queue
+**
+** This function lets the program determine whether there is input
+** available. This indicates whether or not a call to cio_getchar()
+** would block.
+**
+** @return number of characters in the input queue
+*/
+int cio_input_queue( void );
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/clock.h b/include/clock.h
new file mode 100644
index 0000000..6eae41f
--- /dev/null
+++ b/include/clock.h
@@ -0,0 +1,55 @@
+/**
+** @file clock.h
+**
+** @author CSCI-452 class of 20245
+**
+** @brief Clock module declarations
+*/
+
+#ifndef CLOCK_H_
+#define CLOCK_H_
+
+#include <common.h>
+
+/*
+** General (C and/or assembly) definitions
+*/
+
+// conversion functions for seconds, ms, and ticks
+// (SEC_TO_MS is defined in defs.h)
+#define MS_TO_TICKS(n) ((n))
+#define SEC_TO_TICKS(n) (MS_TO_TICKS(SEC_TO_MS(n)))
+#define TICKS_TO_SEC(n) ((n) / CLOCK_FREQ)
+#define TICKS_TO_SEC_ROUNDED(n) (((n)+(CLOCK_FREQ-1)) / CLOCK_FREQ)
+
+#ifndef ASM_SRC
+
+/*
+** Start of C-only definitions
+*/
+
+/*
+** Types
+*/
+
+/*
+** Globals
+*/
+
+// current system time
+extern uint32_t system_time;
+
+/*
+** Prototypes
+*/
+
+/**
+** Name: clk_init
+**
+** Clock module initialization
+*/
+void clk_init( void );
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/common.h b/include/common.h
new file mode 100644
index 0000000..599c492
--- /dev/null
+++ b/include/common.h
@@ -0,0 +1,31 @@
+/**
+** @file common.h
+**
+** @author Warren R. Carithers
+**
+** @brief Common definitions for the baseline system.
+**
+** This header file pulls in the standard header information needed
+** by all parts of the system. It is purely for our convenience.
+*/
+
+#ifndef COMMON_H_
+#define COMMON_H_
+
+// everything needs these; they also pull in
+// the kernel- or user-level defs and lib headers
+#include <types.h>
+#include <params.h>
+#include <defs.h>
+#include <lib.h>
+
+#ifdef KERNEL_SRC
+
+// only kernel code needs these headers
+#include <common.h>
+#include <cio.h>
+#include <debug.h>
+
+#endif /* KERNEL_SRC */
+
+#endif
diff --git a/include/compat.h b/include/compat.h
new file mode 100644
index 0000000..ee62090
--- /dev/null
+++ b/include/compat.h
@@ -0,0 +1,131 @@
+/**
+** @file compat.h
+**
+** @author Warren R. Carithers
+**
+** @brief Compatibility definitions for standard modules.
+**
+** These definitions are here to simplify the integration
+** of some pre-written modules into the 452 baseline system.
+** This is used primarily for the 'kmem' and 'sio' modules.
+**
+** We use CPP symbols and not actual data types for things here,
+** as this means we don't need to include any other header files
+** into this file. This helps get around "include loops" (e.g.,
+** a.h includes b.h, which includes c.h, which includes a.h) when
+** there are many interdependencies between source files.
+*/
+
+#ifndef COMPAT_H_
+#define COMPAT_H_
+
+#include <common.h>
+#include <procs.h>
+
+/*
+** Section 1: sized integer types
+**
+** Internally, we use standard names for "sized" integer types for
+** simplicity. If those disagree with the names used in the rest of
+** the system, we take the opportunity to define our names here.
+**
+** To enable these, uncomment them, and place the apropriate
+** existing type names in place of the '?' characters.
+*/
+
+// standard "sized integer" types
+// #define int8_t ?
+// #define uint8_t ?
+// #define int16_t ?
+// #define uint16_t ?
+// #define int32_t ?
+// #define uint32_t ?
+// #define int64_t ?
+// #define uint64_t ?
+// #define bool_t ?
+
+/*
+** Section 2: other types
+**
+** Add type definitions here as needed.
+**
+** Note: we do not include the PCB and Queue declarations
+** here because we don't actually need them in this header
+** file - we're only defining CPP macros. Whatever file
+** uses these macros, however, must include the appropriate
+** headers if it uses these macros.
+**
+** To enable these, uncomment them, and place the apropriate
+** existing type names in place of the '?' characters.
+*/
+
+// type name for the PCB
+#define PCBTYPE pcb_t
+
+// type name for our queue
+#define QTYPE pcb_queue_t
+
+/*
+** Section 3: interface and behavior
+**
+** Include #define statements here as needed to define
+** the names of functions and globals used in these modules
+** in terms of the names used in the rest of the baseline.
+**
+** To enable these, uncomment them, and place the apropriate
+** existing variable or function names in place of the '?' characters.
+*/
+
+// string functions
+#define SLENGTH strlen
+
+// scheduler
+#define SCHED schedule
+
+// dispatcher
+#define DISPATCH dispatch
+
+/*
+** blocked queue for reading processes
+**
+** Define this if we are blocking processes which try to
+** read from the SIO when no characters are available.
+** Its value should be the name of the globally-visible
+** queue to be used.
+*/
+#define QNAME sioread
+
+#ifdef QNAME
+
+// Only define these macros if we need to be able to create and
+// manage a queue of things. It is expected that these will need
+// to be customized based on the names and calling sequences of
+// the appropriate functions.
+
+// invoke the queue creation function
+// examples:
+//
+// #define QCREATE(q) do {
+// _que_create( &(q), NULL );
+// } while(0)
+//
+// #define QCREATE(q) // do nothing
+
+#define QCREATE(q) // handled elsewhere for us
+
+// check to see if the queue is empty
+// examples:
+//
+// #define QEMPTY(q) queue_is_empty(q)
+// #define QEMPTY(q) (quene_length(q) > 0)
+#define QEMPTY(q) pcb_queue_empty(q)
+
+// this macro expands into code that removes a value from
+// 'q' and places it into 'd'
+#define QDEQUE(q,d) do { \
+ assert(pcb_queue_remove( (q), (pcb_t **) &(d) ) == SUCCESS ); \
+ } while(0)
+
+#endif /* QNAME */
+
+#endif
diff --git a/include/debug.h b/include/debug.h
new file mode 100644
index 0000000..c8ddfb4
--- /dev/null
+++ b/include/debug.h
@@ -0,0 +1,324 @@
+/**
+** @file debug.h
+**
+** @author Numerous CSCI-452 classes
+**
+** Debugging macros and constants.
+**
+*/
+
+#ifndef DEBUG_H_
+#define DEBUG_H_
+
+// Standard system headers
+
+#include <cio.h>
+#include <support.h>
+
+// Kernel library
+
+#include <lib.h>
+
+#ifndef ASM_SRC
+
+/*
+** Start of C-only definitions
+*/
+
+/*
+** General function entry/exit announcements
+*/
+
+#ifdef ANNOUNCE_ENTRY
+// Announce that we have entered a kernel function
+// usage: ENTERING( "name" ), EXITING( "name" )
+// currently, these do not use the macro parameter, but could be
+// modified to do so; instead, we use the __func__ CPP pseudo-macro
+// to get the function name
+#define ENTERING(n) do { cio_puts( " enter " __func__ ); } while(0)
+#define EXITING(n) do { cio_puts( " exit " __func__ ); } while(0)
+#else
+#define ENTERING(m) // do nothing
+#define EXITING(m) // do nothing
+#endif
+
+/*
+** Console messages when error conditions are noted.
+*/
+
+// Warning messages to the console
+// m: message (condition, etc.)
+#define WARNING(m) do { \
+ cio_printf( "\n** %s (%s @ %d): ", __func__, __FILE__, __LINE__ ); \
+ cio_puts( m ); \
+ cio_putchar( '\n' ); \
+ } while(0)
+
+// Panic messages to the console
+// n: severity level
+// m: message (condition, etc.)
+#define PANIC(n,m) do { \
+ sprint( b512, "%s (%s @ %d), %d: %s\n", \
+ __func__, __FILE__, __LINE__, n, # m ); \
+ kpanic( b512 ); \
+ } while(0)
+
+/*
+** Assertions are categorized by the "sanity level" being used in this
+** compilation; each only triggers a fault if the sanity level is at or
+** above a specific value. This allows selective enabling/disabling of
+** debugging checks.
+**
+** The sanity level is set during compilation with the CPP macro
+** "SANITY". A sanity level of 0 disables conditional assertions,
+** but not the basic assert() version.
+*/
+
+#ifndef SANITY
+// default sanity check level: check everything!
+#define SANITY 9999
+#endif
+
+// Always-active assertions
+#define assert(x) if( !(x) ) { PANIC(0,x); }
+
+// only provide these macros if the sanity check level is positive
+
+#if SANITY > 0
+
+#define assert1(x) if( SANITY >= 1 && !(x) ) { PANIC(1,x); }
+#define assert2(x) if( SANITY >= 2 && !(x) ) { PANIC(2,x); }
+#define assert3(x) if( SANITY >= 3 && !(x) ) { PANIC(3,x); }
+#define assert4(x) if( SANITY >= 4 && !(x) ) { PANIC(4,x); }
+// arbitrary sanity level
+#define assertN(n,x) if( SANITY >= (n) && !(x) ) { PANIC(n,x); }
+
+#else
+
+#define assert1(x) // do nothing
+#define assert2(x) // do nothing
+#define assert3(x) // do nothing
+#define assert4(x) // do nothing
+#define assertN(n,x) // do nothing
+
+#endif /* SANITY > 0 */
+
+/*
+** Tracing options are enabled by defining one or more of the T_
+** macros described in the Makefile.
+**
+** To add a tracing option:
+**
+** 1) Pick a short name for it (e.g., "PCB", "VM", ...)
+** 2) At the end of this list, add code like this, with "name"
+** replaced by your short name, and "nnnnnnnn" replaced by a
+** unique bit that will designate this tracing option:
+**
+** #ifdef T_name
+** #define TRname 0xnnnnnnnn
+** #else
+** #define TRname 0
+** #endif
+**
+** Use the next bit position following the one in last list entry.
+** 3) Add this to the end of the "TRACE" macro definition:
+**
+** | TRname
+**
+** 4) In the list of "TRACING_*" macros, add one for your option
+** (using a name that might be more descriptive) in the 'then' clause:
+**
+** #define TRACING_bettername ((TRACE & TRname) != 0)
+**
+** 5) Also add a "null" version in the 'else' clause:
+**
+** #define TRACING_bettername 0
+**
+** 6) Maybe add your T_name choice to the Makefile with an explanation
+** on the off chance you want anyone else to be able to understand
+** what it's used for. :-)
+**
+** We're making CPP work for its pay with this file.
+*/
+
+// 2^0 bit
+#ifdef T_PCB
+#define TRPCB 0x00000001
+#else
+#define TRPCB 0
+#endif
+
+#ifdef T_VM
+#define TRVM 0x00000002
+#else
+#define TRVM 0
+#endif
+
+#ifdef T_QUE
+#define TRQUEUE 0x00000004
+#else
+#define TRQUEUE 0
+#endif
+
+#ifdef T_SCH
+#define TRSCHED 0x00000008
+#else
+#define TRSCHED 0
+#endif
+
+// 2^4 bit
+#ifdef T_DSP
+#define TRDISP 0x00000010
+#else
+#define TRDISP 0
+#endif
+
+#ifdef T_SCALL
+#define TRSYSCALLS 0x00000020
+#else
+#define TRSYSCALLS 0
+#endif
+
+#ifdef T_SRET
+#define TRSYSRETS 0x00000040
+#else
+#define TRSYSRETS 0
+#endif
+
+#ifdef T_EXIT
+#define TREXIT 0x00000080
+#else
+#define TREXIT 0
+#endif
+
+// 2^8 bit
+#ifdef T_INIT
+#define TRINIT 0x00000100
+#else
+#define TRINIT 0
+#endif
+
+#ifdef T_KM
+#define TRKMEM 0x00000200
+#else
+#define TRKMEM 0
+#endif
+
+#ifdef T_KMFR
+#define TRKMEM_F 0x00000400
+#else
+#define TRKMEM_F 0
+#endif
+
+#ifdef T_KMIN
+#define TRKMEM_I 0x00000800
+#else
+#define TRKMEM_I 0
+#endif
+
+// 2^12 bit
+#ifdef T_FORK
+#define TRFORK 0x00001000
+#else
+#define TRFORK 0
+#endif
+
+#ifdef T_EXEC
+#define TREXEC 0x00002000
+#else
+#define TREXEC 0
+#endif
+
+#ifdef T_SIO
+#define TRSIO_STAT 0x00004000
+#else
+#define TRSIO_STAT 0
+#endif
+
+#ifdef T_SIOR
+#define TRSIO_RD 0x00008000
+#else
+#define TRSIO_RD 0
+#endif
+
+// 2^16 bit
+#ifdef T_SIOW
+#define TRSIO_WR 0x00010000
+#else
+#define TRSIO_WR 0
+#endif
+
+#ifdef T_USER
+#define TRUSER 0x00020000
+#else
+#define TRUSER 0
+#endif
+
+#ifdef T_ELF
+#define TRELF 0x00040000
+#else
+#define TRELF 0
+#endif
+
+// 13 bits remaining for tracing options
+// next available bit: 0x00080000
+
+#define TRACE (TRDISP | TREXIT | TRINIT | TRKMEM | TRKMEM_F | TRKMEM_I | TRPCB | TRQUEUE | TRSCHED | TREXEC | TRSIO_RD | TRSIO_STAT | TRSIO_WR | TRFORK | TRVM | TRSYSCALLS | TRSYSRETS | TRUSER | TRELF)
+
+#if TRACE > 0
+
+// compile-time expressions for testing trace options
+// usage: #if TRACING_thing
+#define TRACING_PCB ((TRACE & TRPCB) != 0)
+#define TRACING_VM ((TRACE & TRVM) != 0)
+#define TRACING_QUEUE ((TRACE & TRQUEUE) != 0)
+#define TRACING_SCHED ((TRACE & TRSCHED) != 0)
+#define TRACING_SYSCALLS ((TRACE & TRSYSCALLS) != 0)
+#define TRACING_SYSRETS ((TRACE & TRSYSRETS) != 0)
+#define TRACING_EXIT ((TRACE & TREXIT) != 0)
+#define TRACING_DISPATCH ((TRACE & TRDISPATCH) != 0)
+#define TRACING_INIT ((TRACE & TRINIT) != 0)
+#define TRACING_KMEM ((TRACE & TRKMEM) != 0)
+#define TRACING_KMEM_FREELIST ((TRACE & TRKMEM_F) != 0)
+#define TRACING_KMEM_INIT ((TRACE & TRKMEM_I) != 0)
+#define TRACING_SPAWN ((TRACE & TRSPAWN) != 0)
+#define TRACING_SIO_STAT ((TRACE & TRSIO_STAT) != 0)
+#define TRACING_SIO_ISR ((TRACE & TRSIO_ISR) != 0)
+#define TRACING_SIO_RD ((TRACE & TRSIO_RD) != 0)
+#define TRACING_SIO_WR ((TRACE & TRSIO_WR) != 0)
+#define TRACING_USER ((TRACE & TRUSER) != 0)
+#define TRACING_ELF ((TRACE & TRELF) != 0)
+
+#define TRACING_SOMETHING (TRACE != 0)
+
+#else
+
+// TRACE == 0, so just define these all as "false"
+
+#define TRACING_PCB 0
+#define TRACING_STACK 0
+#define TRACING_QUEUE 0
+#define TRACING_SCHED 0
+#define TRACING_SYSCALLS 0
+#define TRACING_SYSRET 0
+#define TRACING_EXIT 0
+#define TRACING_DISPATCH 0
+#define TRACING_INIT 0
+#define TRACING_KMEM 0
+#define TRACING_KMEM_FREELIST 0
+#define TRACING_KMEM_INIT 0
+#define TRACING_SPAWN 0
+#define TRACING_SI_STAT 0
+#define TRACING_SIO_ISR 0
+#define TRACING_SIO_RD 0
+#define TRACING_SIO_WR 0
+#define TRACING_USER 0
+#define TRACING_ELF 0
+
+#define TRACING_SOMETHING 0
+
+#endif /* TRACE */
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/defs.h b/include/defs.h
new file mode 100644
index 0000000..0280c47
--- /dev/null
+++ b/include/defs.h
@@ -0,0 +1,129 @@
+/**
+** @file defs.h
+**
+** @author Warren R. Carithers
+**
+** @brief Common definitions.
+**
+** This header file defines things which are neede by all
+** parts of the system (OS and user levels).
+**
+** Things which are kernel-specific go in the kdefs.h file;
+** things which are user-specific go in the udefs.h file.
+** The correct one of these will be automatically included
+** at the end of this file.
+*/
+
+#ifndef DEFS_H_
+#define DEFS_H_
+
+/*
+** General (C and/or assembly) definitions
+**
+** This section of the header file contains definitions that can be
+** used in either C or assembly-language source code.
+*/
+
+// NULL pointer value
+//
+// we define this the traditional way so that
+// it's usable from both C and assembly
+
+#define NULL 0
+
+// predefined i/o channels
+
+#define CHAN_CIO 0
+#define CHAN_SIO 1
+
+// maximum allowable number of command-line arguments
+#define MAX_ARGS 10
+
+// sizes of various things
+#define NUM_1KB 0x00000400 // 2^10
+#define NUM_4KB 0x00001000 // 2^12
+#define NUM_1MB 0x00100000 // 2^20
+#define NUM_4MB 0x00400000 // 2^22
+#define NUM_1GB 0x40000000 // 2^30
+#define NUM_2GB 0x80000000 // 2^31
+#define NUM_3GB 0xc0000000
+
+#ifndef ASM_SRC
+
+/*
+** Start of C-only definitions
+**
+** Anything that should not be visible to something other than
+** the C compiler should be put here.
+*/
+
+/*
+** System error codes
+**
+** These can be returned to both system functions
+** and to user system calls.
+*/
+ // success!
+#define SUCCESS (0)
+# define E_SUCCESS SUCCESS
+ // generic "something went wrong"
+#define E_FAILURE (-1)
+ // specific failure reasons
+#define E_BAD_PARAM (-2)
+#define E_BAD_CHAN (-3)
+#define E_NO_CHILDREN (-4)
+#define E_NO_MEMORY (-5)
+#define E_NOT_FOUND (-6)
+#define E_NO_PROCS (-7)
+
+/*
+** These error codes are internal to the OS.
+*/
+#define E_EMPTY_QUEUE (-100)
+#define E_NO_PCBS (-101)
+#define E_NO_PTE (-102)
+#define E_LOAD_LIMIT (-103)
+
+// exit status values
+#define EXIT_SUCCESS (0)
+#define EXIT_FAILURE (-1)
+#define EXIT_KILLED (-101)
+#define EXIT_BAD_SYSCALL (-102)
+
+/*
+** Process priority values
+*/
+enum priority_e {
+ PRIO_HIGH, PRIO_STD, PRIO_LOW, PRIO_DEFERRED
+ // sentinel
+ , N_PRIOS
+};
+
+// halves of various data sizes
+
+#define UI16_UPPER 0xff00
+#define UI16_LOWER 0x00ff
+
+#define UI32_UPPER 0xffff0000
+#define UI32_LOWER 0x0000ffff
+
+#define UI64_UPPER 0xffffffff00000000LL
+#define UI64_LOWER 0x00000000ffffffffLL
+
+// Simple conversion pseudo-functions usable by everyone
+
+// convert seconds to ms
+#define SEC_TO_MS(n) ((n) * 1000)
+
+#endif /* !ASM_SRC */
+
+/*
+** Level-specific definitions
+*/
+#ifdef KERNEL_SRC
+#include <kdefs.h>
+#else
+#include <udefs.h>
+#endif /* KERNEL_SRC */
+
+#endif
diff --git a/include/elf.h b/include/elf.h
new file mode 100644
index 0000000..a43e5c3
--- /dev/null
+++ b/include/elf.h
@@ -0,0 +1,235 @@
+/**
+** @file elf.h
+**
+** @author Warren R. Carithers
+**
+** @brief ELF format declarations
+*/
+
+#ifndef ELF_H_
+#define ELF_H_
+
+#include <common.h>
+
+#ifndef ASM_SRC
+
+/*
+** Start of C-only definitions
+*/
+
+// ELF data types (TIS ELF Spec v1.2, May 1995
+typedef uint32_t e32_a; // 32-bit unsigned address
+typedef uint16_t e32_h; // 16-bit unsigned "medium" integer
+typedef uint32_t e32_o; // 32-bit unsigned offset
+typedef int32_t e32_sw; // 32-bit signed "large" integer
+typedef uint32_t e32_w; // 32-bit unsigned "large" integer
+typedef uint8_t e32_si; // 8-bit unsigned "small" integer
+
+// ELF magic number - first four bytes
+#define ELF_MAGIC 0x464C457FU // "\x7FELF" in little-endian order
+#define EI_NIDENT 16
+
+union elfident_u {
+ uint8_t bytes[EI_NIDENT]; // array of 16 bytes
+ struct {
+ uint32_t magic; // magic number
+ uint8_t class; // file class
+ uint8_t data; // data encoding
+ uint8_t version; // file version
+ uint8_t osabi; // OS ABI identification
+ uint8_t abivers; // ABI version
+ uint8_t pad[7]; // padding to 16 bytes
+ } f;
+};
+
+// indices for byte fields in the ident array
+#define EI_MAGIC 0
+# define EI_MAG0 EI_MAGIC
+# define EI_MAG1 1
+# define EI_MAG2 2
+# define EI_MAG3 3
+#define EI_CLASS 4
+#define EI_DATA 5
+#define EI_VERSION 6
+#define EI_OSABI 7
+#define EI_ABIVERSION 8
+
+// ELF classes
+#define ELF_CLASS_NONE 0
+#define ELF_CLASS_32 1 // 32-bit objects
+#define ELF_CLASS_64 2 // 64-bit objects
+
+// ELF data encoding
+#define ELF_DATA_NONE 0 // invalid data encoding
+#define ELF_DATA_2LSB 1 // two's complement little-endian
+#define ELF_DATA_2MSB 2 // two's complement big-endian
+
+// ELF versions
+#define ELF_VERSION__NONE 0 // invalid version
+# define EV_NONE ELF_VERSION_NONE
+#define ELF_VERSION__CURRENT 1 // current version
+# define EV_CURRENT ELF_VERSION_CURRENT
+
+// ELF header
+//
+// field names are from the TIS ELF Spec v1.2, May 1995
+typedef struct elfhdr_s {
+ union elfident_u e_ident; // file identification
+ e32_h e_type; // file type
+ e32_h e_machine; // required architecture
+ e32_w e_version; // object file version
+ e32_a e_entry; // entry point (VA)
+ e32_o e_phoff; // offset to program header table (PHT)
+ e32_o e_shoff; // offset to section header table (SHT)
+ e32_w e_flags; // processor-specific flags
+ e32_h e_ehsize; // ELF header size (bytes)
+ e32_h e_phentsize; // size of one PHT entry (bytes)
+ e32_h e_phnum; // number of PHT entries
+ e32_h e_shentsize; // size of one SHT entry (bytes)
+ e32_h e_shnum; // number of SHT entries
+ e32_h e_shstrndx; // SHT index of the sect. name string table
+} elfhdr_t;
+
+#define SZ_ELFHDR sizeof(elfhdr_t)
+
+// field values
+// e_type
+#define ET_NONE 0 // no file type
+#define ET_REL 1 // relocatable file
+#define ET_EXEC 2 // executable file
+#define ET_DYN 3 // shared object file
+#define ET_CORE 4 // core file
+#define ET_LO_OS 0xfe00 // processor-specific
+#define ET_HI_OS 0xfeff // processor-specific
+#define ET_LO_CP 0xff00 // processor-specific
+#define ET_HI_CP 0xffff // processor-specific
+
+// e_machine
+#define EM_NONE 0x00 // no machine type
+#define EM_M32 0x01 // AT&T WE 32100
+#define EM_SPARC 0x02 // SUN SPARC
+#define EM_386 0x03 // Intel Architecture
+#define EM_68K 0x04 // Motorola 68000
+#define EM_88K 0x05 // Motorola 88000
+#define EM_IAMCU 0x06 // Intel MCU
+#define EM_860 0x07 // Intel 80860
+#define EM_MIPS 0x08 // MIPS RS3000 Big-Endian
+#define EM_S370 0x09 // IBM System/370
+#define EM_MIPS_RS3_LE 0x0a // MIPS RS3000 Big-Endian
+#define EM_SPARC32PLLUS 0x12 // Sun "v8plus"
+#define EM_PPC 0x14 // IBM PowerPC
+#define EM_PPC64 0x15 // IBM PowerPC 64-bit
+#define EM_S390 0x16 // IBM System/390
+#define EM_ARM 0x28 // ARM up to V7/AArch32
+#define EM_SPARCV9 0x2b // SPARC V9 64-bit
+#define EM_IA_64 0x32 // Intel Itanium (Merced)
+#define EM_MIPS_X 0x32 // Stanford MIPS-X
+#define EM_X86_64 0x3E // AMD x86-64 (Intel64)
+#define EM_PDP11 0x40 // DEC PDP-11
+#define EM_VAX 0x4b // DEC VAX
+#define EM_AARCH64 0xb7 // ARM AArch64
+#define EM_Z80 0xec // Zilog Z-80
+#define EM_AMDGPU 0xf0 // AMD GPU
+#define EM_RISCV 0xf3 // RISC-V
+#define EM_BPF 0xf7 // Berkeley Packet Filter
+
+// ELF section header
+//
+// field names are from the TIS ELF Spec v1.2, May 1995
+typedef struct shdr_s {
+ e32_w sh_name; // section name (index into string table)
+ e32_w sh_type; // section contents/semantics
+ e32_w sh_flags; // attribute flag bits
+ e32_a sh_addr; // 0, or load point of this section in memory
+ e32_o sh_offset; // byte offset within the file
+ e32_w sh_size; // section size in bytes
+ e32_w sh_link; // section header index table link
+ e32_w sh_info; // "extra information"
+ e32_w sh_addralign; // required alignment
+ e32_w sh_entsize; // 0, or size of each entry in the section
+} elfsecthdr_t;
+
+#define SZ_ELFSECTHDR sizeof(elfsecthdr_t)
+
+// sh_name
+#define SHN_UNDEF 0
+
+// sh_type
+#define SHT_NULL 0x00
+#define SHT_PROGBITS 0x01
+#define SHT_SYMTAB 0x02
+#define SHT_STRTAB 0x03
+#define SHT_RELA 0x04
+#define SHT_HASH 0x05
+#define SHT_DYNAMIC 0x06
+#define SHT_NOTE 0x07
+#define SHT_NOBITS 0x08
+#define SHT_REL 0x09
+#define SHT_SHLIB 0x0a
+#define SHT_DYNSYM 0x0b
+#define SHT_LO_CP 0x70000000
+#define SHT_HI_CP 0x7fffffff
+#define SHT_LO_US 0x80000000
+#define SHT_HI_US 0x8fffffff
+
+// sh_flags
+#define SHF_WRITE 0x001
+#define SHF_ALLOC 0x002
+#define SHF_EXECINSTR 0x004
+#define SHF_MERGE 0x010
+#define SHF_STRINGS 0x020
+#define SHF_INFO_LINK 0x040
+#define SHF_LINK_ORDER 0x080
+#define SHF_OS_NONCON 0x100
+#define SHF_GROUP 0x200
+#define SHF_TLS 0x400
+#define SHF_MASKOS 0x0ff00000
+#define SHF_MASKPROC 0xf0000000
+
+// ELF program header
+//
+// field names are from the TIS ELF Spec v1.2, May 1995
+typedef struct phdr_s {
+ e32_w p_type; // type of segment
+ e32_o p_offset; // byte offset in file
+ e32_a p_va; // load point in memory (virtual address)
+ e32_a p_pa; // load point in memory (physical address)
+ e32_w p_filesz; // number of bytes in this file
+ e32_w p_memsz; // number of bytes in memory
+ e32_w p_flags; // attribute flag bits
+ e32_w p_align; // required alignment
+} elfproghdr_t;
+
+#define SZ_ELFPROGHDR sizeof(elfproghdr_t)
+
+// p_type
+#define PT_NULL 0
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_TLS 7
+#define PT_LO_OS 0x70000000
+#define PT_HI_OS 0x7fffffff
+#define PT_LO_CP 0x70000000
+#define PT_HI_CP 0x7fffffff
+
+// p_flags
+#define PF_E 0x1
+#define PF_W 0x2
+#define PF_R 0x4
+#define PF_MASKPROC 0xf0000000
+
+/*
+** Globals
+*/
+
+/*
+** Prototypes
+*/
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/kdefs.h b/include/kdefs.h
new file mode 100644
index 0000000..f9fe853
--- /dev/null
+++ b/include/kdefs.h
@@ -0,0 +1,146 @@
+/**
+** @file kdefs.h
+**
+** @author CSCI-452 class of 20245
+**
+** @brief Kernel-only declarations.
+*/
+
+#ifndef KDEFS_H_
+#define KDEFS_H_
+
+// debugging macros
+#include <debug.h>
+
+/*
+** General (C and/or assembly) definitions
+*/
+
+// page sizes
+#define SZ_PAGE NUM_4KB
+#define SZ_BIGPAGE NUM_4MB
+
+// kernel stack size (bytes)
+#define N_KSTKPAGES 1
+#define SZ_KSTACK (N_KSTKPAGES * SZ_PAGE)
+
+// user stack size
+#define N_USTKPAGES 2
+#define SZ_USTACK (N_USTKPAGES * SZ_PAGE)
+
+// declarations for modulus checking of (e.g.) sizes and addresses
+
+#define MOD4_BITS 0x00000003
+#define MOD4_MASK 0xfffffffc
+#define MOD4_INC 0x00000004
+#define MOD4_SHIFT 2
+
+#define MOD16_BITS 0x0000000f
+#define MOD16_MASK 0xfffffff0
+#define MOD16_INC 0x00000010
+#define MOD16_SHIFT 4
+
+#define MOD1K_BITS 0x000003ff
+#define MOD1K_MASK 0xfffffc00
+#define MOD1K_INC 0x00000400
+#define MOD1K_SHIFT 10
+
+#define MOD4K_BITS 0x00000fff
+#define MOD4K_MASK 0xfffff000
+#define MOD4K_INC 0x00001000
+#define MOD4K_SHIFT 12
+
+#define MOD1M_BITS 0x000fffff
+#define MOD1M_MASK 0xfff00000
+#define MOD1M_INC 0x00100000
+#define MOD1M_SHIFT 20
+
+#define MOD1G_BITS 0x3fffffff
+#define MOD1G_MASK 0xc0000000
+#define MOD1G_INC 0x40000000
+#define MOD1G_SHIFT 30
+
+#ifndef ASM_SRC
+
+/*
+** Start of C-only definitions
+*/
+
+// unit conversion macros
+#define B_TO_KB(x) (((uint_t)(x))>>10)
+#define B_TO_MB(x) (((uint_t)(x))>>20)
+#define B_TO_GB(x) (((uint_t)(x))>>30)
+
+#define KB_TO_B(x) (((uint_t)(x))<<10)
+#define KB_TO_MB(x) (((uint_t)(x))>>10)
+#define KB_TO_GB(x) (((uint_t)(x))>>20)
+
+#define MB_TO_B(x) (((uint_t)(x))<<20)
+#define MB_TO_KB(x) (((uint_t)(x))<<10)
+#define MB_TO_GB(x) (((uint_t)(x))>>10)
+
+#define GB_TO_B(x) (((uint_t)(x))<<30)
+#define GB_TO_KB(x) (((uint_t)(x))<<20)
+#define GB_TO_MB(x) (((uint_t)(x))<<10)
+
+// potetially useful compiler attributes
+#define ALIGN(x) __attribute__((__aligned__(x)))
+#define PACKED __attribute__((__packed__))
+
+/*
+** Utility macros
+*/
+
+//
+// macros to clear data structures
+//
+// these are usable for clearing single-valued data items (e.g.,
+// a PCB, etc.)
+#define CLEAR(v) memclr( &v, sizeof(v) )
+#define CLEAR_PTR(p) memclr( p, sizeof(*p) )
+
+//
+// macros for access registers and system call arguments
+//
+
+// REG(pcb,x) -- access a specific register in a process context
+#define REG(pcb,x) ((pcb)->context->x)
+
+// RET(pcb) -- access return value register in a process context
+#define RET(pcb) ((pcb)->context->eax)
+
+// ARG(pcb,n) -- access argument #n from the indicated process
+//
+// ARG(pcb,0) --> return address
+// ARG(pcb,1) --> first parameter
+// ARG(pcb,2) --> second parameter
+// etc.
+//
+// ASSUMES THE STANDARD 32-BIT ABI, WITH PARAMETERS PUSHED ONTO THE
+// STACK. IF THE PARAMETER PASSING MECHANISM CHANGES, SO MUST THIS!
+#define ARG(pcb,n) ( ( (uint32_t *) (((pcb)->context) + 1) ) [(n)] )
+
+/*
+** Types
+*/
+
+/*
+** Globals
+*/
+
+// general-purpose character buffer
+extern char b256[256];
+
+// buffer for use by PANIC() macro
+extern char b512[512];
+
+// kernel stack
+extern uint8_t kstack[SZ_KSTACK];
+
+/*
+** Prototypes
+*/
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/klib.h b/include/klib.h
new file mode 100644
index 0000000..c1d270c
--- /dev/null
+++ b/include/klib.h
@@ -0,0 +1,57 @@
+/*
+** @file klib.h
+**
+** @author Warren R. Carithers
+**
+** Additional support functions for the kernel.
+*/
+
+#ifndef KLIB_H_
+#define KLIB_H_
+
+#include <common.h>
+
+#ifndef ASM_SRC
+
+#include <x86/ops.h>
+
+/**
+** Name: put_char_or_code( ch )
+**
+** Description: Prints a character on the console, unless it
+** is a non-printing character, in which case its hex code
+** is printed
+**
+** @param ch The character to be printed
+*/
+void put_char_or_code( int ch );
+
+/**
+** Name: backtrace
+**
+** Perform a simple stack backtrace. Could be augmented to use the
+** symbol table to print function/variable names, etc., if so desired.
+**
+** @param ebp Initial EBP to use
+** @param args Number of function argument values to print
+*/
+void backtrace( uint32_t *ebp, uint_t args );
+
+/**
+** Name: kpanic
+**
+** Kernel-level panic routine
+**
+** usage: kpanic( msg )
+**
+** Prefix routine for panic() - can be expanded to do other things
+** (e.g., printing a stack traceback)
+**
+** @param msg[in] String containing a relevant message to be printed,
+** or NULL
+*/
+void kpanic( const char *msg );
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/kmem.h b/include/kmem.h
new file mode 100644
index 0000000..5a98765
--- /dev/null
+++ b/include/kmem.h
@@ -0,0 +1,138 @@
+/**
+** @file kmem.h
+**
+** @author Warren R. Carithers
+** @author Kenneth Reek
+** @author 4003-506 class of 20013
+**
+** @brief Support for dynamic memory allocation within the OS.
+**
+** This is a basic page allocator. Each allocation request returns
+** a pointer to a single 4096-byte page of memory.
+**
+** The module also supports subddivision of pages into "slices",
+** each of which is 1KB (i.e., 1/4 of a page).
+*/
+
+#ifndef KMEM_H_
+#define KMEM_H_
+
+#define KERNEL_SRC
+
+// standard types etc.
+#include <common.h>
+
+/*
+** General (C and/or assembly) definitions
+*/
+
+// Slab and slice sizes, in bytes
+
+#define SZ_SLAB SZ_PAGE
+#define SZ_SLICE (SZ_SLAB >> 2)
+
+// memory limits
+//
+// these determine the range of memory addresses the kmem
+// module will manage
+//
+// we won't map any memory below 1MB or above 1GB
+#define KM_LOW_CUTOFF NUM_1MB
+#define KM_HIGH_CUTOFF NUM_1GB
+
+#ifndef ASM_SRC
+
+/*
+** Start of C-only definitions
+*/
+
+/*
+** Types
+*/
+
+/*
+** Globals
+*/
+
+/*
+** Prototypes
+*/
+
+/**
+** Name: km_init
+**
+** Find what memory is present on the system and
+** construct the list of free memory blocks.
+**
+** Dependencies:
+** Must be called before any other init routine that uses
+** dynamic storage is called.
+*/
+void km_init( void );
+
+/**
+** Name: km_dump
+**
+** Dump information about the free lists to the console. By default,
+** prints only the list sizes; if 'addrs' is true, also dumps the list
+** of page addresses; if 'all' is also true, dumps page addresses and
+** slice addresses.
+**
+** @param addrs Also dump page addresses
+** @param both Also dump slice addresses
+*/
+void km_dump( bool_t addrs, bool_t both );
+
+/*
+** Functions that manipulate free memory blocks.
+*/
+
+/**
+** Name: km_page_alloc
+**
+** Allocate a page of memory from the free list.
+**
+** @return a pointer to the beginning of the allocated page,
+** or NULL if no memory is available
+*/
+void *km_page_alloc( void );
+
+/**
+** Name: km_page_free
+**
+** Returns a memory block to the list of available blocks,
+** combining it with adjacent blocks if they're present.
+**
+** CRITICAL ASSUMPTION: multi-page blocks will be freed one page
+** at a time!
+**
+** @param[in] block Pointer to the page to be returned to the free list
+*/
+void km_page_free( void *block );
+
+/**
+** Name: km_slice_alloc
+**
+** Dynamically allocates a slice (1/4 of a page). If no
+** memory is available, we return NULL (unless ALLOC_FAIL_PANIC
+** was defined, in which case we panic).
+**
+** @return a pointer to the allocated slice
+*/
+void *km_slice_alloc( void );
+
+/**
+** Name: km_slice_free
+**
+** Returns a slice to the list of available slices.
+**
+** We make no attempt to merge slices, as they are independent
+** blocks of memory (unlike pages).
+**
+** @param[in] block Pointer to the slice (1/4 page) to be freed
+*/
+void km_slice_free( void *block );
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/lib.h b/include/lib.h
new file mode 100644
index 0000000..bd19111
--- /dev/null
+++ b/include/lib.h
@@ -0,0 +1,287 @@
+/**
+** @file lib.h
+**
+** @author Numerous CSCI-452 classes
+**
+** @brief C declarations of common library functions
+**
+** These are callable from either kernel or user code. Care should be taken
+** that user code is linked against these separately from kernel code, to
+** ensure separation of the address spaces.
+*/
+
+#ifndef LIB_H_
+#define LIB_H_
+
+#ifndef ASM_SRC
+
+#include <common.h>
+
+/*
+**********************************************
+** MEMORY MANIPULATION FUNCTIONS
+**********************************************
+*/
+
+/**
+** memset(buf,len,value)
+**
+** initialize all bytes of a block of memory to a specific value
+**
+** @param buf The buffer to initialize
+** @param len Buffer size (in bytes)
+** @param value Initialization value
+*/
+void memset( void *buf, register uint32_t len, register uint32_t value );
+
+/**
+** memclr(buf,len)
+**
+** Initialize all bytes of a block of memory to zero
+**
+** @param buf The buffer to initialize
+** @param len Buffer size (in bytes)
+*/
+void memclr( void *buf, register uint32_t len );
+
+/**
+** memcpy(dst,src,len)
+**
+** Copy a block from one place to another
+**
+** May not correctly deal with overlapping buffers
+**
+** @param dst Destination buffer
+** @param src Source buffer
+** @param len Buffer size (in bytes)
+*/
+void memcpy( void *dst, register const void *src, register uint32_t len );
+
+/*
+**********************************************
+** STRING MANIPULATION FUNCTIONS
+**********************************************
+*/
+
+/**
+** str2int(str,base) - convert a string to a number in the specified base
+**
+** @param str The string to examine
+** @param base The radix to use in the conversion
+**
+** @return The converted integer
+*/
+int str2int( register const char *str, register int base );
+
+/**
+** strlen(str) - return length of a NUL-terminated string
+**
+** @param str The string to examine
+**
+** @return The length of the string, or 0
+*/
+uint32_t strlen( register const char *str );
+
+/**
+** strcmp(s1,s2) - compare two NUL-terminated strings
+**
+** @param s1 The first source string
+** @param s2 The second source string
+**
+** @return negative if s1 < s2, zero if equal, and positive if s1 > s2
+*/
+int strcmp( register const char *s1, register const char *s2 );
+
+/**
+** strcpy(dst,src) - copy a NUL-terminated string
+**
+** @param dst The destination buffer
+** @param src The source buffer
+**
+** @return The dst parameter
+**
+** NOTE: assumes dst is large enough to hold the copied string
+*/
+char *strcpy( register char *dst, register const char *src );
+
+/**
+** strcat(dst,src) - append one string to another
+**
+** @param dst The destination buffer
+** @param src The source buffer
+**
+** @return The dst parameter
+**
+** NOTE: assumes dst is large enough to hold the resulting string
+*/
+char *strcat( register char *dst, register const char *src );
+
+/**
+** pad(dst,extra,padchar) - generate a padding string
+**
+** @param dst Pointer to where the padding should begin
+** @param extra How many padding bytes to add
+** @param padchar What character to pad with
+**
+** @return Pointer to the first byte after the padding
+**
+** NOTE: does NOT NUL-terminate the buffer
+*/
+char *pad( char *dst, int extra, int padchar );
+
+/**
+** padstr(dst,str,len,width,leftadjust,padchar - add padding characters
+** to a string
+**
+** @param dst The destination buffer
+** @param str The string to be padded
+** @param len The string length, or -1
+** @param width The desired final length of the string
+** @param leftadjust Should the string be left-justified?
+** @param padchar What character to pad with
+**
+** @return Pointer to the first byte after the padded string
+**
+** NOTE: does NOT NUL-terminate the buffer
+*/
+char *padstr( char *dst, char *str, int len, int width,
+ int leftadjust, int padchar );
+
+/**
+** sprint(dst,fmt,...) - formatted output into a string buffer
+**
+** @param dst The string buffer
+** @param fmt Format string
+**
+** The format string parameter is followed by zero or more additional
+** parameters which are interpreted according to the format string.
+**
+** NOTE: assumes the buffer is large enough to hold the result string
+**
+** NOTE: relies heavily on the x86 parameter passing convention
+** (parameters are pushed onto the stack in reverse order as
+** 32-bit values).
+*/
+void sprint( char *dst, char *fmt, ... );
+
+/*
+**********************************************
+** CONVERSION FUNCTIONS
+**********************************************
+*/
+
+/**
+** cvtuns0(buf,value) - local support routine for cvtuns()
+**
+** Convert a 32-bit unsigned value into a NUL-terminated character string
+**
+** @param buf Result buffer
+** @param value Value to be converted
+**
+** @return Pointer to the first unused byte in the buffer
+**
+** NOTE: assumes buf is large enough to hold the resulting string
+*/
+char *cvtuns0( char *buf, uint32_t value );
+
+/**
+** cvtuns(buf,value)
+**
+** Convert a 32-bit unsigned value into a NUL-terminated character string
+**
+** @param buf Result buffer
+** @param value Value to be converted
+**
+** @return Length of the resulting buffer
+**
+** NOTE: assumes buf is large enough to hold the resulting string
+*/
+int cvtuns( char *buf, uint32_t value );
+
+/**
+** cvtdec0(buf,value) - local support routine for cvtdec()
+**
+** convert a 32-bit unsigned integer into a NUL-terminated character string
+**
+** @param buf Destination buffer
+** @param value Value to convert
+**
+** @return The number of characters placed into the buffer
+** (not including the NUL)
+**
+** NOTE: assumes buf is large enough to hold the resulting string
+*/
+char *cvtdec0( char *buf, int value );
+
+/**
+** cvtdec(buf,value)
+**
+** convert a 32-bit signed value into a NUL-terminated character string
+**
+** @param buf Destination buffer
+** @param value Value to convert
+**
+** @return The number of characters placed into the buffer
+** (not including the NUL)
+**
+** NOTE: assumes buf is large enough to hold the resulting string
+*/
+int cvtdec( char *buf, int32_t value );
+
+/**
+** cvthex(buf,value)
+**
+** convert a 32-bit unsigned value into a mininal-length (up to
+** 8-character) NUL-terminated character string
+**
+** @param buf Destination buffer
+** @param value Value to convert
+**
+** @return The number of characters placed into the buffer
+** (not including the NUL)
+**
+** NOTE: assumes buf is large enough to hold the resulting string
+*/
+int cvthex( char *buf, uint32_t value );
+
+/**
+** cvtoct(buf,value)
+**
+** convert a 32-bit unsigned value into a mininal-length (up to
+** 11-character) NUL-terminated character string
+**
+** @param buf Destination buffer
+** @param value Value to convert
+**
+** @return The number of characters placed into the buffer
+** (not including the NUL)
+**
+** NOTE: assumes buf is large enough to hold the resulting string
+*/
+int cvtoct( char *buf, uint32_t value );
+
+/**
+** bound(min,value,max)
+**
+** This function confines an argument within specified bounds.
+**
+** @param min Lower bound
+** @param value Value to be constrained
+** @param max Upper bound
+**
+** @return The constrained value
+*/
+uint32_t bound( uint32_t min, uint32_t value, uint32_t max );
+
+#endif /* !ASM_SRC */
+
+/*
+** Finally, pull in the level-specific library headers
+*/
+#ifdef KERNEL_SRC
+#include <klib.h>
+#else
+#include <ulib.h>
+#endif /* KERNEL_SRC */
+
+#endif
diff --git a/include/list.h b/include/list.h
new file mode 100644
index 0000000..28c2377
--- /dev/null
+++ b/include/list.h
@@ -0,0 +1,68 @@
+/**
+** @file list.h
+**
+** @author Warren R. Carithers
+**
+** @brief Support for a basic linked list data type.
+**
+** This module provides a very basic linked list data structure.
+** A list can contain anything that has a pointer field in the first
+** four bytes; these routines assume those bytes contain a pointer to
+** the following entry in the list, whatever that may be.
+*/
+
+#ifndef LIST_H_
+#define LIST_H_
+
+#define KERNEL_SRC
+
+// standard types etc.
+#include <common.h>
+
+/*
+** General (C and/or assembly) definitions
+*/
+
+#ifndef ASM_SRC
+
+/*
+** Start of C-only definitions
+*/
+
+/*
+** Data types
+*/
+
+// The list structure
+typedef struct list_s {
+ struct list_s *next; // link to the successor
+} list_t;
+
+/*
+** Prototypes
+*/
+
+/**
+** Name: list_add
+**
+** Add the supplied data to the beginning of the specified list.
+**
+** @param[in,out] list The address of a list_t variable
+** @param[in] data The data to prepend to the list
+*/
+void list_add( list_t *list, void *data );
+
+/**
+** Name: list_remove
+**
+** Remove the first entry from a linked list.
+**
+** @param[in,out] list The address of a list_t variable
+**
+** @return a pointer to the removed data, or NULL if the list was empty
+*/
+void *list_remove( list_t *list );
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/params.h b/include/params.h
new file mode 100644
index 0000000..52eb81d
--- /dev/null
+++ b/include/params.h
@@ -0,0 +1,31 @@
+/**
+** @file params.h
+**
+** @author CSCI-452 class of 20245
+**
+** @brief System configuration settings
+**
+** This header file contains many of the "easily tunable" system
+** settings, such as clock rate, number of simultaneous user
+** processes, etc. This provides a sort of "one-stop shop" for
+** things that might be tweaked frequently.
+*/
+
+#ifndef PARAMS_H_
+#define PARAMS_H_
+
+/*
+** General (C and/or assembly) definitions
+*/
+
+// Upper bound on the number of simultaneous user-level
+// processes in the system (completely arbitrary)
+
+#define N_PROCS 25
+
+// Clock frequency (Hz)
+
+#define CLOCK_FREQ 1000
+#define TICKS_PER_MS 1
+
+#endif
diff --git a/include/procs.h b/include/procs.h
new file mode 100644
index 0000000..9db4ac8
--- /dev/null
+++ b/include/procs.h
@@ -0,0 +1,452 @@
+/*
+** @file procs.h
+**
+** @author CSCI-452 class of 20245
+**
+** @brief Process-related declarations
+*/
+
+#ifndef PROCS_H_
+#define PROCS_H_
+
+#include <common.h>
+
+/*
+** General (C and/or assembly) definitions
+*/
+
+#ifndef ASM_SRC
+
+/*
+** Start of C-only definitions
+*/
+
+/*
+** Types
+*/
+
+/*
+** Process states
+*/
+enum state_e {
+ // pre-viable
+ STATE_UNUSED = 0, STATE_NEW,
+ // runnable
+ STATE_READY, STATE_RUNNING,
+ // runnable, but waiting for some event
+ STATE_SLEEPING, STATE_BLOCKED, STATE_WAITING,
+ // no longer runnable
+ STATE_KILLED, STATE_ZOMBIE
+ // sentinel value
+ , N_STATES
+};
+
+// these may be handy for checking general conditions of processes
+// they depend on the order of the state names in the enum!
+#define FIRST_VIABLE STATE_READY
+#define FIRST_BLOCKED STATE_SLEEPING
+#define LAST_VIABLE STATE_WAITING
+
+/*
+** Process priorities are defined in <defs.h>
+*/
+
+/*
+** Quantum lengths - values are number of clock ticks
+*/
+enum quantum_e {
+ QUANTUM_SHORT = 1,
+ QUANTUM_STANDARD = 3,
+ QUANTUM_LONG = 5
+};
+
+/*
+** PID-related definitions
+*/
+#define PID_INIT 1
+#define FIRST_USER_PID 2
+
+/*
+** Process context structure
+**
+** NOTE: the order of data members here depends on the
+** register save code in isr_stubs.S!!!!
+**
+** This will be at the top of the user stack when we enter
+** an ISR. In the case of a system call, it will be followed
+** by the return address and the system call parameters.
+*/
+
+typedef struct context_s {
+ uint32_t ss; // pushed by isr_save
+ uint32_t gs;
+ uint32_t fs;
+ uint32_t es;
+ uint32_t ds;
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebp;
+ uint32_t esp;
+ uint32_t ebx;
+ uint32_t edx;
+ uint32_t ecx;
+ uint32_t eax;
+ uint32_t vector;
+ uint32_t code; // pushed by isr_save or the hardware
+ uint32_t eip; // pushed by the hardware
+ uint32_t cs;
+ uint32_t eflags;
+} context_t;
+
+#define SZ_CONTEXT sizeof(context_t)
+
+/*
+** program section information for user processes
+*/
+
+typedef struct section_s {
+ uint_t length; // length, in some units
+ uint_t addr; // location, in some units
+} section_t;
+
+// note: these correspond to the PT_LOAD sections found in
+// an ELF file, not necessarily to text/data/bss
+#define SECT_L1 0
+#define SECT_L2 1
+#define SECT_L3 2
+#define SECT_STACK 3
+
+// total number of section table entries in our PCB
+#define N_SECTS 4
+// number of those that can be loaded from an ELF module
+#define N_LOADABLE 3
+
+/*
+** The process control block
+**
+** Fields are ordered by size to avoid padding
+**
+** Currently, this is 72 bytes long. It could be reduced to 64 (2^6)
+** bytes by making the last four fields uint16_t types; that would
+** divide nicely into 1024 bytes, giving 16 PCBs per 1/4 page of memory.
+*/
+
+typedef struct pcb_s {
+
+ // four-byte fields
+ // start with these four bytes, for easy access in assembly
+ context_t *context; // pointer to context save area on stack
+
+ // VM information
+ pde_t *pdir; // page directory for this process
+ section_t sects[N_SECTS]; // per-section memory information
+
+ // queue linkage
+ struct pcb_s *next; // next PCB in queue
+
+ // process state information
+ struct pcb_s *parent; // pointer to PCB of our parent process
+ uint32_t wakeup; // wakeup time, for sleeping processes
+ int32_t exit_status; // termination status, for parent's use
+
+ // these things may not need to be four bytes
+ uint_t pid; // PID of this process
+ enum state_e state; // process' current state
+ enum priority_e priority; // process priority level
+ uint_t ticks; // remaining ticks in this time slice
+
+} pcb_t;
+
+#define SZ_PCB sizeof(pcb_t)
+
+/*
+** PCB queue structure (opaque to the rest of the kernel)
+*/
+typedef struct pcb_queue_s *pcb_queue_t;
+
+/*
+** Queue ordering methods
+*/
+enum pcb_queue_order_e {
+ O_FIFO, O_PRIO, O_PID, O_WAKEUP
+ // sentinel
+ , N_ORDERINGS
+};
+#define O_FIRST_STYLE O_FIFO
+#define O_LAST_STYLE O_WAKEUP
+
+/*
+** Globals
+*/
+
+// public-facing queue handles
+extern pcb_queue_t pcb_freelist;
+extern pcb_queue_t ready;
+extern pcb_queue_t waiting;
+extern pcb_queue_t sleeping;
+extern pcb_queue_t zombie;
+extern pcb_queue_t sioread;
+
+// pointer to the currently-running process
+extern pcb_t *current;
+
+// the process table
+extern pcb_t ptable[N_PROCS];
+
+// next available PID
+extern uint_t next_pid;
+
+// pointer to the PCB for the 'init' process
+extern pcb_t *init_pcb;
+
+// table of state name strings
+extern const char *state_str[N_STATES];
+
+// table of priority name strings
+extern const char *prio_str[N_PRIOS];
+
+// table of queue ordering name strings
+extern const char *ord_str[N_ORDERINGS];
+
+/*
+** Prototypes
+*/
+
+/**
+** Name: pcb_init
+**
+** Initialization for the Process module.
+*/
+void pcb_init( void );
+
+/**
+** Name: pcb_alloc
+**
+** Allocate a PCB from the list of free PCBs.
+**
+** @param pcb Pointer to a pcb_t * where the PCB pointer will be returned.
+**
+** @return status of the allocation attempt
+*/
+int pcb_alloc( pcb_t **pcb );
+
+/**
+** Name: pcb_free
+**
+** Return a PCB to the list of free PCBs.
+**
+** @param pcb Pointer to the PCB to be deallocated.
+*/
+void pcb_free( pcb_t *pcb );
+
+/**
+** Name: pcb_zombify
+**
+** Turn the indicated process into a Zombie. This function
+** does most of the real work for exit() and kill() calls.
+** Is also called from the scheduler and dispatcher.
+**
+** @param pcb Pointer to the newly-undead PCB
+*/
+void pcb_zombify( register pcb_t *victim );
+
+/**
+** Name: pcb_cleanup
+**
+** Reclaim a process' data structures
+**
+** @param pcb The PCB to reclaim
+*/
+void pcb_cleanup( pcb_t *pcb );
+
+/**
+** Name: pcb_find_pid
+**
+** Locate the PCB for the process with the specified PID
+**
+** @param pid The PID to be located
+**
+** @return Pointer to the PCB, or NULL
+*/
+pcb_t *pcb_find_pid( uint_t pid );
+
+/**
+** Name: pcb_find_ppid
+**
+** Locate the PCB for the process with the specified parent
+**
+** @param pid The PID to be located
+**
+** @return Pointer to the PCB, or NULL
+*/
+pcb_t *pcb_find_ppid( uint_t pid );
+
+/**
+** Name: pcb_queue_reset
+**
+** Initialize a PCB queue.
+**
+** @param queue[out] The queue to be initialized
+** @param order[in] The desired ordering for the queue
+**
+** @return status of the init request
+*/
+int pcb_queue_reset( pcb_queue_t queue, enum pcb_queue_order_e style );
+
+/**
+** Name: pcb_queue_empty
+**
+** Determine whether a queue is empty. Essentially just a wrapper
+** for the PCB_QUEUE_EMPTY() macro, for use outside this module.
+**
+** @param[in] queue The queue to check
+**
+** @return true if the queue is empty, else false
+*/
+bool_t pcb_queue_empty( pcb_queue_t queue );
+
+/**
+** Name: pcb_queue_length
+**
+** Return the count of elements in the specified queue.
+**
+** @param[in] queue The queue to check
+**
+** @return the count (0 if the queue is empty)
+*/
+uint_t pcb_queue_length( const pcb_queue_t queue );
+
+/**
+** Name: pcb_queue_insert
+**
+** Inserts a PCB into the indicated queue.
+**
+** @param queue[in,out] The queue to be used
+** @param pcb[in] The PCB to be inserted
+**
+** @return status of the insertion request
+*/
+int pcb_queue_insert( pcb_queue_t queue, pcb_t *pcb );
+
+/**
+** Name: pcb_queue_peek
+**
+** Return the first PCB from the indicated queue, but don't
+** remove it from the queue
+**
+** @param queue[in] The queue to be used
+**
+** @return the PCB pointer, or NULL if the queue is empty
+*/
+pcb_t *pcb_queue_peek( const pcb_queue_t queue );
+
+/**
+** Name: pcb_queue_remove
+**
+** Remove the first PCB from the indicated queue.
+**
+** @param queue[in,out] The queue to be used
+** @param pcb[out] Pointer to where the PCB pointer will be saved
+**
+** @return status of the removal request
+*/
+int pcb_queue_remove( pcb_queue_t queue, pcb_t **pcb );
+
+/**
+** Name: pcb_queue_remove_this
+**
+** Remove the specified PCB from the indicated queue.
+**
+** @param queue[in,out] The queue to be used
+** @param pcb[in] Pointer to the PCB to be removed
+**
+** @return status of the removal request
+*/
+int pcb_queue_remove_this( pcb_queue_t queue, pcb_t *pcb );
+
+/*
+** Scheduler routines
+*/
+
+/**
+** schedule(pcb)
+**
+** Schedule the supplied process
+**
+** @param pcb Pointer to the PCB of the process to be scheduled
+*/
+void schedule( pcb_t *pcb );
+
+/**
+** dispatch()
+**
+** Select the next process to receive the CPU
+*/
+void dispatch( void );
+
+/*
+** Debugging/tracing routines
+*/
+
+/**
+** Name: ctx_dump
+**
+** Dumps the contents of this process context to the console
+**
+** @param msg[in] An optional message to print before the dump
+** @param c[in] The context to dump out
+*/
+void ctx_dump( const char *msg, register context_t *c );
+
+/**
+** Name: ctx_dump_all
+**
+** dump the process context for all active processes
+**
+** @param msg[in] Optional message to print
+*/
+void ctx_dump_all( const char *msg );
+
+/**
+** Name: pcb_dump
+**
+** Dumps the contents of this PCB to the console
+**
+** @param msg[in] An optional message to print before the dump
+** @param p[in] The PCB to dump
+** @param all[in] Dump all the contents?
+*/
+void pcb_dump( const char *msg, register pcb_t *p, bool_t all );
+
+/**
+** Name: pcb_queue_dump
+**
+** Dump the contents of the specified queue to the console
+**
+** @param msg[in] An optional message to print before the dump
+** @param queue[in] The queue to dump
+** @param contents[in] Also dump (some) contents?
+*/
+void pcb_queue_dump( const char *msg, pcb_queue_t queue, bool_t contents );
+
+/**
+** Name: ptable_dump
+**
+** dump the contents of the "active processes" table
+**
+** @param msg[in] Optional message to print
+** @param all[in] Dump all or only part of the relevant data
+*/
+void ptable_dump( const char *msg, bool_t all );
+
+/**
+** Name: ptable_dump_counts
+**
+** Prints basic information about the process table (number of
+** entries, number with each process state, etc.).
+*/
+void ptable_dump_counts( void );
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/sio.h b/include/sio.h
new file mode 100644
index 0000000..dca80ed
--- /dev/null
+++ b/include/sio.h
@@ -0,0 +1,168 @@
+/**
+** @file sio.h
+**
+** @author Warren R. Carithers
+**
+** @brief SIO definitions
+*/
+
+#ifndef SIO_H_
+#define SIO_H_
+
+// compatibility definitions
+#include <compat.h>
+
+/*
+** General (C and/or assembly) definitions
+*/
+
+// sio interrupt settings
+
+#define SIO_TX 0x01
+#define SIO_RX 0x02
+#define SIO_BOTH (SIO_TX | SIO_RX)
+
+#ifndef ASM_SRC
+
+/*
+** Start of C-only definitions
+*/
+
+#include <common.h>
+
+#include <procs.h>
+
+/*
+** PUBLIC GLOBAL VARIABLES
+*/
+
+// queue for read-blocked processes
+extern QTYPE QNAME;
+
+/*
+** PUBLIC FUNCTIONS
+*/
+
+/**
+** sio_init()
+**
+** Initialize the UART chip.
+*/
+void sio_init( void );
+
+/**
+** sio_enable()
+**
+** Enable SIO interrupts
+**
+** usage: uint8_t old = sio_enable( uint8_t which )
+**
+** @param which Bit mask indicating which interrupt(s) to enable
+**
+** @return the prior IER setting
+*/
+uint8_t sio_enable( uint8_t which );
+
+/**
+** sio_disable()
+**
+** Disable SIO interrupts
+**
+** usage: uint8_t old = sio_disable( uint8_t which )
+**
+** @param which Bit mask indicating which interrupt(s) to disable
+**
+** @return the prior IER setting
+*/
+uint8_t sio_disable( uint8_t which );
+
+/**
+** sio_inq_length()
+**
+** Get the input queue length
+**
+** usage: int num = sio_inq_length()
+**
+** @return the count of characters still in the input queue
+*/
+int sio_inq_length( void );
+
+/**
+** sio_readc()
+**
+** Get the next input character
+**
+** usage: int ch = sio_readc()
+**
+** @return the next character, or -1 if no character is available
+*/
+int sio_readc( void );
+
+/**
+** sio_read()
+**
+** Read the entire input buffer into a user buffer of a specified size
+**
+** usage: int num = sio_read( char *buffer, int length )
+**
+** @param buf The destination buffer
+** @param length Length of the buffer
+**
+** @return the number of bytes copied, or 0 if no characters were available
+*/
+int sio_read( char *buffer, int length );
+
+/**
+** sio_writec( ch )
+**
+** Write a character to the serial output
+**
+** usage: sio_writec( int ch )
+**
+** @param ch Character to be written (in the low-order 8 bits)
+*/
+void sio_writec( int ch );
+
+/**
+** sio_write( ch )
+**
+** Write a buffer of characters to the serial output
+**
+** usage: int num = sio_write( const char *buffer, int length )
+**
+** @param buffer Buffer containing characters to write
+** @param length Number of characters to write
+**
+** @return the number of characters copied into the SIO output buffer
+*/
+int sio_write( const char *buffer, int length );
+
+/**
+** sio_puts( buf )
+**
+** Write a NUL-terminated buffer of characters to the serial output
+**
+** usage: n = sio_puts( const char *buffer );
+**
+** @param buffer The buffer containing a NUL-terminated string
+**
+** @return the count of bytes transferred
+*/
+int sio_puts( const char *buffer );
+
+/**
+** sio_dump( full )
+**
+** Dump the contents of the SIO buffers to the console
+**
+** usage: sio_dump(true) or sio_dump(false)
+**
+** @param full Boolean indicating whether or not a "full" dump
+** is being requested (which includes the contents
+** of the queues)
+*/
+void sio_dump( bool_t full );
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/support.h b/include/support.h
new file mode 100644
index 0000000..bdc5dc6
--- /dev/null
+++ b/include/support.h
@@ -0,0 +1,87 @@
+/**
+** SCCS ID: @(#)support.h 2.3 1/22/25
+**
+** @file support.h
+**
+** @author K. Reek
+** @author Warren R. Carithers
+**
+** Declarations for functions provided in support.c, and
+** some hardware characteristics needed in the initialization.
+**
+*/
+
+#ifndef SUPPORT_H
+#define SUPPORT_H
+
+/*
+** Delay values
+**
+** Notes: The parameter to the delay() function is ambiguous; it
+** purports to indicate a delay length, but that isn't really tied
+** to any real-world time measurement.
+**
+** On the original systems we used (dual 500MHz Intel P3 CPUs), each
+** "unit" was approximately one tenth of a second, so delay(10) would
+** delay for about one second.
+**
+** On the current machines (Intel Core i5-7500), delay(100) is about
+** 2.5 seconds, so each "unit" is roughly 0.025 seconds.
+**
+** Ultimately, just remember that THESE VALUES ARE APPROXIMATE AT BEST.
+*/
+#define DELAY_1_SEC 40
+#define DELAY_1_25_SEC 50
+#define DELAY_2_SEC 80
+#define DELAY_2_5_SEC 100
+#define DELAY_3_SEC 120
+#define DELAY_5_SEC 200
+#define DELAY_7_SEC 280
+#define DELAY_10_SEC 400
+
+#ifndef ASM_SRC
+/**
+** panic
+**
+** Called when we find an unrecoverable error, this routine disables
+** interrupts, prints a description of the error and then goes into a
+** hard loop to prevent any further processing.
+**
+** @param reason NUL-terminated message to be printed.
+*/
+void panic( char *reason );
+
+/**
+** init_interrupts
+**
+** (Re)initilizes the interrupt system. This includes initializing the
+** IDT and the PIC. It is up to the user to enable processor interrupts
+** when they're ready.
+*/
+void init_interrupts( void );
+
+/*
+** install_isr
+**
+** Installs a second-level handler for a specific interrupt. Returns the
+** previously-installed handler for reinstallation (if desired).
+**
+** @param vector the interrupt vector number
+** @param handler the second-stage ISR function to be called by the stub
+**
+** @return a pointer to the previously-registered ISR
+*/
+void (*install_isr( int vector,
+ void ( *handler )(int,int) ) )( int, int );
+
+/*
+** Name: delay
+**
+** See the comment above about the relative accuracy of the 'length'
+** parameter.
+*/
+void delay( int length );
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/syscalls.h b/include/syscalls.h
new file mode 100644
index 0000000..e66f6c0
--- /dev/null
+++ b/include/syscalls.h
@@ -0,0 +1,80 @@
+/**
+** @file syscalls.h
+**
+** @author CSCI-452 class of 20245
+**
+** @brief System call declarations
+*/
+
+#ifndef SYSCALLS_H_
+#define SYSCALLS_H_
+
+#include <common.h>
+
+/*
+** General (C and/or assembly) definitions
+*/
+
+/*
+** system call codes
+**
+** these are used in the user-level C library stub functions,
+** and are defined here as CPP macros instead of as an enum
+** so that they can be used from assembly
+*/
+
+#define SYS_exit 0
+#define SYS_waitpid 1
+#define SYS_fork 2
+#define SYS_exec 3
+#define SYS_read 4
+#define SYS_write 5
+#define SYS_getpid 6
+#define SYS_getppid 7
+#define SYS_gettime 8
+#define SYS_getprio 9
+#define SYS_setprio 10
+#define SYS_kill 11
+#define SYS_sleep 12
+
+// UPDATE THIS DEFINITION IF MORE SYSCALLS ARE ADDED!
+#define N_SYSCALLS 13
+
+// dummy system call code for testing our ISR
+#define SYS_bogus 0xbad
+
+// interrupt vector entry for system calls
+#define VEC_SYSCALL 0x80
+
+#ifndef ASM_SRC
+
+/*
+** Start of C-only definitions
+*/
+
+/*
+** Types
+*/
+
+/*
+** Globals
+*/
+
+/*
+** Prototypes
+*/
+
+#ifdef KERNEL_SRC
+
+/**
+** Name: sys_init
+**
+** Syscall module initialization routine
+*/
+void sys_init( void );
+
+#endif /* KERNEL_SRC */
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/types.h b/include/types.h
new file mode 100644
index 0000000..2f934f1
--- /dev/null
+++ b/include/types.h
@@ -0,0 +1,58 @@
+/**
+** @file types.h
+**
+** @author Warren R. Carithers
+**
+** @brief Common type declarations.
+**
+** This header file contains type declarations used throughout
+** the kernel and user code.
+*/
+
+#ifndef TYPES_H_
+#define TYPES_H_
+
+#ifndef ASM_SRC
+
+/*
+** Start of C-only definitions
+**
+** Anything that should not be visible to something other than
+** the C compiler should be put here.
+*/
+
+/*
+** Types
+*/
+
+// standard integer sized types
+typedef 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 int int64_t;
+typedef unsigned long long int uint64_t;
+
+// other integer types
+typedef unsigned char uchar_t;
+typedef unsigned int uint_t;
+typedef unsigned long int ulong_t;
+
+// Boolean values
+typedef uint8_t bool_t;
+
+#define true 1
+#define false 0
+
+#ifdef KERNEL_SRC
+// we define these here instead of in vm.h in order to get around a
+// nasty chick/egg dependency between procs.h and vm.h
+typedef uint32_t pde_t; // page directory entry
+typedef uint32_t pte_t; // page table entry
+#endif /* KERNEL_SRC */
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/udefs.h b/include/udefs.h
new file mode 100644
index 0000000..50b6952
--- /dev/null
+++ b/include/udefs.h
@@ -0,0 +1,113 @@
+/**
+** @file udefs.h
+**
+** @author CSCI-452 class of 20245
+**
+** @brief "Userland" configuration information
+*/
+
+#ifndef UDEFS_H_
+#define UDEFS_H_
+
+#include <common.h>
+
+/*
+** General (C and/or assembly) definitions
+**
+** This section of the header file contains definitions that can be
+** used in either C or assembly-language source code.
+*/
+
+// delay loop counts
+
+#define DELAY_LONG 100000000
+#define DELAY_MED 4500000
+#define DELAY_SHORT 2500000
+
+#define DELAY_STD DELAY_SHORT
+
+#ifndef ASM_SRC
+
+/*
+** Start of C-only definitions
+*/
+
+// convenience macros
+
+// a delay loop - kind of ugly, but it works
+
+#define DELAY(n) do { \
+ for(int _dlc = 0; _dlc < (DELAY_##n); ++_dlc) continue; \
+ } while(0)
+
+/*
+** We need the list of program IDs so that we can request
+** their execution
+*/
+
+#include <userids.h>
+
+/*
+** All user main() functions have the following prototype:
+**
+** int name( int argc, char *argv[] );
+**
+** To simplify declaring them, we define a macro that expands into
+** that header. This can be used both in the implementation (followed
+** by the function body) and in places where we just need the prototype
+** (following it with a semicolon).
+*/
+
+#define USERMAIN(f) int f( int argc, char *argv[] )
+
+/*
+** User process controls.
+**
+** To enable a specific test, define the symbol SPAWN_name here, and
+** guard the places in other code that use or refer to that test. For
+** example, test 'A' is enabled by definining SPAWN_A here, and all
+** places that refer to test 'A' are guarded with:
+**
+** #ifdef SPAWN_A
+** ... conditionally-compiled code
+** #endif
+**
+** Generally, most of these will exit with a status of 0. If a process
+** returns from its main function when it shouldn't (e.g., if it had
+** called exit() but continued to run), it will usually return a status
+** of ?.
+*/
+
+/*
+** The standard set of test programs, start by the shell (which is started
+** automatically from the initial user process)
+**
+** There is no user 'O' program, and programs 'W' through 'Z' are spawned
+** from other processes and are never spawned directly.
+*/
+
+#define SPAWN_A
+#define SPAWN_B
+#define SPAWN_C
+#define SPAWN_D
+#define SPAWN_E
+#define SPAWN_F
+#define SPAWN_G
+#define SPAWN_H
+#define SPAWN_I
+#define SPAWN_J
+#define SPAWN_K
+#define SPAWN_L
+#define SPAWN_M
+#define SPAWN_N
+#define SPAWN_P
+#define SPAWN_Q
+#define SPAWN_R
+#define SPAWN_S
+#define SPAWN_T
+#define SPAWN_U
+#define SPAWN_V
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/ulib.h b/include/ulib.h
new file mode 100644
index 0000000..d254d6a
--- /dev/null
+++ b/include/ulib.h
@@ -0,0 +1,315 @@
+/**
+** @file ulib.h
+**
+** @author CSCI-452 class of 20245
+**
+** @brief Declarations for user-level library functions
+**
+** This module implements a simple collection of support functions
+** similar to the standard C library.
+*/
+
+#ifndef ULIB_H_
+#define ULIB_H_
+
+#include <common.h>
+
+/*
+** General (C and/or assembly) definitions
+*/
+
+#ifndef ASM_SRC
+
+/*
+** Start of C-only definitions
+*/
+
+/*
+** Types
+*/
+
+/*
+** Globals
+*/
+
+/*
+** Prototypes
+*/
+
+/*
+*************************************************
+** SYSTEM CALLS *********************************
+*************************************************
+*/
+
+/**
+** exit - terminate the calling process
+**
+** usage: exit(status);
+**
+** @param status Termination status of this process
+**
+** Does not return.
+*/
+void exit( int32_t status );
+
+/**
+** waitpid - wait for a child process to terminate
+**
+** usage: pid = waitpid(pid,&status);
+**
+** @param pid PID of the desired child, or 0 for any child
+** @param status Pointer to int32_t into which the child's status is placed,
+** or NULL
+**
+** @return The PID of the terminated child, or an error code
+**
+** If there are no children in the system, returns an error code (*status
+** is unchanged).
+**
+** If there are one or more children in the system and at least one has
+** terminated but hasn't yet been cleaned up, cleans up that process and
+** returns its information; otherwise, blocks until a child terminates.
+*/
+int waitpid( uint_t pid, int32_t *status );
+
+/**
+** fork - create a duplicate of the calling process
+**
+** usage: pid = fork();
+**
+** @return parent - the pid of the new child, or an error code
+** child - 0
+*/
+int fork( void );
+
+/**
+** exec - replace the memory image of the calling process
+**
+** usage: exec( what, args )
+**
+** @param what program table index of the program to exec
+** @param args the command-line argument vector
+**
+** Does not return if it succeeds; if it returns, something has
+** gone wrong.
+*/
+void exec( uint_t what, char **args );
+
+/**
+** read - read into a buffer from a stream
+**
+** usage: n = read(channel,buf,length)
+**
+** @param chan I/O stream to read from
+** @param buf Buffer to read into
+** @param length Maximum capacity of the buffer
+**
+** @return The count of bytes transferred, or an error code
+*/
+int read( uint_t chan, void *buffer, uint_t length );
+
+/**
+** write - write from a buffer to a stream
+**
+** usage: n = write(channel,buf,length)
+**
+** @param chan I/O stream to write to
+** @param buf Buffer to write from
+** @param length Maximum capacity of the buffer
+**
+** @return The count of bytes transferred, or an error code
+*/
+int write( uint_t chan, const void *buffer, uint_t length );
+
+/**
+** getpid - get the PID of the calling process
+**
+** usage: pid = getpid()
+**
+** @return the PID of this process
+*/
+uint_t getpid( void );
+
+/**
+** getppid - get the PID of the calling process' parent
+**
+** usage: pid = getppid()
+**
+** @return the PID of this process' parent
+*/
+uint_t getppid( void );
+
+/**
+** gettime - get the current system time
+**
+** usage: pid = gettime()
+**
+** @return the system time
+*/
+uint32_t gettime( void );
+
+/**
+** getprio - get the scheduling priority of the calling process
+**
+** usage: prio = getprio()
+**
+** @return the process' priority
+*/
+int getprio( void );
+
+/**
+** setprio - set the scheduling priority of the calling process
+**
+** usage: oldprio = setprio(newprio)
+**
+** @param new the desired new priority
+**
+** @return the old priority value
+*/
+int setprio( int new );
+
+/**
+** kill - terminate a process with extreme prejudice
+**
+** usage: n = kill( pid )
+**
+** @param pid the intended victim
+**
+** @return 0 on success, else an error code
+*/
+int32_t kill( uint_t pid );
+
+/**
+** sleep - put the current process to sleep for some length of time
+**
+** usage: sleep(n);
+**
+** @param ms Desired sleep time (in ms), or 0 to yield the CPU
+**
+** @return the time the process spent sleeping (in ms)
+*/
+int sleep( uint32_t ms );
+
+/**
+** bogus - a nonexistent system call, to test our syscall ISR
+**
+** usage: bogus()
+**
+** Does not return.
+*/
+void bogus( void );
+
+/*
+*************************************************
+** CONVENIENT "SHORTHAND" VERSIONS OF SYSCALLS **
+*************************************************
+**
+** These are library functions that perform specific common
+** variants of system calls. This helps reduce the total number
+** of system calls, keeping our baseline OS as lean and mean
+** as we can make it. :-)
+*/
+
+/**
+** wait - wait for any child to exit
+**
+** usage: pid = wait(&status)
+**
+** Calls waitpid(0,status)
+**
+** @param status Pointer to int32_t into which the child's status is placed,
+** or NULL
+**
+** @return The PID of the terminated child, or an error code
+*/
+int wait( int32_t *status );
+
+/**
+** spawn - create a new process running a different program
+**
+** usage: n = spawn(what,args)
+**
+** Creates a new process and then execs 'what'
+**
+** @param what Program table index of the program to spawn
+** @param args The command-line argument vector for the process
+**
+** @return The PID of the child, or an error code
+*/
+int spawn( uint_t what, char **args );
+
+/**
+** cwritech(ch) - write a single character to the console
+**
+** @param ch The character to write
+**
+** @return The return value from calling write()
+*/
+int cwritech( char ch );
+
+/**
+** cwrites(str) - write a NUL-terminated string to the console
+**
+** @param str The string to write
+**
+*/
+int cwrites( const char *str );
+
+/**
+** cwrite(buf,leng) - write a sized buffer to the console
+**
+** @param buf The buffer to write
+** @param leng The number of bytes to write
+**
+** @return The return value from calling write()
+*/
+int cwrite( const char *buf, uint32_t leng );
+
+/**
+** swritech(ch) - write a single character to the SIO
+**
+** @param ch The character to write
+**
+** @return The return value from calling write()
+*/
+int swritech( char ch );
+
+/**
+** swrites(str) - write a NUL-terminated string to the SIO
+**
+** @param str The string to write
+**
+** @return The return value from calling write()
+*/
+int swrites( const char *str );
+
+/**
+** swrite(buf,leng) - write a sized buffer to the SIO
+**
+** @param buf The buffer to write
+** @param leng The number of bytes to write
+**
+** @return The return value from calling write()
+*/
+int swrite( const char *buf, uint32_t leng );
+
+/*
+*************************************************
+** MISCELLANEOUS USEFUL SUPPORT FUNCTIONS *******
+*************************************************
+*/
+
+/**
+** fake_exit()
+**
+** dummy "startup" function
+**
+** calls exit(%eax) - serves as the "return to" code for
+** main() functions, in case they don't call exit() themselves
+*/
+void fake_exit( void );
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/user.h b/include/user.h
new file mode 100644
index 0000000..4d9402f
--- /dev/null
+++ b/include/user.h
@@ -0,0 +1,138 @@
+/**
+** @file user.h
+**
+** @author CSCI-452 class of 20245
+**
+** @brief Declarations of user-level code management routines
+*/
+
+#ifndef USER_H_
+#define USER_H_
+
+#include <common.h>
+
+#include <procs.h>
+#include <x86/arch.h>
+
+// default value for EFLAGS in new processes
+#define DEFAULT_EFLAGS (EFL_MB1 | EFL_IF)
+
+/*
+** General (C and/or assembly) definitions
+*/
+
+#ifndef ASM_SRC
+
+/*
+** Start of C-only definitions
+*/
+
+/*
+** Types
+*/
+
+/*
+** Blob file organization
+**
+** The file begins with a four-byte magic number and a four-byte integer
+** indicating the number of ELF files contained in the blob. This is
+** followed by an array of 32-byte file table entries, and then the contents
+** of the ELF files in the order they appear in the program file table.
+**
+** Bytes Contents
+** ----- ----------------------------
+** 0 - 3 File magic number ("BLB\0")
+** 4 - 7 Number of ELF files in blob ("n")
+** 8 - n*32+8 Program file table
+** n*32+9 - ? ELF file contents
+**
+** Each program file table entry contains the following information:
+**
+** name File name (up to 19 characters long)
+** offset Byte offset to the ELF header for this file
+** size Size of this ELF file, in bytes
+** flags Flags related to this file
+*/
+
+// user program blob header
+typedef struct header_s {
+ char magic[4];
+ uint32_t num;
+} header_t;
+
+// length of the file name field
+#define NAMELEN 20
+
+// program descriptor
+typedef struct prog_s {
+ char name[NAMELEN]; // truncated name (15 chars)
+ uint32_t offset; // offset from the beginning of the blob
+ uint32_t size; // size of this ELF module
+ uint32_t flags; // miscellaneous flags
+} prog_t;
+
+/*
+** Globals
+*/
+
+/*
+** Prototypes
+*/
+
+/**
+** Name: user_init
+**
+** Initializes the user support module.
+*/
+void user_init( void );
+
+/**
+** Name: user_locate
+**
+** Locates a user program in the user code archive.
+**
+** @param what The ID of the user program to find
+**
+** @return pointer to the program table entry in the code archive, or NULL
+*/
+prog_t *user_locate( uint_t what );
+
+/**
+** Name: user_duplicate
+**
+** Duplicates the memory setup for an existing process.
+**
+** @param new The PCB for the new copy of the program
+** @param old The PCB for the existing the program
+**
+** @return the status of the duplicate attempt
+*/
+int user_duplicate( pcb_t *new, pcb_t *old );
+
+/**
+** Name: user_load
+**
+** Loads a user program from the user code archive into memory.
+** Allocates all needed frames and sets up the VM tables.
+**
+** @param prog A pointer to the program table entry to be loaded
+** @param pcb The PCB for the program being loaded
+** @param args The argument vector for the program
+**
+** @return the status of the load attempt
+*/
+int user_load( prog_t *prog, pcb_t *pcb, const char **args );
+
+/**
+** Name: user_cleanup
+**
+** "Unloads" a user program. Deallocates all memory frames and
+** cleans up the VM structures.
+**
+** @param pcb The PCB of the program to be cleaned up
+*/
+void user_cleanup( pcb_t *pcb );
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/userids.h b/include/userids.h
new file mode 100644
index 0000000..284f3ee
--- /dev/null
+++ b/include/userids.h
@@ -0,0 +1,33 @@
+/**
+** @file userids.h
+**
+** @author Warren R. Carithers
+**
+** @brief IDs for user-level programs
+**
+** NOTE: this file is automatically generated when the user.img file
+** is created. Do not edit this manually!
+*/
+
+#ifndef USERIDS_H_
+#define USERIDS_H_
+
+#ifndef ASM_SRC
+/*
+** These IDs are used to identify the various user programs.
+** Each call to exec() will provide one of these as the first
+** argument.
+**
+** This list should be updated if/when the collection of
+** user processes changes.
+*/
+enum users_e {
+ Init, Idle, Shell, ProgABC, ProgDE, ProgFG, ProgH, ProgI,
+ ProgJ, ProgKL, ProgMN, ProgP, ProgQ, ProgR, ProgS, ProgTUV,
+ ProgW, ProgX, ProgY, ProgZ
+ // sentinel
+ , N_USERS
+};
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/vm.h b/include/vm.h
new file mode 100644
index 0000000..d557d5e
--- /dev/null
+++ b/include/vm.h
@@ -0,0 +1,433 @@
+/**
+** @file vm.h
+**
+** @author CSCI-452 class of 20245
+**
+** @brief Virtual memory-related declarations.
+*/
+
+#ifndef VM_H_
+#define VM_H_
+
+#include <defs.h>
+#include <types.h>
+
+#include <procs.h>
+
+/*
+** VM layout of the system
+**
+** User processes use the first 4MB of the 32-bit address space; see the
+** next comment for details.
+**
+** Kernel virtual addresses are in the "higher half" range, beginning
+** at 0x80000000. We define our mapping such that virtual address
+** 0x8nnnnnnn maps to physical address 0x0nnnnnnn, so converting between
+** the two is trivial.
+*/
+
+/*
+** VM layout of process' address space
+**
+** Processes are limited to the first 4MB of the 32-bit address space:
+**
+** Address Range Contents
+** ======================= ================================
+** 0x00000000 - 0x00000fff page 0 is inaccessible
+** 0x00001000 - 0x000..fff text occupies pages 1 - N
+** 0x000..000 - 0x000..fff data occupies pages N+1 - N+d
+** 0x000..000 - 0x000..fff bss occupies pages N+d+1 - N+d+b
+** 0x000..000 - 0x003fdfff unusable
+** 0x003fe000 - 0x003fffff stack occupies last two pages
+**
+** This gives us the following page table structure:
+**
+** Page directory:
+** Entries Contents
+** ======== ==============================
+** 0 point to PMT for address space
+** 1 - 1023 invalid
+**
+** Page map table:
+** Entries Contents
+** ======== ==============================
+** 0 invalid
+** 1 - N text frames
+** N+1 - N+d data frames
+** N+d+1 - N+d+b bss frames
+** N+d+b+1 - 1021 invalid
+** 1022 - 1023 stack frames
+*/
+
+/*
+** General (C and/or assembly) definitions
+*/
+
+// user virtual addresses
+#define USER_TEXT 0x00001000
+#define USER_STACK 0x003fe000
+#define USER_STK_END 0x00400000
+
+// how to find the addresses of the stack pages in the VM hierarchy
+// user address space is the first 4MB of virtual memory
+#define USER_PDE 0
+// the stack occupies the last two pages of the address space
+#define USER_STK_PTE1 1022
+#define USER_STK_PTE2 1023
+
+// some important memory addresses
+#define KERN_BASE 0x80000000 // start of "kernel" memory
+#define EXT_BASE 0x00100000 // start of "extended" memory (1MB)
+#define DEV_BASE 0xfe000000 // "device" memory
+#define PHYS_TOP 0x7fffffff // last usable physical address
+
+// where the kernel actually lives
+#define KERN_PLINK 0x00010000
+#define KERN_VLINK (KERN_BASE + KERN_PLINK)
+
+// physical/virtual converters
+#ifndef ASM_SRC
+// uses casting
+#define V2P(a) (((uint_t)(a)) - KERN_BASE)
+#define P2V(a) ((void *)(((uint_t)(a)) + KERN_BASE))
+#else
+// doesn't use casting
+#define V2P(a) ((a) - KERN_BASE)
+#define P2V(a) ((a) + KERN_BASE)
+#endif /* !ASM_SRC */
+
+// number of entries in a page directory or page table
+#define N_PDE 1024
+#define N_PTE 1024
+
+// index field shift counts and masks
+#define PDIX_SHIFT 22
+#define PTIX_SHIFT 12
+#define PIX2I_MASK 0x3ff
+
+#ifndef ASM_SRC
+// 4KB frame numbers are 20 bits wide
+#define FRAME_4K_SHIFT 12
+#define F2I_4K_MASK 0x000fffff
+#define TO_4KFRAME(n) (((n)&F2I_4K_MASK) << FRAME_4K_SHIFT)
+#define GET_4KFRAME(n) (((n) >> FRAME_4K_SHIFT)&F2I_4K_MASK)
+
+// 4MB frame numbers are 10 bits wide
+#define FRAME_4M_SHIFT 22
+#define F2I_4M_MASK 0x000003ff
+#define TO_4MFRAME(n) (((n)&F2I_4M_MASK) << FRAME_4M_SHIFT)
+#define GET_4MFRAME(n) (((n) >> FRAME_4M_SHIFT)&F2I_4M_MASK)
+
+// extract the PMT address or frame address from a table entry
+#define FRAME_MASK MOD4K_MASK
+#define PERM_MASK MOD4K_BITS
+#define PDE_ADDR(p) (((uint32_t)(p))&FRAME_MASK)
+#define PTE_ADDR(p) (((uint32_t)(p))&FRAME_MASK)
+#define PERMS(p) (((uint32_t)(p))&PERM_MASK)
+
+// extract the table indices from a 32-bit address
+#define PDIX(v) ((((uint32_t)(v)) >> PDIX_SHIFT) & PIX2I_MASK)
+#define PTIX(v) ((((uint32_t)(v)) >> PTIX_SHIFT) & PIX2I_MASK)
+
+// page-size address rounding macros
+#define SZ_PG_M1 MOD4K_BITS
+#define SZ_PG_MASK MOD4K_MASK
+#define PGUP(a) (((a)+SZ_PG_M1) & SZ_PG_MASK)
+#define PGDOWN(a) ((a) & SZ_PG_MASK)
+
+// page directory entry fields
+#define PDE_P 0x00000001
+#define PDE_RW 0x00000002
+#define PDE_US 0x00000004
+#define PDE_PWT 0x00000008
+#define PDE_PCD 0x00000010
+#define PDE_A 0x00000020
+#define PDE_AVL1 0x00000040
+#define PDE_PS 0x00000080
+#define PDE_AVL2 0x00000f00
+#define PDE_BA 0xfffff000
+
+// page table entry fields
+#define PTE_P 0x00000001
+#define PTE_RW 0x00000002
+#define PTE_US 0x00000004
+#define PTE_PWT 0x00000008
+#define PTE_PCD 0x00000010
+#define PTE_A 0x00000020
+#define PTE_D 0x00000040
+#define PTE_PAT 0x00000080
+#define PTE_G 0x00000100
+#define PTE_AVL2 0x00000e00
+#define PTE_FA 0xfffff000
+
+#define PG_CODE (PTE_USER | PTE_PRESENT)
+#define PG_DATA (PTE_USER | PTE_RW | PTE_PRESENT)
+
+// error code bit assignments for page faults
+#define PFLT_P 0x00000001
+#define PFLT_W 0x00000002
+#define PFLT_US 0x00000004
+#define PFLT_RSVD 0x00000008
+#define PFLT_ID 0x00000010
+#define PFLT_PK 0x00000020
+#define PFLT_SS 0x00000040
+#define PFLT_HLAT 0x00000080
+#define PFLT_SGX 0x00008000
+#define PFLT_UNUSED 0xffff7f00
+
+// create a pde/pte from an integer frame number and permission bits
+#define MKPDE(f,p) ((pde_t)( TO_FRAME((f)) | (p) ))
+#define MKPTE(f,p) ((pte_t)( TO_FRAME((f)) | (p) ))
+
+// is a PDE/PTE present?
+// (P bit is in the same place in both)
+#define IS_PRESENT(entry) (((entry) & PDE_P) != 0 )
+
+// is a PDE a 4MB page entry?
+#define IS_LARGE(pde) (((pde) & PDE_PS) != 0 )
+#endif /* !ASM_SRC */
+
+#ifndef ASM_SRC
+
+/*
+** Start of C-only definitions
+*/
+
+/*
+** Types
+*/
+
+// page directory entries
+
+// as a 32-bit word, in types.h
+// typedef uint32_t pde_t;
+
+// PDE for 4KB pages
+typedef struct pdek_s {
+ uint_t p :1; // present
+ uint_t rw :1; // writable
+ uint_t us :1; // user/supervisor
+ uint_t pwt :1; // cache write-through
+ uint_t pcd :1; // cache disable
+ uint_t a :1; // accessed
+ uint_t avl1 :1; // ignored (available)
+ uint_t ps :1; // page size (must be 0)
+ uint_t avl2 :4; // ignored (available)
+ uint_t fa :20; // frame address
+} pdek_f_t;
+
+// PDE for 4MB pages
+typedef struct pdem_s {
+ uint_t p :1; // present
+ uint_t rw :1; // writable
+ uint_t us :1; // user/supervisor
+ uint_t pwt :1; // cache write-through
+ uint_t pcd :1; // cache disable
+ uint_t a :1; // accessed
+ uint_t d :1; // dirty
+ uint_t ps :1; // page size (must be 1)
+ uint_t g :1; // global
+ uint_t avl :3; // ignored (available)
+ uint_t fa :20; // frame address
+} pdem_f_t;
+
+// page table entries
+
+// as a 32-bit word, in types.h
+// typedef uint32_t pte_t;
+
+// broken out into fields
+typedef struct pte_s {
+ uint_t p :1; // present
+ uint_t rw :1; // writable
+ uint_t us :1; // user/supervisor
+ uint_t pwt :1; // cache write-through
+ uint_t pcd :1; // cache disable
+ uint_t a :1; // accessed
+ uint_t d :1; // dirty
+ uint_t pat :1; // page attribute table in use
+ uint_t g :1; // global
+ uint_t avl :3; // ignored (available)
+ uint_t fa :20; // frame address
+} ptef_t;
+
+// page fault error code bits
+// comment: meaning when 1 / meaning when 0
+struct pfec_s {
+ uint_t p :1; // page-level protection violation / !present
+ uint_t w :1; // write / read
+ uint_t us :1; // user-mode access / supervisor-mode access
+ uint_t rsvd :1; // reserved bit violation / not
+ uint_t id :1; // instruction fetch / data fetch
+ uint_t pk :1; // protection-key violation / !pk
+ uint_t ss :1; // shadow stack access / !ss
+ uint_t hlat :1; // HLAT paging / ordinary paging or access rights
+ uint_t xtr1 :7; // unused
+ uint_t sgz :1; // SGX-specific access control violation / !SGX
+ uint_t xtr2 :16; // more unused
+};
+
+typedef union pfec_u {
+ uint32_t u;
+ struct pfec_s s;
+} pfec_t;
+
+// Mapping descriptor for VA::PA mappings
+typedef struct mapping_t {
+ uint32_t va_start; // starting virtual address for this range
+ uint32_t pa_start; // first physical address in the range
+ uint32_t pa_end; // last physical address in the range
+ uint32_t perm; // access control
+} mapping_t;
+
+/*
+** Globals
+*/
+
+// created page directory for the kernel
+extern pde_t *kpdir;
+
+/*
+** Prototypes
+*/
+
+/**
+** Name: vm_init
+**
+** Initialize the VM module
+**
+** Note: should not be called until after the memory free list has
+** been set up.
+*/
+void vm_init( void );
+
+/**
+** Name: vm_pagedup
+**
+** Duplicate a page of memory
+**
+** @param old Pointer to the first byte of a page
+**
+** @return a pointer to the new, duplicate page, or NULL
+*/
+void *vm_pagedup( void *old );
+
+/**
+** Name: vm_ptdup
+**
+** Duplicate a page directory entry
+**
+** @param dst Pointer to where the duplicate should go
+** @param curr Pointer to the entry to be duplicated
+**
+** @return true on success, else false
+*/
+bool_t vm_ptdup( pde_t *dst, pde_t *curr );
+
+/**
+** Name: vm_getpte
+**
+** Return the address of the PTE corresponding to the virtual address
+** 'va' within the address space controlled by 'pgdir'. If there is no
+** page table for that VA and 'alloc' is true, create the necessary
+** page table entries.
+**
+** @param pdir Pointer to the page directory to be searched
+** @param va The virtual address we're looking for
+** @param alloc Should we allocate a page table if there isn't one?
+**
+** @return A pointer to the page table entry for this VA, or NULL
+*/
+pte_t *vm_getpte( pde_t *pdir, const void *va, bool_t alloc );
+
+/**
+** Name: vm_mkkvm
+**
+** Create the kernel's page table hierarchy
+*/
+pde_t *vm_mkkvm( void );
+
+/**
+** Name: vm_mkuvm
+**
+** Create the page table hierarchy for a user process
+*/
+pde_t *vm_mkuvm( void );
+
+/**
+** Name: vm_set_kvm
+**
+** Switch the page table register to the kernel's page directory
+*/
+void vm_set_kvm( void );
+
+/**
+** Name: vm_set_uvm
+**
+** Switch the page table register to the page directory for a user process.
+**
+** @param p The PCB of the user process
+*/
+void vm_set_uvm( pcb_t *p );
+
+/**
+** Name: vm_add
+**
+** Add pages to the page hierarchy for a process, copying data into
+** them if necessary.
+**
+** @param pdir Pointer to the page directory to modify
+** @param wr "Writable" flag for the PTE
+** @param sys "System" flag for the PTE
+** @param va Starting VA of the range
+** @param size Amount of physical memory to allocate
+** @param data Pointer to data to copy, or NULL
+** @param bytes Number of bytes to copy
+**
+** @return status of the allocation attempt
+*/
+int vm_add( pde_t *pdir, bool_t wr, bool_t sys,
+ void *va, uint32_t size, char *data, uint32_t bytes );
+
+/**
+** Name: vm_free
+**
+** Deallocate a page table hierarchy and all physical memory frames
+** in the user portion.
+**
+** @param pdir Pointer to the page directory
+*/
+void vm_free( pde_t *pdir );
+
+/*
+** Name: vm_map
+**
+** Create PTEs for virtual addresses starting at 'va' that refer to
+** physical addresses in the range [pa, pa+size-1]. We aren't guaranteed
+** that va is page-aligned.
+**
+** @param pdir Page directory for this address space
+** @param va The starting virtual address
+** @param size Length of the range to be mapped
+** @param pa The starting physical address
+** @param perm Permission bits for the PTEs
+*/
+int vm_map( pde_t *pdir, void *va, uint_t size, uint_t pa, int perm );
+
+/**
+** Name: vm_uvmdup
+**
+** Create a duplicate of the user portio of an existing page table
+** hierarchy. We assume that the "new" page directory exists and
+** the system portions of it should not be touched.
+**
+** @param old Existing page directory
+** @param new New page directory
+**
+** @return status of the duplication attempt
+*/
+int vm_uvmdup( pde_t *old, pde_t *new );
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/vmtables.h b/include/vmtables.h
new file mode 100644
index 0000000..17f6e0a
--- /dev/null
+++ b/include/vmtables.h
@@ -0,0 +1,43 @@
+/**
+** @file vmtables.h
+**
+** @author CSCI-452 class of 20245
+**
+** @brief Predefined VM tables
+*/
+
+#ifndef VMTABLES_H_
+#define VMTABLES_H_
+
+#include <defs.h>
+#include <types.h>
+#include <vm.h>
+
+#ifndef ASM_SRC
+
+/*
+** Initial page directory, for when the kernel is starting up
+**
+** we use large (4MB) pages here to allow us to use a one-level
+** paging hierarchy; the kernel will create a new page table
+** hierarchy once memory is initialized
+*/
+extern pde_t firstpdir[];
+
+/*
+** "Identity" page map table.
+**
+** This just maps the first 4MB of physical memory. It is initialized
+** in vm_init().
+*/
+extern pte_t id_map[];
+
+/*
+** Kernel address mappings, present in every page table
+*/
+extern mapping_t kmap[];
+extern const uint32_t n_kmap;
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/x86/arch.h b/include/x86/arch.h
new file mode 100644
index 0000000..113c76b
--- /dev/null
+++ b/include/x86/arch.h
@@ -0,0 +1,303 @@
+/*
+** @file arch.h
+**
+** @author Warren R. Carithers
+** @author K. Reek
+**
+** Definitions of constants and macros for use
+** with the x86 architecture and registers.
+**
+*/
+
+#ifndef X86ARCH_H_
+#define X86ARCH_H_
+
+/*
+** Video stuff
+*/
+#define VID_BASE_ADDR 0xB8000
+
+/*
+** Memory management
+*/
+#define SEG_PRESENT 0x80
+#define SEG_PL_0 0x00
+#define SEG_PL_1 0x20
+#define SEG_PL_2 0x40
+#define SEG_PL_3 0x50
+#define SEG_SYSTEM 0x00
+#define SEG_NON_SYSTEM 0x10
+#define SEG_32BIT 0x04
+#define DESC_IGATE 0x06
+
+/*
+** Exceptions
+*/
+#define N_EXCEPTIONS 256
+
+/*
+** Bit definitions in registers
+**
+** See IA-32 Intel Architecture SW Dev. Manual, Volume 3: System
+** Programming Guide, page 2-8.
+*/
+
+/*
+** EFLAGS
+*/
+#define EFL_RSVD 0xffc00000 /* reserved */
+#define EFL_MB0 0x00008020 /* must be zero */
+#define EFL_MB1 0x00000002 /* must be 1 */
+
+#define EFL_ID 0x00200000
+#define EFL_VIP 0x00100000
+#define EFL_VIF 0x00080000
+#define EFL_AC 0x00040000
+#define EFL_VM 0x00020000
+#define EFL_RF 0x00010000
+#define EFL_NT 0x00004000
+#define EFL_IOPL 0x00003000
+#define EFL_OF 0x00000800
+#define EFL_DF 0x00000400
+#define EFL_IF 0x00000200
+#define EFL_TF 0x00000100
+#define EFL_SF 0x00000080
+#define EFL_ZF 0x00000040
+#define EFL_AF 0x00000010
+#define EFL_PF 0x00000004
+#define EFL_CF 0x00000001
+
+/*
+** CR0, CR1, CR2, CR3, CR4
+**
+** IA-32 V3, page 2-12.
+*/
+#define CR0_RSVD 0x1ffaffc0
+#define CR0_PG 0x80000000
+#define CR0_CD 0x40000000
+#define CR0_NW 0x20000000
+#define CR0_AM 0x00040000
+#define CR0_WP 0x00010000
+#define CR0_NE 0x00000020
+#define CR0_ET 0x00000010
+#define CR0_TS 0x00000008
+#define CR0_EM 0x00000004
+#define CR0_MP 0x00000002
+#define CR0_PE 0x00000001
+
+#define CR1_RSVD 0xffffffff
+
+#define CR2_RSVD 0x00000000
+#define CR2_PF_LIN_ADDR 0xffffffff
+
+#define CR3_RSVD 0x00000fe7
+#define CR3_PD_BASE 0xfffff000
+#define CR3_PCD 0x00000010
+#define CR3_PWT 0x00000008
+
+#define CR4_RSVD 0xfd001000
+#define CR4_UINT 0x02000000
+#define CR4_PKS 0x01000000
+#define CR4_CET 0x00800000
+#define CR4_PKE 0x00400000
+#define CR4_SMAP 0x00200000
+#define CR4_SMEP 0x00100000
+#define CR4_KL 0x00080000
+#define CR4_OSXS 0x00040000
+#define CR4_PCID 0x00020000
+#define CR4_FSGS 0x00010000
+#define CR4_SMXE 0x00004000
+#define CR4_VMXE 0x00002000
+#define CR4_LA57 0x00001000
+#define CR4_UMIP 0x00000800
+#define CR4_OSXMMEXCPT 0x00000400
+#define CR4_OSFXSR 0x00000200
+#define CR4_PCE 0x00000100
+#define CR4_PGE 0x00000080
+#define CR4_MCE 0x00000040
+#define CR4_PAE 0x00000020
+#define CR4_PSE 0x00000010
+#define CR4_DE 0x00000008
+#define CR4_TSD 0x00000004
+#define CR4_PVI 0x00000002
+#define CR4_VME 0x00000001
+
+/*
+** PMode segment selector field masks
+**
+** IA-32 V3, page 3-8.
+*/
+#define SEG_SEL_IX_MASK 0xfff8
+#define SEG_SEL_TI_MASK 0x0004
+#define SEG_SEL_RPL_MASK 0x0003
+
+/*
+** Segment descriptor bytes
+**
+** IA-32 V3, page 3-10.
+**
+** Bytes:
+** 0, 1: segment limit 15:0
+** 2, 3: base address 15:0
+** 4: base address 23:16
+** 7: base address 31:24
+*/
+
+/*
+** Byte 5: access control bits
+** 7: present
+** 6-5: DPL
+** 4: system/user
+** 3-0: type
+*/
+#define SEG_ACCESS_P_MASK 0x80
+# define SEG_PRESENT 0x80
+# define SEG_NOT_PRESENT 0x00
+
+#define SEG_ACCESS_DPL_MASK 0x60
+# define SEG_DPL_0 0x00
+# define SEG_DPL_1 0x20
+# define SEG_DPL_2 0x40
+# define SEG_DPL_3 0x60
+
+#define SEG_ACCESS_S_MASK 0x10
+# define SEG_SYSTEM 0x00
+# define SEG_NON_SYSTEM 0x10
+
+#define SEG_TYPE_MASK 0x0f
+# define SEG_DATA_A_BIT 0x1
+# define SEG_DATA_W_BIT 0x2
+# define SEG_DATA_E_BIT 0x4
+# define SEG_CODE_A_BIT 0x1
+# define SEG_CODE_R_BIT 0x2
+# define SEG_CODE_C_BIT 0x4
+# define SEG_DATA_RO 0x0
+# define SEG_DATA_ROA 0x1
+# define SEG_DATA_RW 0x2
+# define SEG_DATA_RWA 0x3
+# define SEG_DATA_RO_XD 0x4
+# define SEG_DATA_RO_XDA 0x5
+# define SEG_DATA_RW_XW 0x6
+# define SEG_DATA_RW_XWA 0x7
+# define SEG_CODE_XO 0x8
+# define SEG_CODE_XOA 0x9
+# define SEG_CODE_XR 0xa
+# define SEG_CODE_XRA 0xb
+# define SEG_CODE_XO_C 0xc
+# define SEG_CODE_XO_CA 0xd
+# define SEG_CODE_XR_C 0xe
+# define SEG_CODE_XR_CA 0xf
+
+/*
+** Byte 6: sizes
+** 7: granularity
+** 6: d/b
+** 5: long mode
+** 4: available!
+** 3-0: upper 4 bits of limit
+** 7: base address 31:24
+*/
+#define SEG_SIZE_G_MASK 0x80
+# define SEG_GRAN_BYTE 0x00
+# define SEG_GRAN_4KBYTE 0x80
+
+#define SEG_SIZE_D_B_MASK 0x40
+# define SEG_DB_16BIT 0x00
+# define SEG_DB_32BIT 0x40
+
+#define SEG_SIZE_L_MASK 0x20
+# define SEG_L_64BIT 0x20
+# define SEG_L_32BIT 0x00
+
+#define SEG_SIZE_AVL_MASK 0x10
+
+#define SEG_SIZE_LIM_19_16_MASK 0x0f
+
+
+/*
+** System-segment and gate-descriptor types
+**
+** IA-32 V3, page 3-15.
+*/
+ // type 0: reserved
+#define SEG_SYS_16BIT_TSS_AVAIL 0x1
+#define SEG_SYS_LDT 0x2
+#define SEG_SYS_16BIT_TSS_BUSY 0x3
+#define SEG_SYS_16BIT_CALL_GATE 0x4
+#define SEG_SYS_TASK_GATE 0x5
+#define SEG_SYS_16BIT_INT_GATE 0x6
+#define SEG_SYS_16BIT_TRAP_GATE 0x7
+ // type 8: reserved
+#define SEG_SYS_32BIT_TSS_AVAIL 0x9
+ // type A: reserved
+#define SEG_SYS_32BIT_TSS_BUSY 0xb
+#define SEG_SYS_32BIT_CALL_GATE 0xc
+ // type D: reserved
+#define SEG_SYS_32BIT_INT_GATE 0xe
+#define SEG_SYS_32BIT_TRAP_GATE 0xf
+
+/*
+** IDT Descriptors
+**
+** IA-32 V3, page 5-13.
+**
+** All have a segment selector in bytes 2 and 3; Task Gate descriptors
+** have bytes 0, 1, 4, 6, and 7 reserved; others have bytes 0, 1, 6,
+** and 7 devoted to the 16 bits of the Offset, with the low nybble of
+** byte 4 reserved.
+*/
+#define IDT_PRESENT 0x8000
+#define IDT_DPL_MASK 0x6000
+# define IDT_DPL_0 0x0000
+# define IDT_DPL_1 0x2000
+# define IDT_DPL_2 0x4000
+# define IDT_DPL_3 0x6000
+#define IDT_GATE_TYPE 0x0f00
+# define IDT_TASK_GATE 0x0500
+# define IDT_INT16_GATE 0x0600
+# define IDT_INT32_GATE 0x0e00
+# define IDT_TRAP16_GATE 0x0700
+# define IDT_TRAP32_GATE 0x0f00
+
+/*
+** Interrupt vectors
+*/
+
+// predefined by the architecture
+#define VEC_DIVIDE_ERROR 0x00
+#define VEC_DEBUG_EXCEPTION 0x01
+#define VEC_NMI_INTERRUPT 0x02
+#define VEC_BREAKPOINT 0x03
+#define VEC_OVERFLOW 0x04
+#define VEC_BOUND_RANGE_EXCEEDED 0x05
+#define VEC_INVALID_OPCODE 0x06
+#define VEC_DEVICE_NOT_AVAILABLE 0x07
+#define VEC_DOUBLE_FAULT 0x08
+#define VEC_COPROCESSOR_OVERRUN 0x09
+#define VEC_INVALID_TSS 0x0a
+#define VEC_SEGMENT_NOT_PRESENT 0x0b
+#define VEC_STACK_FAULT 0x0c
+#define VEC_GENERAL_PROTECTION 0x0d
+#define VEC_PAGE_FAULT 0x0e
+// 0x0f is reserved - unused
+#define VEC_FPU_ERROR 0x10
+#define VEC_ALIGNMENT_CHECK 0x11
+#define VEC_MACHINE_CHECK 0x12
+#define VEC_SIMD_FP_EXCEPTION 0x13
+#define VEC_VIRT_EXCEPTION 0x14
+#define VEC_CTRL_PROT_EXCEPTION 0x15
+// 0x16 through 0x1f are reserved
+
+// 0x20 through 0xff are user-defined, non-reserved
+
+// IRQ0 through IRQ15 will use vectors 0x20 through 0x2f
+#define VEC_TIMER 0x20
+#define VEC_KBD 0x21
+#define VEC_COM2 0x23
+#define VEC_COM1 0x24
+#define VEC_PARALLEL 0x25
+#define VEC_FLOPPY 0x26
+#define VEC_MYSTERY 0x27
+#define VEC_MOUSE 0x2c
+
+#endif
diff --git a/include/x86/bios.h b/include/x86/bios.h
new file mode 100644
index 0000000..a19e570
--- /dev/null
+++ b/include/x86/bios.h
@@ -0,0 +1,73 @@
+/*
+** @file bios.h
+**
+** @author Warren R. Carithers
+**
+** BIOS-related declarations
+*/
+
+#ifndef BIOS_H_
+#define BIOS_H_
+
+/*
+** BIOS-related memory addresses
+*/
+
+#define BIOS_BDA 0x0400
+
+/*
+** Selected BIOS interrupt numbers
+*/
+
+#define BIOS_TIMER 0x08
+#define BIOS_KBD 0x09
+#define BIOS_VIDEO 0x10
+#define BIOS_EQUIP 0x11
+#define BIOS_MSIZ 0x12
+#define BIOS_DISK 0x13
+#define BIOS_SERIAL 0x14
+#define BIOS_MISC 0x15
+#define BIOS_KBDSVC 0x16
+#define BIOS_PRTSVC 0x17
+#define BIOS_BOOT 0x19
+#define BIOS_RTCPCI 0x1a
+
+// BIOS video commands (AH)
+#define BV_W_ADV 0x0e
+
+// BIOS disk commands (AH)
+#define BD_RESET 0x00
+#define BD_CHECK 0x01
+#define BD_RDSECT 0x02
+#define BD_WRSECT 0x03
+#define BD_PARAMS 0x08
+
+// BIOS disk commands with parameters (AX)
+#define BD_READ(n) ((BD_RDSECT << 8) | (n))
+#define BD_READ1 0x0201
+
+// CMOS ports (used for masking NMIs)
+#define CMOS_ADDR 0x70
+#define CMOS_DATA 0x71
+
+// important related commands
+#define NMI_ENABLE 0x00
+#define NMI_DISABLE 0x80
+
+/*
+** Physical Memory Map Table (0000:2D00 - 0000:7c00)
+**
+** Primarily used with the BIOS_MISC interrupt
+*/
+#define MMAP_SEG 0x02D0
+#define MMAP_DISP 0x0000
+#define MMAP_ADDR ((MMAP_SEG << 4) + MMAP_DISP)
+#define MMAP_SECTORS 0x0a
+
+#define MMAP_ENT 24 /* bytes per entry */
+#define MMAP_MAX_ENTS (BOOT_ADDR - MMAP_ADDR - 4) / 24
+
+#define MMAP_CODE 0xE820 /* int 0x15 code */
+#define MMAP_MAGIC_NUM 0x534D4150 /* for 0xE820 interrupt */
+
+#endif
diff --git a/include/x86/ops.h b/include/x86/ops.h
new file mode 100644
index 0000000..ad795b9
--- /dev/null
+++ b/include/x86/ops.h
@@ -0,0 +1,443 @@
+/**
+** @file ops.h
+**
+** @author Warren R. Carithers
+**
+** @brief Inline escapes to assembly for efficiency
+**
+** Inspiration from:
+** Martins Mozeiko, https://gist.github.com/mmozeiko/f68ad2546bd6ab953315
+** MIT's xv6, https://github.com/mit-pdos/xv6-public
+**
+** Note: normally, GCC doesn't inline unless the optimization level is
+** over 1. This can be forced by adding
+**
+** __attribute__((always_inline))
+**
+** after the parameter list on each declaration. This is enabled by
+** defining the compile-time CPP symbol FORCE_INLINING.
+*/
+
+#ifndef OPS_H_
+#define OPS_H_
+
+#include <common.h>
+
+#ifndef ASM_SRC
+
+// control "forced" inlining
+#ifdef FORCE_INLINING
+#define OPSINLINED __attribute__((always_inline))
+#else
+#define OPSINLINED /* no-op */
+#endif /* FORCE_INLINING */
+
+/****************************
+** Data movement
+****************************/
+
+/**
+** Block move functions
+**
+** Variations: movsb(), movsl(), movsq()
+**
+** Description: Copy from source buffer to destination buffer
+**
+** @param dst Destination buffer
+** @param src Source buffer
+** @param len Byte count
+*/
+static inline void
+movsb( void* dst, const void* src, uint32_t len ) OPSINLINED
+{
+ __asm__ __volatile__( "cld; rep movsb"
+ : "+D"(dst), "+S"(src), "+c"(len)
+ : : "memory" );
+}
+
+static inline void
+movsw( void* dst, const void* src, uint32_t len ) OPSINLINED
+{
+ __asm__ __volatile__( "cld; rep movsw"
+ : "+D"(dst), "+S"(src), "+c"(len)
+ : : "memory" );
+}
+
+static inline void
+movsl( void* dst, const void* src, uint32_t len ) OPSINLINED
+{
+ __asm__ __volatile__( "cld; rep movsl"
+ : "+D"(dst), "+S"(src), "+c"(len)
+ : : "memory" );
+}
+
+static inline void
+movsq( void* dst, const void* src, uint32_t len ) OPSINLINED
+{
+ __asm__ __volatile__( "cld; rep movsq"
+ : "+D"(dst), "+S"(src), "+c"(len)
+ : : "memory" );
+}
+
+/**
+** Block store functions
+**
+** Variations: stosb(), stosw(), stosl()
+**
+** Description: Store a specific value into destination buffer
+**
+** @param dst Destination buffer
+** @param val Data to copy
+** @param len Byte count
+*/
+static inline void
+stosb( void *dst, uint8_t val, uint32_t len ) OPSINLINED
+{
+ __asm__ __volatile__( "cld; rep stosb"
+ : "=D" (dst), "=c" (len)
+ : "0" (dst), "1" (len), "a" (val)
+ : "memory", "cc" );
+}
+
+static inline void
+stosw( void *dst, uint16_t val, uint32_t len ) OPSINLINED
+{
+ __asm__ __volatile__( "cld; rep stos2"
+ : "=D" (dst), "=c" (len)
+ : "0" (dst), "1" (len), "a" (val)
+ : "memory", "cc" );
+}
+
+static inline void
+stosl( void *dst, uint32_t val, uint32_t len ) OPSINLINED
+{
+ __asm__ __volatile__( "cld; rep stosl"
+ : "=D" (dst), "=c" (len)
+ : "0" (dst), "1" (len), "a" (val)
+ : "memory", "cc" );
+}
+
+/****************************
+** Special register access
+****************************/
+
+/**
+** Register read functions
+**
+** Variations: r_cr0(), r_cr2(), r_cr3(), r_cr4(), r_eflags(),
+** r_ebp(), r_esp()
+**
+** Description: Reads the register indicated by its name
+**
+** @return Contents of the register
+*/
+static inline uint32_t
+r_cr0( void ) OPSINLINED
+{
+ uint32_t val;
+ __asm__ __volatile__( "movl %%cr0,%0" : "=r" (val) );
+ return val;
+}
+
+static inline uint32_t
+r_cr2( void ) OPSINLINED
+{
+ uint32_t val;
+ __asm__ __volatile__( "movl %%cr2,%0" : "=r" (val) );
+ return val;
+}
+
+static inline uint32_t
+r_cr3( void ) OPSINLINED
+{
+ uint32_t val;
+ __asm__ __volatile__( "movl %%cr3,%0" : "=r" (val) );
+ return val;
+}
+
+static inline uint32_t
+r_cr4( void ) OPSINLINED
+{
+ uint32_t val;
+ __asm__ __volatile__( "movl %%cr4,%0" : "=r" (val) );
+ return val;
+}
+
+static inline uint32_t
+r_eflags(void) OPSINLINED
+{
+ uint32_t val;
+ __asm__ __volatile__( "pushfl; popl %0" : "=r" (val) );
+ return val;
+}
+
+static inline uint32_t
+r_ebp(void) OPSINLINED
+{
+ uint32_t val;
+ __asm__ __volatile__( "movl %%ebp,%0" : "=r" (val) );
+ return val;
+}
+
+static inline uint32_t
+r_esp(void) OPSINLINED
+{
+ uint32_t val;
+ __asm__ __volatile__( "movl %%esp,%0" : "=r" (val) );
+ return val;
+}
+
+/**
+** Register write functions
+**
+** Variations: w_cr0(), w_cr2(), w_cr3(), w_cr4(), w_eflags()
+**
+** Description: Writes a value into the CR indicated by its name
+*/
+static inline void
+w_cr0( uint32_t val ) OPSINLINED
+{
+ __asm__ __volatile__( "movl %0,%%cr0" : : "r" (val) );
+}
+
+static inline void
+w_cr2( uint32_t val ) OPSINLINED
+{
+ __asm__ __volatile__( "movl %0,%%cr2" : : "r" (val) );
+}
+
+static inline void
+w_cr3( uint32_t val ) OPSINLINED
+{
+ __asm__ __volatile__( "movl %0,%%cr3" : : "r" (val) );
+}
+
+static inline void
+w_cr4( uint32_t val ) OPSINLINED
+{
+ __asm__ __volatile__( "movl %0,%%cr4" : : "r" (val) );
+}
+
+static inline void
+w_eflags(uint32_t eflags) OPSINLINED
+{
+ __asm__ __volatile__( "pushl %0; popfl" : : "r" (eflags) );
+}
+
+/**
+** Descriptor table load functions
+**
+** Variations: w_gdt(), w_idt()
+**
+** Description: Load an address into the specified processor register
+**
+** @param addr The value to be loaded into the register
+*/
+static inline void
+w_gdt( void *addr ) OPSINLINED
+{
+ __asm__ __volatile__( "lgdt (%0)" : : "r" (addr) );
+}
+
+static inline void
+w_idt( void *addr ) OPSINLINED
+{
+ __asm__ __volatile__( "lidt (%0)" : : "r" (addr) );
+}
+
+/**
+** CPU ID access
+**
+** Description: Retrieve CPUID information
+**
+** @param op Value to be placed into %eax for the operation
+** @param ap Pointer to where %eax contents should be saved, or NULL
+** @param bp Pointer to where %ebx contents should be saved, or NULL
+** @param cp Pointer to where %ecx contents should be saved, or NULL
+** @param dp Pointer to where %edx contents should be saved, or NULL
+*/
+static inline void
+cpuid( uint32_t op, uint32_t *ap, uint32_t *bp,
+ uint32_t *cp, uint32_t *dp ) OPSINLINED
+{
+ uint32_t eax, ebx, ecx, edx;
+ __asm__ __volatile__( "cpuid"
+ : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
+ : "a" (op) );
+
+ if( ap ) *ap = eax;
+ if( bp ) *bp = ebx;
+ if( cp ) *cp = ecx;
+ if( dp ) *dp = edx;
+}
+
+/****************************
+** TLB management
+****************************/
+
+/**
+** TLB invalidation for one page
+**
+** Description: Invalidate the TLB entry for an address
+**
+** @param addr An address within the page to be flushed
+*/
+static inline void
+invlpg( uint32_t addr ) OPSINLINED
+{
+ __asm__ __volatile__( "invlpg (%0)" : : "r" (addr) : "memory" );
+}
+
+/**
+** TLB invalidation for all pages
+**
+** Description: Flush all entries from the TLB
+**
+** We do this by changing CR3.
+*/
+static inline void
+flushtlb( void ) OPSINLINED
+{
+ uint32_t cr3;
+ __asm__ __volatile__( "movl %%cr3,%0" : "=r" (cr3) );
+ __asm__ __volatile__( "movl %0,%%cr2" : : "r" (cr3) );
+}
+
+/****************************
+** I/O instructions
+****************************/
+
+/**
+** Name: inN
+**
+** Variations: inb(), inw(), inl()
+**
+** Description: Read some amount of data from the supplied I/O port
+**
+** @param port The i/o port to read from
+**
+** @return The data read from the specified port
+*/
+static inline uint8_t
+inb( int port ) OPSINLINED
+{
+ uint8_t data;
+ __asm__ __volatile__( "inb %w1,%0" : "=a" (data) : "d" (port) );
+ return data;
+}
+
+static inline uint16_t
+inw( int port ) OPSINLINED
+{
+ uint16_t data;
+ __asm__ __volatile__( "inw %w1,%0" : "=a" (data) : "d" (port) );
+ return data;
+}
+
+static inline uint32_t
+inl( int port ) OPSINLINED
+{
+ uint32_t data;
+ __asm__ __volatile__( "inl %w1,%0" : "=a" (data) : "d" (port) );
+ return data;
+}
+
+/**
+** Name: outN
+**
+** Variations: outb(), outw(), outl()
+**
+** Description: Write some data to the specified I/O port
+**
+** @param port The i/o port to write to
+** @param data The data to be written to the port
+**
+** @return The data read from the specified port
+*/
+static inline void
+outb( int port, uint8_t data ) OPSINLINED
+{
+ __asm__ __volatile__( "outb %0,%w1" : : "a" (data), "d" (port) );
+}
+
+static inline void
+outw( int port, uint16_t data ) OPSINLINED
+{
+ __asm__ __volatile__( "outw %0,%w1" : : "a" (data), "d" (port) );
+}
+
+static inline void
+outl( int port, uint32_t data ) OPSINLINED
+{
+ __asm__ __volatile__( "outl %0,%w1" : : "a" (data), "d" (port) );
+}
+
+/****************************
+** Miscellaneous instructions
+****************************/
+
+/**
+** Name: breakpoint
+**
+** Description: Cause a breakpoint interrupt for debugging purposes
+*/
+static inline void
+breakpoint( void ) OPSINLINED
+{
+ __asm__ __volatile__( "int3" );
+}
+
+/**
+** Name: get_ra
+**
+** Description: Get the return address for the calling function
+** (i.e., where whoever called us will go back to)
+**
+** @return The address the calling routine will return to as a uint32_t
+*/
+static inline uint32_t
+get_ra( void ) OPSINLINED
+{
+ uint32_t val;
+ __asm__ __volatile__( "movl 4(%%ebp),%0" : "=r" (val) );
+ return val;
+}
+
+/**
+** Name: ev_wait
+**
+** Description: Pause until something happens
+*/
+static inline void
+ev_wait( void ) OPSINLINED
+{
+ __asm__ __volatile__( "sti ; hlt" );
+}
+
+
+/**
+** Name: xchgl
+**
+** Description: Perform an atomic exchange with memory
+**
+** @param addr Memory location to be modified
+** @param data Data to exchange
+**
+** @return The old contents of the memory location
+*/
+static inline uint32_t
+xchgl( volatile uint32_t *addr, uint32_t data ) OPSINLINED
+{
+ uint32_t old;
+
+ // + indicates a read-modify-write operand
+ __asm__ __volatile__( "lock; xchgl %0, %1"
+ : "+m" (*addr), "=a" (old)
+ : "1" (data)
+ : "cc");
+ return old;
+}
+
+#endif /* !ASM_SRC */
+
+#endif
diff --git a/include/x86/pic.h b/include/x86/pic.h
new file mode 100644
index 0000000..d4fa93b
--- /dev/null
+++ b/include/x86/pic.h
@@ -0,0 +1,139 @@
+/**
+** @file pic.h
+**
+** @author Warren R. Carithers
+** @author K. Reek
+**
+** Definitions of constants and macros for the Intel 8259 Programmable
+** Interrupt Controller.
+**
+*/
+
+#ifndef X86PIC_H_
+#define X86PIC_H_
+
+/*
+** Our expected configuration is two PICs, with the secondary connected
+** through the IRQ2 pin of the primary.
+*/
+
+/*
+** Port addresses for the command port and interrupt mask register port
+** for both the primary and secondary PICs.
+*/
+#define PIC1_CMD 0x20 // primary command
+#define PIC1_DATA (PIC1_CMD + 1) // primary data / int mask register
+#define PIC2_CMD 0xA0 // secondary command
+#define PIC2_DATA (PIC2_CMD + 1) // secondary data / int mask register
+
+/*
+** Initialization Command Word (ICW) definitions
+**
+** Initialization sequence:
+** ICW1 Init command is sent to each command port.
+** ICW2 vector commands are sent to the data ports.
+** If "cascade mode" was selected, send ICW3 commands to the data ports.
+** If "need ICW4" was selected, send ICW4 commands to the data ports.
+**
+** Following that sequence, the PIC is ready to accept interrupts;
+** it will also accept Output Command Words (OCWs) to the data ports.
+**
+** PIC1_* defines are intended for the primary PIC
+** PIC2_* defines are intended for the secondary PIC
+** PIC_* defines are sent to both PICs
+*/
+
+/*
+** ICW1: initialization, send to command port
+*/
+#define PIC_CW1_INIT 0x10 // start initialization sequence
+#define PIC_CW1_NEED4 0x01 // ICW4 will also be set
+#define PIC_CW1_SINGLE 0x02 // select single (vs. cascade) mode
+#define PIC_CW1_INTVAL 0x04 // set call interval to 4 (vs. 8)
+#define PIC_CW1_LEVEL 0x08 // use level-triggered mode (vs. edge)
+
+/*
+** ICW2: interrupt vector base offsets, send to data port
+*/
+#define PIC1_CW2_VECBASE 0x20 // IRQ0 int vector number
+#define PIC2_CW2_VECBASE 0x28 // IRQ8 int vector number
+
+/*
+** ICW3: secondary::primary attachment, send to data port
+*/
+#define PIC1_CW3_SEC_IRQ2 0x04 // bit mask: secondary is on pin 2
+#define PIC2_CW3_SEC_ID 0x02 // integer: secondary id
+
+/*
+** ICW4: operating mode, send to data port
+*/
+#define PIC_CW4_PM86 0x01 // 8086 mode (vs. 8080/8085)
+#define PIC_CW4_AUTOEOI 0x02 // do auto eoi's
+#define PIC_CW4_UNBUF 0x00 // unbuffered mode
+#define PIC_CW4_SEC_BUF 0x08 // put secondary in buffered mode
+#define PIC_CW4_PRI_BUF 0x0C // put primary in buffered mode
+#define PIC_CW4_SFNMODE 0x10 // "special fully nested" mode
+
+/*
+** Operation Control Words (OCWs)
+**
+** After the init sequence, can send these
+*/
+
+/*
+** OCW1: interrupt mask; send to data port
+*/
+#define PIC_MASK_NONE 0x00 // allow all interrupts
+#define PIC_MASK_NO_IRQ0 0x01 // prevent IRQ0 interrupts
+#define PIC_MASK_NO_IRQ1 0x02 // prevent IRQ1 interrupts
+#define PIC_MASK_NO_IRQ2 0x04 // prevent IRQ2 interrupts
+#define PIC_MASK_NO_IRQ3 0x08 // prevent IRQ3 interrupts
+#define PIC_MASK_NO_IRQ4 0x10 // prevent IRQ4 interrupts
+#define PIC_MASK_NO_IRQ5 0x20 // prevent IRQ5 interrupts
+#define PIC_MASK_NO_IRQ6 0x40 // prevent IRQ6 interrupts
+#define PIC_MASK_NO_IRQ7 0x80 // prevent IRQ7 interrupts
+#define PIC_MASK_ALL 0xff // prevent all interrupts
+
+/*
+** OCW2: EOI control, interrupt level; send to command port
+*/
+#define PIC_LVL_0 0x00 // act on IRQ level 0
+#define PIC_LVL_1 0x01 // act on IRQ level 1
+#define PIC_LVL_2 0x02 // act on IRQ level 2
+#define PIC_LVL_3 0x03 // act on IRQ level 3
+#define PIC_LVL_4 0x04 // act on IRQ level 4
+#define PIC_LVL_5 0x05 // act on IRQ level 5
+#define PIC_LVL_6 0x06 // act on IRQ level 6
+#define PIC_LVL_7 0x07 // act on IRQ level 7
+
+#define PIC_EOI_NON_SPEC 0x20 // non-specific EOI command
+# define PIC_EOI PIC_EOI_NON_SPEC
+
+#define PIC_EOI_SPEC 0x60 // specific EOI command
+# define PIC_SEOI PIC_EOI_SPEC
+# define PIC_SEOI_LVL0 (PIC_EOI_SPEC | PIC_LVL_0)
+# define PIC_SEOI_LVL1 (PIC_EOI_SPEC | PIC_LVL_1)
+# define PIC_SEOI_LVL2 (PIC_EOI_SPEC | PIC_LVL_2)
+# define PIC_SEOI_LVL3 (PIC_EOI_SPEC | PIC_LVL_3)
+# define PIC_SEOI_LVL4 (PIC_EOI_SPEC | PIC_LVL_4)
+# define PIC_SEOI_LVL5 (PIC_EOI_SPEC | PIC_LVL_5)
+# define PIC_SEOI_LVL6 (PIC_EOI_SPEC | PIC_LVL_6)
+# define PIC_SEOI_LVL7 (PIC_EOI_SPEC | PIC_LVL_7)
+
+#define PIC_EOI_ROT_NONSP 0xa0 // rotate on non-spec EOI cmd
+#define PIC_EOI_SET_ROT_AUTO 0x80 // set "rotate in auto EOI mode"
+#define PIC_EOI_CLR_ROT_AUTO 0x00 // clear "rotate in auto EOI mode"
+#define PIC_EOI_ROT_SPEC 0xe0 // rotate on spec EOI cmd (+ level)
+#define PIC_EOI_SET_PRIO 0xc0 // set priority (+ level)
+#define PIC_EOI_NOP 0x40 // no operation
+
+/*
+** OCW3: read requests, special mask mode; send to command port
+*/
+#define PIC_READIRR 0x0a // read the IR register
+#define PIC_READISR 0x0b // read the IS register
+#define PIC_POLL 0x0c // poll
+#define PIC_MASK_RESET 0x48 // reset special mask mode
+#define PIC_MASK_SET 0x68 // set special mask mode
+
+#endif
diff --git a/include/x86/pit.h b/include/x86/pit.h
new file mode 100644
index 0000000..269fcec
--- /dev/null
+++ b/include/x86/pit.h
@@ -0,0 +1,82 @@
+/*
+** @file pit.h
+**
+** @author Warren R. Carithers
+** @author K. Reek
+**
+** Definitions of constants and macros for the
+** Intel 8254 Programmable Interval Timer
+**
+*/
+
+#ifndef X86PIT_H_
+#define X86PIT_H_
+
+
+/*
+** Hardware timer (Intel 8254 Programmable Interval Timer)
+**
+** Control word layout:
+**
+** Bit 7 6 | 5 4 | 3 2 1 | 0
+** Field SC1 SC0|RW1 RW0|M2 M1 M0 |BCD
+**
+** SC - select counter
+** RW - read/write
+** M - mode
+** BCD - binary or BCD counter
+*/
+
+/* Frequency settings */
+#define PIT_DEFAULT_TICKS_PER_SECOND 18 // actually 18.2065Hz
+#define PIT_DEFAULT_MS_PER_TICK (1000/PIT_DEFAULT_TICKS_PER_SECOND)
+#define PIT_FREQ 1193182 // clock cycles/sec
+
+/* Port assignments */
+#define PIT_BASE_PORT 0x40 // I/O port for the timer
+# define PIT_0_PORT (PIT_BASE_PORT)
+# define PIT_1_PORT (PIT_BASE_PORT+1)
+# define PIT_2_PORT (PIT_BASE_PORT+2)
+# define PIT_CONTROL_PORT (PIT_BASE_PORT+3)
+
+/* BCD field */
+#define PIT_USE_DECIMAL 0x00 // 16-bit binary counter (default)
+#define PIT_USE_BCD 0x01 // BCD counter
+
+/* Timer modes */
+#define PIT_MODE_0 0x00 // int on terminal count
+#define PIT_MODE_1 0x02 // one-shot
+#define PIT_MODE_2 0x04 // divide-by-N
+#define PIT_MODE_3 0x06 // square-wave
+#define PIT_MODE_4 0x08 // software strobe
+#define PIT_MODE_5 0x0a // hardware strobe
+
+/* Timer 0 settings */
+#define PIT_0_SELECT 0x00 // select timer 0
+#define PIT_0_LOAD 0x30 // load LSB, then MSB
+#define PIT_0_NDIV PIT_MODE_2 // divide-by-N counter
+#define PIT_0_SQUARE PIT_MODE_3 // square-wave mode
+#define PIT_0_ENDSIGNAL 0x00 // assert OUT at end of count
+
+/* Timer 1 settings */
+#define PIT_1_SELECT 0x40 // select timer 1
+#define PIT_1_READ 0x30 // read/load LSB then MSB
+#define PIT_1_RATE 0x06 // square-wave, for USART
+
+/* Timer 2 settings */
+#define PIT_2_SELECT 0x80 // select timer 1
+#define PIT_2_READ 0x30 // read/load LSB then MSB
+#define PIT_2_RATE 0x06 // square-wave, for USART
+
+/* Timer read-back */
+#define PIT_READBACK 0xc0 // perform a read-back
+#define PIT_RB_NOT_COUNT 0x20 // don't latch the count
+#define PIT_RB_NOT_STATUS 0x10 // don't latch the status
+#define PIT_RB_CHAN_2 0x08 // read back channel 2
+#define PIT_RB_CHAN_1 0x04 // read back channel 1
+#define PIT_RB_CHAN_0 0x02 // read back channel 0
+#define PIT_RB_ACCESS_MASK 0x30 // access mode field
+#define PIT_RB_OP_MASK 0x0e // oper mode field
+#define PIT_RB_BCD_MASK 0x01 // BCD mode field
+
+#endif
diff --git a/include/x86/uart.h b/include/x86/uart.h
new file mode 100644
index 0000000..0c6194b
--- /dev/null
+++ b/include/x86/uart.h
@@ -0,0 +1,349 @@
+/*
+** @file uart.h
+**
+** @author M. Reek
+** @authors K. Reek, Warren R. Carithers
+**
+** Definitions for a 16540/16550 compatible UART. Definitions are taken
+** from datasheets for the National Semiconductor INS8250, NS16450, and
+** NS16550 UART chips, and the PC87309 Super I/O legacy peripheral chip.
+**
+** The naming convention is UAx_yyy_zzzzz. "x" is either 4 or 5 (see below),
+** "yyy" is the name of the register to which this value applies, and
+** "zzzzz" is the name of the value or field.
+**
+** The UA4 prefix denotes 16540 compatible functions, available in both
+** chips. The UA5 prefix denotes 16550-only functions (primarily the FIFOs).
+**
+** For many items there are two names: one short one that matches the name
+** in the chip manual, and another that is more readable.
+*/
+
+#ifndef UART_H
+#define UART_H
+
+/*********************************************************************
+***************************** I/O PORTS ******************************
+*********************************************************************/
+
+/*
+** Base port number assigned to the device
+*/
+#define UA4_COM1_PORT 0x3f8
+#define UA4_COM2_PORT 0x2f8
+#define UA4_COM3_PORT 0x3e8
+#define UA4_COM4_PORT 0x2e8
+
+// short name for the one we'll use
+#define UA4_PORT UA4_COM1_PORT
+#define UA5_PORT UA4_COM1_PORT
+
+/*
+** Registers
+**
+** The 164x0 chips have the following registers. The (RO) and (WO)
+** suffixes indicate read-only and write-only access.
+**
+** Index Register(s)
+** ===== =========================================
+** 0 Receiver Data (RO), Transmitter Data (WO)
+** 1 Interrupt Enable
+** 2 Interrupt ID (RO), FIFO Control (WO)
+** 3 Line Control, Divisor Latch
+** 4 Modem Control
+** 5 Line Status
+** 6 Modem Status
+** 7 Scratch
+**
+** Registers indices are relative to the base I/O port for the
+** specific UART port being used (e.g., for COM1, the port addresses
+** are 0x3f8 through 0x3ff). When two registers share a port and have
+** different access methods (RO vs. WO), a read from the port accesses
+** the RO register and a write to the port access the WO register.
+**
+** The Line Control and Divisor Latch registers are accessed by writing
+** a byte to the port; the high-order bit determines which register is
+** accessed (0 selects Line Control, 1 selects Divisor Latch), with the
+** remaining bits selecting fields within the indicated register.
+*/
+
+/*
+** Receiver Data Register (read-only)
+*/
+#define UA4_RXD (UA4_PORT+0)
+# define UA4_RX_DATA UA4_RXD
+
+/*
+** Transmitter Data Register (write-only)
+*/
+#define UA4_TXD (UA4_PORT+0)
+# define UA4_TX_DATA UA4_TXD
+
+/*
+** Interrupt Enable Register
+*/
+#define UA4_IER (UA4_PORT+1)
+# define UA4_INT_ENABLE_REG UA4_IER
+
+// fields
+#define UA4_IER_RX_IE 0x01 // Rcvr High-Data-Level Int Enable
+#define UA4_IER_TX_IE 0x02 // Xmitter Low-data-level Int Enable
+#define UA4_IER_LS_IE 0x04 // Line Status Int Enable
+#define UA4_IER_MS_IE 0x08 // Modem Status Int Enable
+
+// aliases
+#define UA4_IER_RX_INT_ENABLE UA4_IER_RX_IE
+#define UA4_IER_TX_INT_ENABLE UA4_IER_TX_IE
+#define UA4_IER_LINE_STATUS_INT_ENABLE UA4_IER_LS_IE
+#define UA4_IER_MODEM_STATUS_INT_ENABLE UA4_IER_MS_IE
+
+/*
+** Interrupt Identification Register (read-only)
+**
+** a.k.a. Event Identification Register
+*/
+#define UA4_IIR (UA4_PORT+2)
+# define UA4_EVENT_ID UA4_IIR
+
+// fields
+#define UA4_IIR_IPF 0x01 // Interrupt Pending flag
+
+#define UA4_IIR_IPR_MASK 0x06 // Interrupt Priority mask
+# define UA4_IIR_IPR0_MASK 0x02 // IPR bit 0 mask
+# define UA4_IIR_IPR1_MASK 0x04 // IPR bit 1 mask
+
+#define UA5_IIR_RXFT 0x08 // RX_FIFO Timeout
+#define UA5_IIR_FEN0 0x40 // FIFOs Enabled
+#define UA5_IIR_FEN1 0x80 // FIFOs Enabled
+
+// aliases
+#define UA4_IIR_INT_PENDING UA4_IIR_IPF
+#define UA4_IIR_INT_PRIORITY UA4_IIR_IPR
+#define UA5_IIR_RX_FIFO_TIMEOUT UA5_IIR_RXFT
+#define UA5_IIR_FIFO_ENABLED_0 UA5_IIR_FEN0
+#define UA5_IIR_FIFO_ENABLED_1 UA5_IIR_FEN1
+
+// IIR interrupt priorities (four-bit values)
+#define UA4_IIR_INT_PRI_MASK 0x0f // Mask for extracting int priority
+# define UA4_IIR_NO_INT 0x01 // no interrupt
+# define UA4_IIR_LINE_STATUS 0x06 // line status interrupt
+# define UA4_IIR_RX 0x04 // Receiver High Data Level
+# define UA5_IIR_RX_FIFO 0x0c // Receiver FIFO timeout (16550)
+# define UA4_IIR_TX 0x02 // Transmitter Low Data level
+# define UA4_IIR_MODEM_STATUS 0x00 // Modem Status
+
+// aliases
+#define UA4_IIR_NO_INT_PENDING UA4_IIR_NO_INT
+#define UA4_IIR_LINE_STATUS_INT_PENDING UA4_IIR_LINE_STATUS
+#define UA4_IIR_RX_INT_PENDING UA4_IIR_RX
+#define UA5_IIR_RX_FIFO_TIMEOUT_INT_PENDING UA5_IIR_RX_FIFO
+#define UA4_IIR_TX_INT_PENDING UA4_IIR_TX
+#define UA4_IIR_MODEM_STATUS_INT_PENDING UA4_IIR_MODEM_STATUS
+
+/*
+** FIFO Control Register (16550 only, write-only)
+*/
+#define UA5_FCR (UA5_PORT+2)
+# define UA5_FIFO_CTL UA5_FCR
+
+#define UA5_FCR_FIFO_RESET 0x00 // Reset the FIFO
+#define UA5_FCR_FIFO_EN 0x01 // FIFO Enable
+#define UA5_FCR_RXSR 0x02 // Receiver Soft Reset
+#define UA5_FCR_TXSR 0x04 // Transmitter Soft Reset
+
+#define UA5_FCR_TXFT_MASK 0x30 // TX_FIFO threshold level mask
+# define UA5_FCR_TXFT0_MASK 0x10 // TXFT bit 0 mask
+# define UA5_FCR_TXFT1_MASK 0x20 // TXFT bit 1 mask
+# define UA5_FCR_TX_FIFO_1 0x00 // 1 char
+# define UA5_FCR_TX_FIFO_3 0x10 // 3 char
+# define UA5_FCR_TX_FIFO_9 0x20 // 9 char
+# define UA5_FCR_TX_FIFO_13 0x30 // 13 char
+
+#define UA5_FCR_RXFT_MASK 0xc0 // RX_FIFO threshold level mask
+# define UA5_FCR_RXFT0_MASK 0x40 // RXFT bit 0 mask
+# define UA5_FCR_RXFT1_MASK 0x80 // RXFT bit 1 mask
+# define UA5_FCR_RX_FIFO_1 0x00 // 1 char
+# define UA5_FCR_RX_FIFO_4 0x40 // 4 char
+# define UA5_FCR_RX_FIFO_8 0x80 // 8 char
+# define UA5_FCR_RX_FIFO_14 0xc0 // 14 char
+
+// aliases
+#define UA5_FCR_FIFO_ENABLED UA5_FCR_FIFO_EN
+#define UA5_FCR_RX_SOFT_RESET UA5_FCR_RXSR
+#define UA5_FCR_TX_SOFT_RESET UA5_FCR_TXSR
+#define UA5_FCR_TX_FIFO_1_CHAR UA5_FCR_TX_FIFO_1
+#define UA5_FCR_TX_FIFO_3_CHAR UA5_FCR_TX_FIFO_3
+#define UA5_FCR_TX_FIFO_9_CHAR UA5_FCR_TX_FIFO_9
+#define UA5_FCR_TX_FIFO_13_CHAR UA5_FCR_TX_FIFO_13
+#define UA5_FCR_RX_FIFO_1_CHAR UA5_FCR_RX_FIFO_1
+#define UA5_FCR_RX_FIFO_4_CHAR UA5_FCR_RX_FIFO_4
+#define UA5_FCR_RX_FIFO_8_CHAR UA5_FCR_RX_FIFO_8
+#define UA5_FCR_RX_FIFO_14_CHAR UA5_FCR_RX_FIFO_14
+
+/*
+** Line Control Register (available in all banks)
+**
+** Selected when bit 7 of the value written to the port is a 0.
+*/
+#define UA4_LCR (UA4_PORT+3)
+# define UA4_LINE_CTL UA4_LCR
+
+#define UA4_LCR_WLS_MASK 0x03 // Word Length Select mask
+# define UA4_LCR_WLS0_MASK 0x01 // WLS bit 0 mask
+# define UA4_LCR_WLS1_MASK 0x02 // WLS bit 1 mask
+# define UA4_LCR_WLS_5 0x00 // 5 bits per char
+# define UA4_LCR_WLS_6 0x01 // 6 bits per char
+# define UA4_LCR_WLS_7 0x02 // 7 bits per char
+# define UA4_LCR_WLS_8 0x03 // 8 bits per char
+
+#define UA4_LCR_STB 0x04 // Stop Bits
+# define UA4_LCR_1_STOP_BIT 0x00
+# define UA4_LCR_2_STOP_BIT 0x04
+
+#define UA4_LCR_PEN 0x08 // Parity Enable
+#define UA4_LCR_EPS 0x10 // Even Parity Select
+#define UA4_LCR_STKP 0x20 // Sticky Parity
+# define UA4_LCR_NO_PARITY 0x00
+# define UA4_LCR_ODD_PARITY UA4_LCR_PEN
+# define UA4_LCR_EVEN_PARITY (UA4_LCR_PEN|UA4_LCR_EPS)
+# define UA4_LCR_PARITY_LOGIC_1 (UA4_LCR_PEN|UA4_LCR_STKP)
+# define UA4_LCR_PARITY_LOGIC_0 (UA4_LCR_PEN|UA4_LCR_EPS|UA4_LCR_STKP)
+
+#define UA4_LCR_SBRK 0x40 // Set Break
+#define UA4_LCR_DLAB 0x80 // Divisor Latch select bit
+
+// aliases
+# define UA4_LCR_STOP_BITS UA4_LCR_STB
+# define UA4_LCR_PARITY_ENABLE UA4_LCR_PEN
+# define UA4_LCR_SET_BREAK UA4_LCR_SBRK
+# define UA4_LCR_BANK_SELECT_ENABLE UA4_LCR_BKSE
+
+/*
+** Divisor Latch Registers
+** Divisor Latch Least Significant (DLL)
+** Divisor Latch Most Significant (DLM)
+**
+** These contain the lower and upper halves of the 16-bit divisor for
+** baud rate generation.
+**
+** Accessing them requires sending a command to LCR with the most
+** significant bit (0x80, the DLAB field) set. This "unlocks" the
+** Divisor Latch registers, which are accessed at UA4_PORT+0 and
+** UA4_PORT+1 (i.e., in place of the RXD/TXD and IE registers). To
+** "re-lock" the Divisor Latch registers, write a command byte to
+** LCR with 0 in the DLAB bit.
+*/
+#define UA4_DLL (UA4_PORT+0) // Divisor Latch (least sig.)
+#define UA4_DLM (UA4_PORT+1) // Divisor Latch (most sig.)
+
+// aliases
+#define UA4_DIVISOR_LATCH_LS UA4_DLL
+#define UA4_DIVISOR_LATCH_MS UA4_DLM
+
+// Baud rate divisor high and low bytes
+#define BAUD_HIGH_BYTE(x) (((x) >> 8) & 0xff)
+#define BAUD_LOW_BYTE(x) ((x) & 0xff)
+
+// Baud rate divisors
+#define DL_BAUD_50 2304
+#define DL_BAUD_75 1536
+#define DL_BAUD_110 1047
+#define DL_BAUD_150 768
+#define DL_BAUD_300 384
+#define DL_BAUD_600 192
+#define DL_BAUD_1200 96
+#define DL_BAUD_1800 64
+#define DL_BAUD_2000 58
+#define DL_BAUD_2400 48
+#define DL_BAUD_3600 32
+#define DL_BAUD_4800 24
+#define DL_BAUD_7200 16
+#define DL_BAUD_9600 12
+#define DL_BAUD_14400 8
+#define DL_BAUD_19200 6
+#define DL_BAUD_28800 4
+#define DL_BAUD_38400 3
+#define DL_BAUD_57600 2
+#define DL_BAUD_115200 1
+
+/*
+** Modem Control Register
+*/
+#define UA4_MCR (UA4_PORT+4)
+# define UA4_MODEM_CTL UA4_MCR
+
+#define UA4_MCR_DTR 0x01 // Data Terminal Ready
+#define UA4_MCR_RTS 0x02 // Ready to Send
+#define UA4_MCR_RILP 0x04 // Loopback Interrupt Request
+#define UA4_MCR_ISEN 0x08 // Interrupt Signal Enable
+#define UA4_MCR_DCDLP 0x08 // DCD Loopback
+#define UA4_MCR_LOOP 0x10 // Loopback Enable
+
+// aliases
+#define UA4_MCR_DATA_TERMINAL_READY UA4_MCR_DTR
+#define UA4_MCR_READY_TO_SEND UA4_MCR_RTS
+#define UA4_MCR_LOOPBACK_INT_REQ UA4_MCR_RILP
+#define UA4_MCR_INT_SIGNAL_ENABLE UA4_MCR_ISEN
+#define UA4_MCR_LOOPBACK_DCD UA4_MCR_DCDLP
+#define UA4_MCR_LOOPBACK_ENABLE UA4_MCR_LOOP
+
+/*
+** Line Status Register
+*/
+#define UA4_LSR (UA4_PORT+5)
+# define UA4_LINE_STATUS UA4_LSR
+
+#define UA4_LSR_RXDA 0x01 // Receiver Data Available
+#define UA4_LSR_OE 0x02 // Overrun Error
+#define UA4_LSR_PE 0x04 // Parity Error
+#define UA4_LSR_FE 0x08 // Framing Error
+#define UA4_LSR_BRK 0x10 // Break Event Detected
+#define UA4_LSR_TXRDY 0x20 // Transmitter Ready
+#define UA4_LSR_TXEMP 0x40 // Transmitter Empty
+#define UA4_LSR_ER_INF 0x80 // Error in RX_FIFO
+
+// aliases
+#define UA4_LSR_RX_DATA_AVAILABLE UA4_LSR_RXDA
+#define UA4_LSR_OVERRUN_ERROR UA4_LSR_OE
+#define UA4_LSR_PARITY_ERROR UA4_LSR_PE
+#define UA4_LSR_FRAMING_ERROR UA4_LSR_FE
+#define UA4_LSR_BREAK_DETECTED UA4_LSR_BRK
+#define UA4_LSR_TX_READY UA4_LSR_TXRDY
+#define UA4_LSR_TX_EMPTY UA4_LSR_TXEMP
+#define UA4_LSR_RX_FIFO_ERROR UA4_LSR_ER_INF
+
+/*
+** Modem Status Register
+*/
+#define UA4_MSR (UA4_PORT+6)
+# define UA4_MODEM_STATUS UA4_MSR
+
+#define UA4_MSR_DCTS 0x01 // Delta Clear to Send
+#define UA4_MSR_DDSR 0x02 // Delta Data Set Ready
+#define UA4_MSR_TERI 0x04 // Trailing Edge Ring Indicate
+#define UA4_MSR_DDCD 0x08 // Delta Data Carrier Detect
+#define UA4_MSR_CTS 0x10 // Clear to Send
+#define UA4_MSR_DSR 0x20 // Data Set Ready
+#define UA4_MSR_RI 0x40 // Ring Indicate
+#define UA4_MSR_DCD 0x80 // Data Carrier Detect
+
+// aliases
+#define UA4_MSR_DELTA_CLEAR_TO_SEND UA4_MSR_DCTS
+#define UA4_MSR_DELTA_DATA_SET_READY UA4_MSR_DDSR
+#define UA4_MSR_TRAILING_EDGE_RING UA4_MSR_TERI
+#define UA4_MSR_DELTA_DATA_CARRIER_DETECT UA4_MSR_DDCD
+#define UA4_MSR_CLEAR_TO_SEND UA4_MSR_CTS
+#define UA4_MSR_DATA_SET_READY UA4_MSR_DSR
+#define UA4_MSR_RING_INDICATE UA4_MSR_RI
+#define UA4_MSR_DATA_CARRIER_DETECT UA4_MSR_DCD
+
+/*
+** Scratch Register
+**
+** Not used by the UART; usable as a "scratchpad" register for
+** temporary storage.
+*/
+#define UA4_SCR (UA4_PORT+7)
+# define UA4_SCRATCH UA4_UA5_SCR
+
+#endif /* uart.h */