diff options
author | Ben Burwell <ben@benburwell.com> | 2015-04-01 20:47:40 -0400 |
---|---|---|
committer | Ben Burwell <ben@benburwell.com> | 2015-04-01 20:47:40 -0400 |
commit | 4a04db9470cc0492a4bfb9752de14d8e12209177 (patch) | |
tree | 52ea5efdefb181ed9b76d3e749766f2924b69044 /docs/tech | |
parent | d8463e5ebbf8805c30ee6402e6667eb5f78446cc (diff) |
add docs
Diffstat (limited to 'docs/tech')
-rw-r--r-- | docs/tech/TechMan.pdf | bin | 0 -> 255028 bytes | |||
-rw-r--r-- | docs/tech/TechMan.tex | 57 | ||||
-rw-r--r-- | docs/tech/data_structures.tex | 95 | ||||
-rw-r--r-- | docs/tech/overview_of_program.tex | 21 | ||||
-rw-r--r-- | docs/tech/program_structure.tex | 118 | ||||
-rw-r--r-- | docs/tech/source_code.tex | 41 |
6 files changed, 332 insertions, 0 deletions
diff --git a/docs/tech/TechMan.pdf b/docs/tech/TechMan.pdf Binary files differnew file mode 100644 index 0000000..7192e92 --- /dev/null +++ b/docs/tech/TechMan.pdf diff --git a/docs/tech/TechMan.tex b/docs/tech/TechMan.tex new file mode 100644 index 0000000..d9ea3c4 --- /dev/null +++ b/docs/tech/TechMan.tex @@ -0,0 +1,57 @@ +\documentclass[11pt]{book} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage{makeidx} +\usepackage{graphicx} +\usepackage{tabularx} +\usepackage{listings} +\usepackage{color} +\usepackage{makeidx} + +\definecolor{dkgreen}{rgb}{0, 0.6, 0} +\definecolor{gray}{rgb}{0.5, 0.5, 0.5} +\definecolor{mauve}{rgb}{0.58, 0, 0.82} +\definecolor{dkred}{rgb}{0.7, 0, 0} + +\lstset{frame=tb, + language=C, + aboveskip=3mm, + belowskip=3mm, + showstringspaces=false, + columns=flexible, + basicstyle={\small\ttfamily}, + numbers=none, + numberstyle=\tiny\color{gray}, + keywordstyle=\color{blue}, + commentstyle=\color{dkgreen}, + stringstyle=\color{mauve}, + identifierstyle=\color{dkred}, + breaklines=true, + breakatwhitespace=true + tabsize=3 +} + +\author{B. Burwell and A. Morash} +\title{MPX--OS Technical Manual} +\date{Fall 2013} + +\makeindex + +\begin{document} + +\maketitle + +\frontmatter +\tableofcontents + +\mainmatter +\include{overview_of_program} +\include{program_structure} +\include{data_structures} +\include{source_code} + +\printindex + +\backmatter + +\end{document}
\ No newline at end of file diff --git a/docs/tech/data_structures.tex b/docs/tech/data_structures.tex new file mode 100644 index 0000000..0805caf --- /dev/null +++ b/docs/tech/data_structures.tex @@ -0,0 +1,95 @@ +\chapter{Data Structures} +\label{data_structures} + +\section{Process Control Block} +\label{process_control_block} + +The operating system stores information about processes in a Process Control Block\index{Process Control Block} (PCB)\index{PCB}. Defined in {\tt mpx.h}, the PCB stores the following information: +\begin{enumerate} + \item A pointer to the next PCB in the chain. + \item A pointer to the previous PCB in the queue. + \item A pointer to the next PCB in the queue. + \item A 9-character array to store the process name.\footnote{Note that thus, the maximum length of a process name is 8 characters, since character 9 will be {\tt 0x0}.} + \item A type (application or system). + \item A state (ready, running, or blocked). + \item A ``suspended'' flag. + \item A stack pointer for the process's stack. + \item An array of size {\tt STACK\_SIZE} to store the stack. + \item The address at which the process is loaded in memory. + \item The amount of memory allocated for the process. + \item A pointer to a parameter structure, storing the operation number and operation type for the process's current IO operation (if any). +\end{enumerate} + +The actual code for the structure is listed here: + +\begin{lstlisting} +struct pcbstruct { + struct pcbstruct * chain; + struct pcbstruct * next; + struct pcbstruct * prev; + char name[9]; + short type; + short priority; + short state; + short suspend; + unsigned stack_ptr; + unsigned stack[STACK_SIZE]; + unsigned loadaddr; + parm *parm_add; + int mem_size; +}; +\end{lstlisting} + +Each process control block is linked to the next one (except for the last one, whose next PCB is {\tt NULL}) by a pointer for iteration purposes. Process control blocks can reside in at most one of several system-wide queues at any given time. + +\subsection{Ready Queue} + +The ready queue is maintained as a priority-ordered list of processes that are ready to be run. This way, the dispatcher knows which process to start next. Queue operations stored in {\tt pcb.c} use the {\tt next} and {\tt prev} fields of the PCB to create a doubly-linked list and is prioritized using the PCB's {\tt priority} field. By definition, the priority of an application process must be greater than the minimum priority and smaller than the maxiumum priority of a system process. In this way, we can assign the idle process to have the lowest possible priority and the command handler to have the highest possible priority. + +\subsection{I/O Queue} + +The I/O queue stores queue of processes involved in I/O operations. This queue is a normal FIFO queue, contrasted with the Ready Queue. + +\section{Device Control Block} +\label{device_control_block} + +In order to manage I/O devices, MPX-OS uses Device Control Blocks,\index{Device Control Block} or DCBs. The {\tt struct} for the DCB is defined in {\tt mpx.h}, and is accessible to all component programs. + +The following information is stored: +\begin{enumerate} + \item The current operation. + \item A pointer to the event flag used to signal completion. + \item A pointer to the PCB currently using the device. + \item A pointer to the head of the queue of PCBs waiting to use the device. + \item A far pointer to an int to store the length of the device buffer. The far pointer allows it to point to a different section of memory, since the variable will be declared in a user program. + \item A far pointer to a char array to store the I/O buffer. + \item A count of the number of characters in the buffer. + \item A char array to act as the ring buffer, implemented as a circular queue (see below). + \item The index of the front element of the ring buffer. + \item The index of the rear element of the ring buffer. + \item The number of characters in the ring buffer. + \item The maximum size of the ring buffer. +\end{enumerate} + +The code for the DCB structure is listed below: +\begin{lstlisting} +struct dcb_struct { + unsigned current_op; + unsigned * event_flag; + pcb * current_pcb; + pcb * pcb_head; + far int * length; + far char * buffer; + int count; + far char * c_buffer; + char ring[INPUT_BUFFER_MAX]; + int ring_front; + int ring_rear; + int ring_count; + int ring_size; +}; +\end{lstlisting} + +\subsection{Ring Buffer} + +The ring buffer is used to implement type-ahead; that is, inputted characters are stored by the DCB when there is no current read operation and inserted into the buffer when a read request is made. There are several variables in the DCB structure used to implement the circular queue, whose logic is located in {\tt dcb.c} diff --git a/docs/tech/overview_of_program.tex b/docs/tech/overview_of_program.tex new file mode 100644 index 0000000..9b9a493 --- /dev/null +++ b/docs/tech/overview_of_program.tex @@ -0,0 +1,21 @@ +\chapter{Overview of the Program} +\label{overview_of_program} + +The MPX Operating System is designed as an exercise to examine various concepts within the theory of operating systems (rather than as a consumer-usable system). It is specially constructed to be started from within MS-DOS, at which time it will ``take over'' the operating system to perform many of its tasks. As MS-DOS is interrupt-driven, it uses interrupt handler routines to perform many low-level services, such as performing I/O, keeping time using the CPU clock, etc. Thus, we can replace the functionality of the interrupt handlers with code we have written by modifying the interrupt vector table. + +MPX is written in C. The following files are used: +\begin{enumerate} + \item {\tt mpx.h} --- A C header file containing all of the functions implemented, global variables, and {\tt \#DEFINE}d macros. + \item {\tt clock.c} --- Functions for enabling, configuring, and disabling the clock interrupt, as well as the function that is referenced in the interrupt vector table that is called when a clock interrupt occurs. + \item {\tt com.c} --- Functions for enabling, configuring, and disabling the {\tt COM} interrupts, as well as the function that is referenced in the interrupt vector table and is called when a clock interrupt occurs. + \item {\tt comhan.c} --- The code for the command handler, which is the main system process that prints a prompt and gets a user-inputted command. + \item {\tt dcb.c} --- Functions for dealing with Device Control Blocks (see page \pageref{device_control_block}). + \item {\tt direct.c} --- Functions for accessing MS-DOS directory listings. This code was provided by the project. + \item {\tt io.c} --- Functions for managing the queueing of processes with regard to I/O operations. + \item {\tt main.c} --- Contains {\tt main()}, which is called to perform setup tasks when MPX-OS first boots. + \item {\tt pcb.c} --- Functions for dealing with Process Control Blocks (see page \pageref{process_control_block}), including their queueing operations. + \item {\tt printer.c} --- Functions for enabling, configuring, and disabling the printer interrupts, as well as the function that is referenced in the interrupt vector table and is called when a clock interrupt occurs. + \item {\tt sys\_req.c} --- Contains the code for generating a software interrupt for when a system request is made from within MPX. This code was provided by the project. + \item {\tt sys\_sppt.c} --- System support, including initializing devices, closing devices, and handling system calls. +\end{enumerate} + diff --git a/docs/tech/program_structure.tex b/docs/tech/program_structure.tex new file mode 100644 index 0000000..dd887ce --- /dev/null +++ b/docs/tech/program_structure.tex @@ -0,0 +1,118 @@ +\chapter{Program Structure} +\label{program_structure} + +\section{Processes} + +\subsection{Types} + +Processes in MPX-OS can be one of two types: application or system processes. Application processes are any process that is loaded by a user. System processes are defined by MPX-OS for internal use; a user cannot load or run a system process. Precisely, MPX-OS defines two system processes, the first of which being the command handler. This process accepts and parses user commands to the operating system. The second system process is the idle process. This process does nothing, it only ensures that when the command handler is engaged in an I/O wait and is therefore blocked, there is something that can be running. + +\subsection{Prioritization} + +Each process has a priority. This allows more important processes, such as the command handler, to get more CPU time than less important ones, such as the idle process. A user can specify the priority of a process when it is loaded. Application processes can have priority $p_a$ where $-126 \le p_a \le 126$, and system processes can have priority $p_s$ where $-128 \le p_s \le 127$. + +\subsection{States} + +There are a number of states each process can be in, including {\tt READY}, {\tt RUNNING}, {\tt BLOCKED}, and {\tt ZOMBIE}. If a process is ready, it can be started immediately. It will then transition to the running state until it executes a system call. If it requests I/O, the process is blocked until the operation completes. If the user requests termination of the process while an I/O operation is in progress, the process will be placed in the zombie state. The I/O will complete, but immediately upon completion the process will be terminated. If the process requests termination, on the other hand, it is immediately terminated, the memory deallocated, and the PCB freed. + +\subsection{Suspension} + +A process can also be suspended, which is essentially pausing it. This is a user action; the user can put processes into and take them out of the suspended state arbitrarily. A suspended process will remain in the queue but will be skipped over when it is reached by the dispatcher. + +\section{System Call ({\tt sys\_call})} + +This function is called whenever one of MPX's processes is requesting a service, such as an I/O operation or termination. It is an interrupt function (its type is {\tt void interrupt}). The function is responsible for examining the parameters that have been placed on the stack, determining the corresponding operation, and executing it. + +\section{Dispatcher ({\tt dispatch})} + +The dispatcher is responsible for retrieving the next queued process and running it. It is also an {\tt interrupt} function. This means that the values of all of the registers will be pushed onto the stack before the function begins, and the registers are popped back off when it is finished. + +\section{Clock Operations} + +The clock interrupt functions in {\tt clock.c} are used to manage the system clock. When MPX-OS boots, it opens the clock for usage by MPX. A global {\tt long} is used to maintain the absolute number of clock ticks, which are configured to occur 18.2 times every second. + +The interrupt handler simply increments the counter variable. There is also a function for reading the clock value which takes pointers to {\tt int}s for storing the number of hours, minutes, and seconds that make up the number of ticks. + +It is of note that the clock will reset to zero when 24 hours are reached. Though partially for aesthetic reasons, it also ensures we do not overflow the capacity of a {\tt long} when running MPX-OS for an extended period of time. + +\section{I/O Drivers} + +\subsection{COM} +The functionality for communicating with the {\tt com} port is contained in {\tt com.c}, which has the following functions defined: + +\subsubsection{\tt com\_open} + +If the COM port is already open, {\tt -2} will be returned. This function initializes the COM port by setting the clock rate's Most Significant Byte (MSB) and Least Significant Byte (LSB) correctly in the Line Control Register. The interrupt vector table is modified such that our interrupt handler will be called when a clock interrupt occurs. + +The function also needs to ensure that interrupts are enabled, now that they will be generated and handled properly. To do this, it sets bit 4 of the Interrupt Mask Register (IMR) to be zero. Bit 3 of the Modem Control Register is set to enable the MCR to receive interrupts from the UART. The Interrupt Enable Register is set to specify which serial interrupts should be enabled. + +Finally, the Device Control Block (page \pageref{device_control_block}) is initialized with the event flag. + +\subsubsection{\tt com\_close} + +To close the COM port, we simply restore pointer to the the MS-DOS interrupt handler in the interrupt vector table. + +\subsubsection{\tt com\_int} + +This is the function that handles COM interrupts. It saves the Base Pointer to return to later, and checks the IIR to see what the interrupt was from and calls either {\tt com\_write\_int} or {\tt com\_read\_int}, whichever is appropriate. + +\subsubsection{\tt com\_read} + +This function initializes a read operation from the COM port with the buffer and length pointers. Since these will be from other processes, they must be declared as {\tt far} pointers. + +\subsubsection{\tt com\_write} + +This function initializes a write operation from the COM port, similarly to how {\tt com\_read} works. + +\subsubsection{\tt com\_read\_int} + +This function is called when the COM port sends a character to the operating system. It is appended to the program buffer. If it was the last character for the buffer (determined by the {\tt length} pointer), a {\tt 1} is returned indicating that the I/O operation has finished. Otherwise, a {\tt 0} is returned. + +\subsubsection{\tt com\_write\_int} + +Similarly, this function is called when the COM port indicates it is ready to receive a character to be written. It takes the next character from the buffer and puts it into the holding register to be printed to the terminal. + +\subsection{Printer} + +The functionality for interfacing with the printer is stored in {\tt printer.c}, which contains the following functions: + +\subsubsection{\tt prt\_open} + +The printer is initialized by setting up the function pointer in the interrupt vector table, enabling printer interrupts on the 8259, clearing the init bit and setting the select bit on the Printer Control Register, and initializing the Device Control Block. + +\subsubsection{\tt prt\_write} + +To write to the printer, we save the buffer and length into the DCB, enable printer interrupts on PCR, strobing the printer, writing null to the Printer Data Register, and unstrobing the printer. + +When the printer is finished printing the null character, it will generate an interrupt to signal that it is ready to print the next character from the buffer. + +\subsubsection{\tt prt\_close} + +To close the printer, we disable printer interrupts using the Interrupt Mask Register and restore the MS-DOS interrupt vector. + +\subsubsection{\tt prt\_int} + +This is the function called when the printer is ready to receive a character. The base pointer is saved. If there are more characters to write, the printer is strobed, the next character from the buffer copied into the Printer Data Register, and the printer is unstrobed. + +If there are no more characters to write, the printer interrupts are disabled and the event flag is set. We then call {\tt IO\_complete}, passing the identifier of the printer device and the saved base pointer. + +The End of Interrupt is sent. + + +\section{Scheduling} + +In MPX-OS, a Round-Robin dispatcher is implemented. There are several functions that handle scheduling tasks based on processes' pending I/O requests. All of this functionality is stored in {\tt io.c}, which implements the following: + +\subsubsection{\tt IO\_sup} + +The far pointers are made to the buffer and length. Then, the proper command based on the op number and op type is called. For example, if the op number refers to COM and the op type is write, {\tt com\_write} is called with the new far pointers. If the request was for a write operation to the console, we insert the process back into the ready queue, since this is not an interrupt-driven operation. + +\subsubsection{\tt IO\_complete} + +The DCB corresponding to the requested device is obtained. The stack pointer of {\tt cop} is set as the saved value. If the process was in the blocked state (as opposed to zombie if its termination had been requested by the user during the I/O operation), its state is set back to ready. In either case, it is placed back in the ready queue. + +If there are any pending I/O requests for the device that just completed, the processes requesting I/O are scheduled by calling {\tt IO\_sched}. Finally, the End of Interrupt signal is sent, and the dispatcher is called. + +\subsubsection{\tt IO\_sched} + +The operation number and type are determined and the appropriate DCB is accessed. If it has an I/O operation in progress, the process is added to the DCB queue and removed from the ready queue. Otherwise (if there is no operation in progress), the currently operating PCB for the DCB is set to the requesting process.
\ No newline at end of file diff --git a/docs/tech/source_code.tex b/docs/tech/source_code.tex new file mode 100644 index 0000000..8ee7f32 --- /dev/null +++ b/docs/tech/source_code.tex @@ -0,0 +1,41 @@ +\chapter{Source Code} +\label{source_code} + +\section{\tt mpx.h} +\lstinputlisting{../../mpx.h} + +\section{\tt clock.c} +\lstinputlisting{../../clock.c} + +\section{\tt com.c} +\lstinputlisting{../../com.c} + +\section{\tt comhan.c} +\lstinputlisting{../../comhan.c} + +\section{\tt dcb.c} +\lstinputlisting{../../dcb.c} + +\section{\tt direct.c} +\lstinputlisting{../../direct.c} + +\section{\tt io.c} +\lstinputlisting{../../io.c} + +\section{\tt load.c} +\lstinputlisting{../../load.c} + +\section{\tt main.c} +\lstinputlisting{../../main.c} + +\section{\tt pcb.c} +\lstinputlisting{../../pcb.c} + +\section{\tt printer.c} +\lstinputlisting{../../printer.c} + +\section{\tt sys\_req.c} +\lstinputlisting{../../sys_req.c} + +\section{\tt sys\_sppt.c} +\lstinputlisting{../../sys_sppt.c} |