Documentation.
authorMothy <troscoe@inf.ethz.ch>
Tue, 7 Aug 2012 10:41:10 +0000 (12:41 +0200)
committerMothy <troscoe@inf.ethz.ch>
Tue, 7 Aug 2012 10:41:10 +0000 (12:41 +0200)
Fixed bug in other serial drivers.

doc/016-serial-ports/Hakefile [new file with mode: 0644]
doc/016-serial-ports/Serial.tex [new file with mode: 0644]
hake/symbolic_targets.mk
kernel/arch/arm_gem5/gem5_serial.c [new file with mode: 0644]
kernel/arch/x86/serial.c
kernel/arch/x86/startup_x86.c

diff --git a/doc/016-serial-ports/Hakefile b/doc/016-serial-ports/Hakefile
new file mode 100644 (file)
index 0000000..1272545
--- /dev/null
@@ -0,0 +1,13 @@
+----------------------------------------------------------------------
+-- Copyright (c) 2012, ETH Zurich.
+-- All rights reserved.
+--
+-- This file is distributed under the terms in the attached LICENSE file.
+-- If you do not find this file, copies can be found by writing to:
+-- ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
+--
+-- Hakefile for /doc/016-serial-ports
+--
+----------------------------------------------------------------------
+
+[ buildTechNote "Serial.tex" "TN-016-Serial.pdf" False False [] ]
diff --git a/doc/016-serial-ports/Serial.tex b/doc/016-serial-ports/Serial.tex
new file mode 100644 (file)
index 0000000..5d3d776
--- /dev/null
@@ -0,0 +1,219 @@
+\documentclass[a4paper,twoside]{report} % for a report (default)
+
+\usepackage{amsmath}
+\usepackage{bftn} % You need this
+\usepackage{cite}
+\usepackage{color}
+\usepackage{listings}
+\usepackage{xspace}
+
+\title{Serial ports in Barrelfish}   % title of report
+\author{Timothy Roscoe}        % author
+\tnnumber{016}  % give the number of the tech report
+\tnkey{Serial ports} % Short title, will appear in footer
+
+% \date{Month Year} % Not needed - will be taken from version history
+
+\begin{document}
+\maketitle
+
+%
+% Include version history first
+%
+\begin{versionhistory}
+\vhEntry{0.0}{08.07.2012}{TR}{Initial version}
+\end{versionhistory}
+
+% \intro{Abstract}             % Insert abstract here
+% \intro{Acknowledgements}     % Uncomment (if needed) for acknowledgements
+% \tableofcontents             % Uncomment (if needed) for final draft
+% \listoffigures               % Uncomment (if needed) for final draft
+% \listoftables                        % Uncomment (if needed) for final draft
+
+\lstset{
+  language=C,
+  basicstyle=\ttfamily \small,
+  flexiblecolumns=false,
+  basewidth={0.5em,0.45em},
+  boxpos=t,
+}
+
+\newcommand{\note}[1]{[\textcolor{red}{\emph{#1}}]}
+\newcommand{\Intf}{\texttt{/kernel/include/serial.h}\xspace}
+
+\tableofcontents
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\chapter{Introduction}
+
+This technical note describes the use of serial ports (UARTS) in
+Barrelfish.  
+
+At present, it only describes the kernel-space interface
+to serial ports, used internally by CPU drivers for debugging and
+console output.  
+
+In the future, it will also describe the interface to user-space UART
+drivers and other console subsystems. 
+
+\chapter{CPU driver interface}\label{cha:cpudriver}
+
+CPU drivers use serial port access for printing debug information,
+status messages during startup, and connecting a debugger such as GDB
+to a processor. 
+
+Each CPU driver implements a serial port subsystem which provides a
+small number serial ports to the rest of the CPU driver.  
+
+The interface to this subsystem is specified in the file
+\Intf, and is described in this chapter.
+Check the header file for a (possibly) more-up-to-date description. 
+
+The interface is intentionally very basic.  It assumes each UART runs
+at a fixed, default speed with basic settings (typically 115000 baud,
+8-bit words, no parity, no flow control).   Serious applications
+should use a full user-space UART driver instead. 
+
+\section{Physical ports}
+
+Serial ports available inside a CPU driver are numbered starting at
+zero. 
+
+The number of available serial ports is given by:
+\begin{alltt}
+  extern const unsigned serial\_num\_physical\_ports;
+\end{alltt}
+
+\subsection{Initialization}
+
+Each port must be initialized before it can be used:
+\begin{alltt}
+  extern errval\_t serial\_init(unsigned port);
+\end{alltt}
+This call should fail with \texttt{SYS\_ERR\_SERIAL\_PORT\_INVALID} if
+the port cannot be initialized, or the port number is out of range.
+
+Initializing a serial port more than once, however, is permissible:
+subsequent attempts to initialize an initialized port are silently
+ignored.  The motivation for this is to handle the case where the
+console and debug logical ports share the same physical port. 
+
+In some cases it is necessary to do an ``early'' initializaton, for
+example while running in physical address space before the MMU is
+enabled.  In such cases the CPU driver should call, and the code
+implement, the following:
+\begin{alltt}
+  extern errval\_t serial\_early\_init(unsigned port);
+\end{alltt}
+
+This returns the same errors as \texttt{serial\_init()}, but it is a
+bug to call this function more than once with the same port number,
+and doing so will cause an assertion failure. 
+
+\subsection{Input/output}
+
+Each serial port provides polled, blocking, single-character
+programmed I/O:
+\begin{alltt}
+  extern void serial\_putchar(unsigned port, char c);
+  extern char serial\_getchar(unsigned port);
+\end{alltt}
+It is a bug to call these with a port number that is out of range
+(i.e. one that is greater than or equal to
+\texttt{serial\_num\_physical\_ports}), and doing so will cause an
+assertion failure.  It may also cause an assertion failure to call
+these functions on a serial port which has not yet been initialized
+with a call to \texttt{serial\_init()} or
+\texttt{serial\_early\_init()}. 
+
+Note that implementations of these functions should not attempt to use
+DMA or interrupts.  They should also not buffer any data in software
+(though they may use a hardware FIFO in the UART if appropriate). 
+
+\section{Logical ports}
+
+Barrelfish CPU drivers have access to two logical serial ports: 
+\begin{itemize}
+\item The \emph{console} port is used for general logging and debug
+  information.  It is principally called by \texttt{kputchar()}, which
+  implements line-buffering and is in turn called by the kernel
+  \texttt{printf()} function.
+\item The \emph{debug} port can be used to attach an external debugger
+  like \texttt{gdb}. 
+\end{itemize}
+
+Both logical ports are assigned to sensible default physical ports by
+the serial port implementation, but they can be changed by writing
+these variables:
+\begin{alltt}
+  extern unsigned serial\_console\_port;
+  extern unsigned serial\_debug\_port;
+\end{alltt}
+
+Note that it is not unusual for both logical ports to be assigned to
+the same physical port. 
+
+The file \Intf also includes inline functions to initialize whichever
+physical port is currently assigned to a logical port:
+\begin{alltt}
+  static inline errval\_t serial\_console\_init(void);
+  static inline errval\_t serial\_debug\_init(void);
+\end{alltt}
+
+There are also input functions, which simply call
+\texttt{serial\_getchar()} with the appropriate port number:
+\begin{alltt}
+  static inline char serial\_console\_getchar(void);
+  static inline char serial\_debug\_getchar(void);
+\end{alltt}
+
+Output functions are similar, but in addition replace any LF character
+with the sequence CR/LF:
+\begin{alltt}
+  static inline void serial\_console\_putchar(char c);
+  static inline void serial\_debug\_putchar(char c);
+\end{alltt}
+
+\section{Implementing a serial port subsystem}
+
+Typically, a rudimentary console driver is the first thing to be
+implemented when writing a CPU driver for a new architecture.   
+
+The serial port subsystem for a CPU driver must implement all the
+functionality in \Intf that deals with physical serial ports, in other
+words:
+\begin{verbatim}
+  const unsigned serial_num_physical_ports;
+  errval_t serial_init(unsigned port);
+  errval_t serial_early_init(unsigned port);
+  void serial_putchar(unsigned port, char c);
+  char serial_getchar(unsigned port);
+  unsigned serial_console_port;  
+  unsigned serial_debug_port;
+\end{verbatim}
+
+Functions for logical ports are provided by inline functions in the
+header file. 
+
+Initializing a serial port typically consists of configuring the UART
+hardware, and then mapping the registers appropriately into the
+kernel's virtual address space. 
+
+Examples of serial port implementations at time of writing include:
+\begin{itemize}
+\item \texttt{/kernel/arch/omap44xx/omap\_uart.c}
+\item \texttt{/kernel/arch/x86/serial.c}
+\end{itemize}
+
+\subsection{Multiprocessor considerations}
+
+This document does not address accessing a single UART from more than
+CPU driver.  If this happens at all, it is typically hidden by the
+implementation (for example, some x86 CPU drivers use a global
+spinlock, since performance is not an issue anyway).  Care should be
+taken not to initialize the UARTs multiple times in such
+circumstances. 
+
+
+
+\end{document}
index df93886..61def56 100644 (file)
@@ -491,6 +491,7 @@ DOCS= \
        ./docs/TN-013-CapabilityManagement.pdf \
        ./docs/TN-014-bulk-transfer.pdf \
        ./docs/TN-015-DiskDriverArchitecture.pdf \
+       ./docs/TN-016-Serial.pdf 
 
 docs doc: $(DOCS)
 .PHONY: docs doc
diff --git a/kernel/arch/arm_gem5/gem5_serial.c b/kernel/arch/arm_gem5/gem5_serial.c
new file mode 100644 (file)
index 0000000..3b78f72
--- /dev/null
@@ -0,0 +1,74 @@
+/**
+ * \file
+ * \brief ARM GEM5 kernel-level serial driver.  Implements the
+ * interface in /kernel/include/serial.h
+ */
+/*
+ * Copyright (c) 2007-2012 ETH Zurich.
+ * All rights reserved.
+ *
+ * This file is distributed under the terms in the attached LICENSE file.
+ * If you do not find this file, copies can be found by writing to:
+ * ETH Zurich D-INFK, CAB F.78, Universitaestr. 6, CH-8092 Zurich. 
+ * Attn: Systems Group.
+ */
+
+#include <kernel.h>
+#include <paging_kernel_arch.h>
+#include <serial.h>
+#include <dev/pl011_uart_dev.h>
+#include <pl011_uart.h>
+
+#define NUM_PORTS 2
+unsigned serial_console_port = 0;
+unsigned serial_debug_port = 1;
+const unsigned serial_num_physical_ports = NUM_PORTS;
+
+
+#define UART0_VBASE            0xE0009000
+#define UART0_SECTION_OFFSET   0x9000
+#define UART_DEVICE_BYTES      0x4c
+#define UART_MAPPING_DIFF      0x1000
+
+static pl011_uart_t ports[NUM_PORTS];
+
+/*
+ * Initialize a serial port 
+ */
+errval_t serial_init(unsigned port)
+{
+    if (port < NUM_PORTS) {
+        lvaddr_t base = paging_map_device(UART0_VBASE + port*UART_MAPPING_DIFF,
+                                          UART_DEVICE_BYTES);
+        pl011_uart_init(&ports[port], 
+                       base + UART0_SECTION_OFFSET + port*UART_MAPPING_DIFF);
+        return SYS_ERR_OK;
+    } else {
+        return SYS_ERR_SERIAL_PORT_INVALID;
+    }
+}
+
+errval_t serial_early_init(unsigned port)
+{
+    if (port < NUM_PORTS) {
+       assert(ports[port].base == 0);
+       pl011_uart_init(&ports[port], UART0_VBASE + port*UART_MAPPING_DIFF);
+       return SYS_ERR_OK;
+    } else {
+       return SYS_ERR_SERIAL_PORT_INVALID;
+    }
+}
+
+void serial_putchar(unsigned port, char c) 
+{
+    assert(port < NUM_PORTS);
+    assert(ports[port].base != 0);
+    pl011_putchar(&ports[port], c);
+};
+
+char serial_getchar(unsigned port)
+{
+    assert(port < NUM_PORTS);
+    assert(ports[port].base != 0);
+    return pl011_getchar(&ports[port]);
+};
index 4885d11..d9291ea 100644 (file)
@@ -29,7 +29,7 @@ int serial_portbase = 0x3f8; // COM1 default, can be changed via command-line ar
 #define NUM_PORTS 2
 unsigned serial_console_port = 0;
 unsigned serial_debug_port = 0;
-unsigned serial_num_physical_ports = NUM_PORTS;
+const unsigned serial_num_physical_ports = NUM_PORTS;
 
 // Note: hardwired for PC hardware
 static const uint32_t portbases[NUM_PORTS] = { 0x3f8, 0x2f8 };
@@ -109,9 +109,9 @@ void serial_putchar(unsigned port, char c)
     assert(port < NUM_PORTS);
     assert(ports[port].base != 0);
     // Wait until FIFO can hold more characters
-    while(!pc16550d_lsr_thre_rdf(&uarts[port]));
+    while(!pc16550d_lsr_thre_rdf(&ports[port]));
     // Write character
-    pc16550d_thr_wr(&uarts[port], c);
+    pc16550d_thr_wr(&ports[port], c);
 }
 
 /** \brief Reads a single character from the default serial port.
@@ -123,6 +123,6 @@ char serial_getchar(unsigned port)
     assert(ports[port].base != 0);
 
     // Read a character from FIFO
-    while( !pc16550d_lsr_dr_rdf(&uarts[port]));
-    return pc16550d_rbr_rd(&uarts[port]);
+    while( !pc16550d_lsr_dr_rdf(&ports[port]));
+    return pc16550d_rbr_rd(&ports[port]);
 }
index f4059ae..cb0b9f6 100644 (file)
@@ -233,6 +233,9 @@ void create_module_caps(struct spawn_state *st)
     }
 }
 
+// XXX from serial.c
+extern int serial_portbase;
+
 static struct cmdarg cmdargs[] = {
     {"loglevel", ArgType_Int, { .integer = &kernel_loglevel }},
     {"logmask", ArgType_Int, { .integer = &kernel_log_subsystem_mask }},